From b4aec7bc1a90a582d2a8b205c40a9b8aef7879ea Mon Sep 17 00:00:00 2001 From: pablo Date: Mon, 19 May 2025 10:44:50 +0300 Subject: [PATCH 1/5] feat(sharding)_: stage2 sending in new communities shard --- protocol/communities/community.go | 10 ++++- protocol/communities_key_distributor.go | 3 +- protocol/messenger.go | 5 ++- protocol/messenger_communities.go | 47 ++++++++++++++-------- protocol/messenger_community_shard.go | 2 +- protocol/messenger_community_storenodes.go | 3 +- protocol/messenger_peersyncing.go | 3 +- protocol/messenger_status_updates.go | 5 ++- 8 files changed, 51 insertions(+), 27 deletions(-) diff --git a/protocol/communities/community.go b/protocol/communities/community.go index f51b75d2fb..2f71bb29ee 100644 --- a/protocol/communities/community.go +++ b/protocol/communities/community.go @@ -1539,8 +1539,14 @@ func (o *Community) MemberUpdateChannelID() string { return o.IDString() + "-memberUpdate" } -func (o *Community) PubsubTopic() string { - return o.Shard().PubsubTopic() +func (o *Community) PubsubTopic(fallbackPubsubTopic ...string) string { + if o.Shard().PubsubTopic() != "" { + return o.Shard().PubsubTopic() + } + if len(fallbackPubsubTopic) > 0 { + return fallbackPubsubTopic[0] + } + return "" } func (o *Community) PubsubTopicPrivateKey() *ecdsa.PrivateKey { diff --git a/protocol/communities_key_distributor.go b/protocol/communities_key_distributor.go index c0c4d125d1..cfaea7af5a 100644 --- a/protocol/communities_key_distributor.go +++ b/protocol/communities_key_distributor.go @@ -8,6 +8,7 @@ import ( "github.com/status-im/status-go/protocol/communities" "github.com/status-im/status-go/protocol/encryption" "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/wakuv2" ) type CommunitiesKeyDistributorImpl struct { @@ -95,7 +96,7 @@ func (ckd *CommunitiesKeyDistributorImpl) sendKeyExchangeMessage(community *comm Recipients: pubkeys, MessageType: protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, HashRatchetGroupID: hashRatchetGroupID, - PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), } _, err := ckd.sender.SendCommunityMessage(context.Background(), &rawMessage) diff --git a/protocol/messenger.go b/protocol/messenger.go index 2fb353f6b5..03ef3cc81d 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -38,6 +38,7 @@ import ( "github.com/status-im/status-go/messaging" "github.com/status-im/status-go/metrics/wakumetrics" multiaccountscommon "github.com/status-im/status-go/multiaccounts/common" + "github.com/status-im/status-go/wakuv2" "github.com/status-im/status-go/multiaccounts" "github.com/status-im/status-go/multiaccounts/accounts" @@ -1093,7 +1094,7 @@ func (m *Messenger) publishContactCode() error { } for _, community := range joinedCommunities { rawMessage.LocalChatID = community.MemberUpdateChannelID() - rawMessage.PubsubTopic = community.PubsubTopic() + rawMessage.PubsubTopic = community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()) _, err = m.sender.SendPublic(ctx, rawMessage.LocalChatID, rawMessage) if err != nil { return err @@ -1997,7 +1998,7 @@ func (m *Messenger) dispatchMessage(ctx context.Context, rawMessage common.RawMe // Use a single content-topic for all community chats. // Reasoning: https://github.com/status-im/status-go/pull/5864 rawMessage.ContentTopic = community.UniversalChatID() - rawMessage.PubsubTopic = community.PubsubTopic() + rawMessage.PubsubTopic = community.PubsubTopic(wakuv2.GlobalCommunityContentPubsubTopic()) canPost, err := m.communitiesManager.CanPost(&m.identity.PublicKey, chat.CommunityID, chat.CommunityChatID(), rawMessage.MessageType) if err != nil { diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go index 697f009952..3458e7f01f 100644 --- a/protocol/messenger_communities.go +++ b/protocol/messenger_communities.go @@ -146,7 +146,7 @@ func (m *Messenger) publishOrg(org *communities.Community, shouldRekey bool) err SkipEncryptionLayer: true, CommunityID: org.ID(), MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, - PubsubTopic: org.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic + PubsubTopic: org.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), Priority: &common.HighPriority, } if org.Encrypted() { @@ -162,7 +162,7 @@ func (m *Messenger) publishOrg(org *communities.Community, shouldRekey bool) err messageID, err := m.sender.SendPublic(context.Background(), org.IDString(), rawMessage) if err == nil { m.logger.Debug("published community", - zap.String("pubsubTopic", org.PubsubTopic()), + zap.String("pubsubTopic", org.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic())), zap.String("communityID", org.IDString()), zap.String("messageID", hexutil.Encode(messageID)), zap.Uint64("clock", org.Clock()), @@ -185,7 +185,7 @@ func (m *Messenger) publishCommunityEvents(community *communities.Community, msg // we don't want to wrap in an encryption layer message SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_EVENTS_MESSAGE, - PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), // TODO: confirm if it should be sent in community pubsub topic Priority: &common.LowPriority, } @@ -213,6 +213,7 @@ func (m *Messenger) publishCommunityPrivilegedMemberSyncMessage(msg *communities Sender: community.PrivateKey(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE, + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), } for _, receivers := range msg.Receivers { @@ -348,7 +349,7 @@ func (m *Messenger) handleCommunitiesSubscription(c chan *communities.Subscripti Sender: community.PrivateKey(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_USER_KICKED, - PubsubTopic: wakuv2.DefaultNonProtectedPubsubTopic(), + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), } _, err = m.sender.SendPrivate(context.Background(), pk, rawMessage) @@ -683,7 +684,7 @@ func (m *Messenger) handleCommunitySharedAddressesRequest(state *ReceivedMessage CommunityID: community.ID(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_SHARED_ADDRESSES_RESPONSE, - PubsubTopic: wakuv2.DefaultNonProtectedPubsubTopic(), + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), ResendType: common.ResendTypeRawMessage, ResendMethod: common.ResendMethodSendPrivate, Recipients: []*ecdsa.PublicKey{signer}, @@ -770,7 +771,7 @@ func (m *Messenger) publishGroupGrantMessage(community *communities.Community, t Sender: community.PrivateKey(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_UPDATE_GRANT, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), Priority: &common.LowPriority, } @@ -962,12 +963,19 @@ func (m *Messenger) initCommunityChats(community *communities.Community) ([]*Cha } } + for _, chat := range publicChatsToInit { + fmt.Printf(">>> publicChatsToInit: %s %s\n", chat.ChatID, chat.PubsubTopic) + } filters, err := m.messaging.InitPublicChats(publicChatsToInit) if err != nil { logger.Debug("InitPublicChats error", zap.Error(err)) return nil, err } + for _, filter := range filters { + fmt.Printf(">>> filter: %s %s\n", filter.ChatID, filter.PubsubTopic) + } + if community.IsControlNode() { // Init the community filter so we can receive messages on the community @@ -1476,7 +1484,7 @@ func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommun ResendType: common.ResendTypeRawMessage, SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN, - PubsubTopic: wakuv2.DefaultNonProtectedPubsubTopic(), + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), Priority: &common.HighPriority, } @@ -1650,7 +1658,7 @@ func (m *Messenger) EditSharedAddressesForCommunity(request *requests.EditShared CommunityID: community.ID(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_EDIT_SHARED_ADDRESSES, - PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), // TODO: confirm if it should be sent in community pubsub topic ResendType: common.ResendTypeRawMessage, } @@ -1693,7 +1701,7 @@ func (m *Messenger) PublishTokenActionToPrivilegedMembers(communityID []byte, ch ResendType: common.ResendTypeRawMessage, ResendMethod: common.ResendMethodSendPrivate, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_TOKEN_ACTION, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), } skipMembers := make(map[string]struct{}) @@ -1854,7 +1862,7 @@ func (m *Messenger) CancelRequestToJoinCommunity(ctx context.Context, request *r CommunityID: community.ID(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_CANCEL_REQUEST_TO_JOIN, - PubsubTopic: wakuv2.DefaultNonProtectedPubsubTopic(), + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), ResendType: common.ResendTypeRawMessage, Priority: &common.HighPriority, } @@ -1987,7 +1995,7 @@ func (m *Messenger) acceptRequestToJoinCommunity(requestToJoin *communities.Requ Community: encryptedDescription, // Deprecated but kept for backward compatibility, to be removed in future Grant: grant, ProtectedTopicPrivateKey: crypto.FromECDSA(key), - Shard: community.Shard().Protobuffer(), + Shard: community.Shard().Protobuffer(), // TODO p test CommunityDescriptionProtocolMessage: descriptionMessage, } @@ -2012,7 +2020,7 @@ func (m *Messenger) acceptRequestToJoinCommunity(requestToJoin *communities.Requ CommunityID: community.ID(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN_RESPONSE, - PubsubTopic: wakuv2.DefaultNonProtectedPubsubTopic(), + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), ResendType: common.ResendTypeRawMessage, ResendMethod: common.ResendMethodSendPrivate, Recipients: []*ecdsa.PublicKey{pk}, @@ -2116,6 +2124,7 @@ func (m *Messenger) declineRequestToJoinCommunity(requestToJoin *communities.Req Sender: community.PrivateKey(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE, + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), } privilegedMembers := community.GetPrivilegedMembers() @@ -2220,7 +2229,7 @@ func (m *Messenger) LeaveCommunity(communityID types.HexBytes) (*MessengerRespon CommunityID: communityID, SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_LEAVE, - PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in the community pubsub topic + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), // TODO: confirm if it should be sent in the community pubsub topic ResendType: common.ResendTypeRawMessage, Priority: &common.HighPriority, } @@ -2886,7 +2895,7 @@ func (m *Messenger) ReevaluateCommunityMembersPermissions(request *requests.Reev CommunityID: request.CommunityID, SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), } _, err = m.SendMessageToControlNode(community, &rawMessage) if err != nil { @@ -3414,6 +3423,10 @@ func (m *Messenger) handleCommunityResponse(state *ReceivedMessageState, communi ChatID: chat.ID, PubsubTopic: community.PubsubTopic(), }) + publicFiltersToInit = append(publicFiltersToInit, &messaging.ChatToInitialize{ + ChatID: chat.ID, + PubsubTopic: wakuv2.GlobalCommunityContentPubsubTopic(), + }) // Update name, currently is the only field is mutable } else if oldChat.Name != chat.Name || oldChat.Description != chat.Description || @@ -3712,7 +3725,7 @@ func (m *Messenger) sendSharedAddressToControlNode(receiver *ecdsa.PublicKey, co CommunityID: community.ID(), SkipEncryptionLayer: false, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN, - PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), // TODO: confirm if it should be sent in community pubsub topic ResendType: common.ResendTypeDataSync, ResendMethod: common.ResendMethodSendPrivate, Recipients: []*ecdsa.PublicKey{receiver}, @@ -4237,7 +4250,7 @@ func (m *Messenger) dispatchMagnetlinkMessage(communityID string) error { Payload: encodedMessage, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_MESSAGE_ARCHIVE_MAGNETLINK, SkipGroupMessageWrap: true, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), Priority: &common.LowPriority, } @@ -5034,7 +5047,7 @@ func (m *Messenger) DeleteCommunityMemberMessages(request *requests.DeleteCommun Sender: community.PrivateKey(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), } _, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage) diff --git a/protocol/messenger_community_shard.go b/protocol/messenger_community_shard.go index ed5ef6d956..bd9114813a 100644 --- a/protocol/messenger_community_shard.go +++ b/protocol/messenger_community_shard.go @@ -58,7 +58,7 @@ func (m *Messenger) sendPublicCommunityShardInfo(community *communities.Communit // we don't want to wrap in an encryption layer message SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PUBLIC_SHARD_INFO, - PubsubTopic: wakuv2.DefaultNonProtectedPubsubTopic(), // it must be sent always to default shard pubsub topic + PubsubTopic: wakuv2.GlobalCommunityControlPubsubTopic(), // it must be sent always to default shard pubsub topic Priority: &common.HighPriority, } diff --git a/protocol/messenger_community_storenodes.go b/protocol/messenger_community_storenodes.go index 571ccc2d60..4e4cc54629 100644 --- a/protocol/messenger_community_storenodes.go +++ b/protocol/messenger_community_storenodes.go @@ -14,6 +14,7 @@ import ( "github.com/status-im/status-go/protocol/protobuf" "github.com/status-im/status-go/protocol/storenodes" v1protocol "github.com/status-im/status-go/protocol/v1" + "github.com/status-im/status-go/wakuv2" ) func (m *Messenger) sendCommunityPublicStorenodesInfo(community *communities.Community, snodes storenodes.Storenodes) error { @@ -50,7 +51,7 @@ func (m *Messenger) sendCommunityPublicStorenodesInfo(community *communities.Com Sender: community.PrivateKey(), SkipEncryptionLayer: true, MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PUBLIC_STORENODES_INFO, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), Priority: &common.HighPriority, } diff --git a/protocol/messenger_peersyncing.go b/protocol/messenger_peersyncing.go index 684adcff5e..5e1f8020e4 100644 --- a/protocol/messenger_peersyncing.go +++ b/protocol/messenger_peersyncing.go @@ -21,6 +21,7 @@ import ( "github.com/status-im/status-go/protocol/encryption/sharedsecret" "github.com/status-im/status-go/protocol/peersyncing" v1protocol "github.com/status-im/status-go/protocol/v1" + "github.com/status-im/status-go/wakuv2" ) var peerSyncingLoopInterval time.Duration = 60 * time.Second @@ -179,7 +180,7 @@ func (m *Messenger) sendDatasyncOffersForCommunities() error { Payload: payload, Ephemeral: true, SkipApplicationWrap: true, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), Priority: &common.LowPriority, } _, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage) diff --git a/protocol/messenger_status_updates.go b/protocol/messenger_status_updates.go index 9e6fea17fb..1db0977771 100644 --- a/protocol/messenger_status_updates.go +++ b/protocol/messenger_status_updates.go @@ -13,6 +13,7 @@ import ( gocommon "github.com/status-im/status-go/common" "github.com/status-im/status-go/messaging" datasyncpeer "github.com/status-im/status-go/protocol/datasync/peer" + "github.com/status-im/status-go/wakuv2" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/protocol/common" @@ -89,7 +90,7 @@ func (m *Messenger) sendUserStatus(ctx context.Context, status UserStatus) error } for _, community := range joinedCommunities { rawMessage.LocalChatID = community.StatusUpdatesChannelID() - rawMessage.PubsubTopic = community.PubsubTopic() + rawMessage.PubsubTopic = community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()) _, err = m.sender.SendPublic(ctx, rawMessage.LocalChatID, rawMessage) if err != nil { return err @@ -178,7 +179,7 @@ func (m *Messenger) sendCurrentUserStatusToCommunity(ctx context.Context, commun MessageType: protobuf.ApplicationMetadataMessage_STATUS_UPDATE, ResendType: common.ResendTypeNone, // does this need to be resent? Ephemeral: statusUpdate.StatusType == protobuf.StatusUpdate_AUTOMATIC, - PubsubTopic: community.PubsubTopic(), + PubsubTopic: community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()), Priority: &common.LowPriority, } From 5286e569e1702673b58b369d074186547e452547 Mon Sep 17 00:00:00 2001 From: pablo Date: Thu, 21 Aug 2025 10:16:27 +0300 Subject: [PATCH 2/5] chore: merge --- .github/workflows/pr.yml | 67 + Dockerfile | 63 + _assets/ci/Jenkinsfile.linux-nix | 1 + _assets/ci/Jenkinsfile.macos-nix | 1 + _assets/ci/Jenkinsfile.nix | 48 + _assets/ci/Jenkinsfile.tests-benchmark | 71 + _assets/scripts/push_benchmark.sh | 47 + _assets/scripts/run_benchmark.sh | 79 + accounts-management/README.md | 426 + accounts-management/accounts.go | 49 + accounts-management/common/address.go | 23 + accounts-management/common/address_test.go | 24 + accounts-management/common/const.go | 15 + accounts-management/common/mnemonic.go | 52 + accounts-management/common/mnemonic_test.go | 118 + accounts-management/common/publickey.go | 66 + accounts-management/common/publickey_test.go | 84 + accounts-management/common/utils.go | 12 + accounts-management/core/errors.go | 104 + .../core/keystore_operations.go | 316 + accounts-management/core/manager.go | 237 + accounts-management/core/manager_test.go | 517 + .../core/persistence_operations.go | 646 + accounts-management/errors/errors.go | 81 + accounts-management/errors/errors_test.go | 102 + .../errors/errors_test_data.go | 38 + accounts-management/generator/README.md | 34 + accounts-management/generator/errors.go | 81 + accounts-management/generator/generator.go | 116 + .../generator/generator_test.go | 159 + accounts-management/generator/path_decoder.go | 229 + .../generator/path_decoder_test.go | 106 + accounts-management/generator/types.go | 214 + accounts-management/generator/types_test.go | 68 + accounts-management/keystore/geth/adapter.go | 191 + accounts-management/keystore/geth/const.go | 7 + .../keystore/geth/decryption.go | 367 + .../keystore/geth/encryption.go | 133 + accounts-management/keystore/geth/helper.go | 79 + .../keystore/geth/migration.go | 69 + .../keystore/geth/reencryption.go | 127 + accounts-management/keystore/interface.go | 41 + accounts-management/keystore/types/account.go | 24 + .../keystore/types/account_test.go | 48 + accounts-management/persistence/interface.go | 43 + accounts-management/types/key.go | 36 + accounts-management/types/keypair.go | 107 + accounts-management/types/types.go | 24 + accounts-management/types/types_test.go | 29 + ...752869164_drop_telemetry_server_url.up.sql | 1 + ...3221199_add_add_backup_path_setting.up.sql | 1 + .../sql/1754574769_drop_mailservers.up.sql | 3 + .../sql/1754667909_drop_http_config.up.sql | 4 + .../sql/1754670349_drop_ipc_config.up.sql | 1 + .../sql/1754670350_drop_cluster_nodes.up.sql | 1 + ...1754670351_drop_wakuv2_custom_nodes.up.sql | 1 + .../1754670352_cleanup_wakuv2_config.up.sql | 15 + .../sql/1754923284_cleanup_node_config.up.sql | 10 + .../sql/1755017956_drop_app_metrics.up.sql | 5 + .../sql/1755264069_cleanup_node_config.up.sql | 1 + cmd/generate-db/README.md | 30 + cmd/generate-db/main.go | 96 + cmd/push-notification-server/main.go | 284 + cmd/status-backend/server/options.go | 19 + common/errors.go | 7 + common/errors_test.go | 22 + contracts/namewrapper/namewrapper.go | 2392 ++++ crypto/README.md | 300 + crypto/crypto.go | 325 + crypto/ethereum_crypto.go | 188 + crypto/geth/provider.go | 106 + crypto/interface.go | 90 + crypto/types/address.go | 215 + crypto/types/errors.go | 61 + crypto/types/hash.go | 119 + crypto/types/hex.go | 78 + crypto/types/utils.go | 123 + crypto/types/utils_test.go | 81 + internal/enr/enr.go | 13 + internal/multiaddr/multiaddr.go | 11 + internal/timesource/timesource.go | 7 + .../adapters/encryption_subscriptions.go | 19 + messaging/adapters/hash_ratchet.go | 27 + messaging/adapters/installation.go | 84 + messaging/adapters/peers.go | 17 + messaging/adapters/received_messages.go | 14 + messaging/adapters/shard.go | 16 + messaging/adapters/shared_secret.go | 27 + messaging/adapters/transport_stats.go | 13 + messaging/common/message_segmentation.go | 285 + messaging/common/message_segmentation_test.go | 203 + messaging/common/message_sender.go | 1388 ++ messaging/common/message_sender_test.go | 382 + messaging/common/persistence_stub_test.go | 264 + .../segmentationProtobufMissDecoding.bin | Bin 0 -> 19321 bytes messaging/core_config.go | 76 + messaging/core_test_utils.go | 184 + messaging/datasync/datasync.go | 64 + messaging/datasync/peer/utils.go | 19 + messaging/datasync/transport.go | 70 + messaging/datasync/utils.go | 30 + messaging/events/message_event.go | 35 + messaging/layers/encryption/README.md | 12 + .../encryption_multi_device_test.go | 348 + .../layers/encryption/encryption_test.go | 1186 ++ messaging/layers/encryption/encryptor.go | 748 + messaging/layers/encryption/helpers.go | 152 + .../sqlite/1536754952_initial_schema.down.sql | 4 + .../sqlite/1536754952_initial_schema.up.sql | 40 + .../1539249977_update_ratchet_info.down.sql | 11 + .../1539249977_update_ratchet_info.up.sql | 13 + .../sqlite/1540715431_add_version.down.sql | 3 + .../sqlite/1540715431_add_version.up.sql | 5 + .../1541164797_add_installations.down.sql | 1 + .../1541164797_add_installations.up.sql | 7 + .../sqlite/1558084410_add_secret.down.sql | 2 + .../sqlite/1558084410_add_secret.up.sql | 11 + .../sqlite/1558588866_add_version.down.sql | 1 + .../sqlite/1558588866_add_version.up.sql | 1 + .../1559627659_add_contact_code.down.sql | 1 + .../sqlite/1559627659_add_contact_code.up.sql | 6 + ...1368210_add_installation_metadata.down.sql | 1 + ...561368210_add_installation_metadata.up.sql | 8 + .../1632236298_add_communities.down.sql | 5 + .../sqlite/1632236298_add_communities.up.sql | 20 + .../1636536507_add_index_bundles.up.sql | 3 + .../1698137564_add_migration_index.up.sql | 11 + .../1709200114_add_migration_index.up.sql | 11 + .../encryption/migrations/sqlite/doc.go | 9 + .../encryption/multidevice/multidevice.go | 129 + .../encryption/multidevice/persistence.go | 282 + .../multidevice/persistence_test.go | 307 + messaging/layers/encryption/persistence.go | 1011 ++ .../persistence_keys_storage_test.go | 201 + .../layers/encryption/persistence_test.go | 391 + messaging/layers/encryption/protocol.go | 919 ++ .../layers/encryption/protocol_message.proto | 111 + messaging/layers/encryption/protocol_test.go | 176 + messaging/layers/encryption/publisher/doc.go | 6 + .../encryption/publisher/persistence.go | 38 + .../layers/encryption/publisher/publisher.go | 131 + .../encryption/publisher/publisher_test.go | 31 + .../encryption/sharedsecret/persistence.go | 120 + .../encryption/sharedsecret/service_test.go | 117 + .../encryption/sharedsecret/sharedsecret.go | 104 + messaging/layers/encryption/x3dh.go | 230 + messaging/layers/encryption/x3dh_test.go | 209 + messaging/types/chat_entity.go | 23 + messaging/types/encryption_subscriptions.go | 8 + messaging/types/handle_message_response.go | 17 + messaging/types/hash_ratchet.go | 13 + messaging/types/installation.go | 27 + messaging/types/message.go | 87 + messaging/types/peers.go | 34 + messaging/types/raw_message.go | 102 + messaging/types/received_messages.go | 7 + messaging/types/segment_message.go | 30 + messaging/types/shard.go | 103 + messaging/types/shared_secret.go | 8 + messaging/types/store_node.go | 80 + messaging/types/transport_stats.go | 6 + {wakuv2 => messaging/waku}/README.md | 0 {wakuv2 => messaging/waku}/api.go | 71 +- {wakuv2 => messaging/waku}/api_test.go | 7 +- {wakuv2 => messaging/waku}/bridge.go | 15 +- {wakuv2 => messaging/waku}/common/README.md | 0 {wakuv2 => messaging/waku}/common/const.go | 0 {wakuv2 => messaging/waku}/common/envelope.go | 3 +- .../waku}/common/envelope_test.go | 3 +- {wakuv2 => messaging/waku}/common/events.go | 0 {wakuv2 => messaging/waku}/common/filter.go | 2 +- .../waku}/common/filter_test.go | 0 {wakuv2 => messaging/waku}/common/helpers.go | 19 - .../waku}/common/helpers_test.go | 0 {wakuv2 => messaging/waku}/common/message.go | 0 {wakuv2 => messaging/waku}/common/metrics.go | 0 {wakuv2 => messaging/waku}/common/topic.go | 5 - .../waku}/common/topic_test.go | 0 {wakuv2 => messaging/waku}/config.go | 6 +- {wakuv2 => messaging/waku}/const.go | 0 {wakuv2 => messaging/waku}/gowaku.go | 109 +- {wakuv2 => messaging/waku}/gowaku_test.go | 0 .../waku}/history_processor_wrapper.go | 2 +- .../waku}/message_publishing.go | 2 +- {wakuv2 => messaging/waku}/nwaku.go | 981 +- {wakuv2 => messaging/waku}/nwaku_test.go | 0 .../waku}/nwaku_test_utils.go | 0 {wakuv2 => messaging/waku}/nwaku_utils.go | 3 +- .../waku}/persistence/dbkey.go | 0 .../waku}/persistence/dbstore.go | 0 .../waku}/persistence/signed_messages.go | 2 +- {wakuv2 => messaging/waku}/pinger.go | 0 {wakuv2 => messaging/waku}/publisher.go | 0 {wakuv2 => messaging/waku}/result.go | 0 {wakuv2 => messaging/waku}/shard.go | 11 - .../waku}/store_message_verifier.go | 0 .../waku}/storenode_requestor.go | 0 {wakuv2 => messaging/waku}/tracer.go | 0 {waku => messaging/waku}/types/envelopes.go | 13 +- {waku => messaging/waku}/types/filter.go | 0 {waku => messaging/waku}/types/mailserver.go | 68 +- {waku => messaging/waku}/types/rpc.go | 12 - {waku => messaging/waku}/types/stats.go | 0 {waku => messaging/waku}/types/subscribe.go | 0 {waku => messaging/waku}/types/topic.go | 2 +- {waku => messaging/waku}/types/waku.go | 5 - {waku => messaging/waku}/types/wrapped.go | 0 {wakuv2 => messaging/waku}/waku_test.go | 284 +- .../waku}/waku_unsupported.go | 0 messaging/wakumetrics/client.go | 165 + messaging/wakumetrics/client_test.go | 178 + messaging/wakumetrics/metrics.go | 187 + metrics/metrics_test.go | 119 + .../accounts/accounts_manager_adapter.go | 104 + .../accounts/accounts_manager_types_mapper.go | 163 + multiaccounts/settings/events.go | 6 + node/backup/controller.go | 144 + node/backup/controller_test.go | 94 + node/backup/core.go | 115 + params/storenode_test.go | 28 + pkg/pubsub/README.md | 224 + pkg/pubsub/publisher.go | 35 + pkg/pubsub/pubsub.go | 24 + pkg/pubsub/pubsub_test.go | 300 + pkg/pubsub/type_publisher.go | 112 + protocol/accounts_manager_interface.go | 29 + protocol/messaging_persistence.go | 376 + protocol/messaging_persistence_test.go | 208 + protocol/messenger_local_backup.go | 70 + protocol/messenger_local_backup_test.go | 159 + protocol/messenger_pubsub_events.go | 11 + ...754570630_drop_community_storenodes.up.sql | 1 + protocol/protobuf/accounts_local_backup.proto | 10 + .../protobuf/messenger_local_backup.proto | 16 + protocol/protobuf/wallet_local_backup.proto | 10 + protocol/requests/load_local_backup.go | 14 + rpc/events.go | 9 + rpc/network/events.go | 4 + rpc/signals_transmitter.go | 52 + services/ens/ensresolver/address.go | 25 + services/ens/ensresolver/address_test.go | 49 + services/personal/service_test.go | 83 + services/wallet/leaderboard/utils.go | 27 + .../wallet/thirdparty/utils/chunk_fetcher.go | 87 + .../thirdparty/utils/chunk_fetcher_test.go | 207 + signal/events_networks.go | 16 + signal/events_peerstats.go | 14 + tests-functional/.dockerignore | 6 + tests-functional/.gitignore | 8 + tests-functional/Makefile | 5 + tests-functional/clients/expvar.py | 124 + tests-functional/clients/gorush_stub.py | 160 + tests-functional/clients/metrics.py | 547 + .../clients/push_notification_server.py | 17 + .../clients/statusgo_container.py | 414 + .../resources/images/test-image-200x200.jpg | Bin 0 -> 4925 bytes .../resources/test_data/__init__.py | 1 + .../resources/test_data/mnemonic_12.py | 61 + .../resources/test_data/mnemonic_15.py | 39 + .../resources/test_data/mnemonic_24.py | 39 + .../test_data/profile_showcase_utils.py | 93 + .../test_data/test_old_user_data.bkp | Bin 0 -> 2622 bytes tests-functional/resources/utils.py | 20 + .../schemas/accounts_addKeypairViaSeedPhrase | 147 + tests-functional/schemas/wakuext_editMessage | 424 - .../schemas/wakuext_emojiReactionsByChatID | 66 - .../wakuext_emojiReactionsByChatIDMessageID | 66 - .../schemas/wakuext_firstUnseenMessageID | 20 - .../schemas/wakuext_getActivityCenterState | 32 - .../wakuext_getLatestContactRequestForContact | 172 - .../schemas/wakuext_getSavedAddresses | 63 - .../schemas/wakuext_getSavedAddressesPerMode | 63 - ...kuext_hasUnseenActivityCenterNotifications | 20 - ...akuext_markActivityCenterNotificationsRead | 371 - ...uext_markActivityCenterNotificationsUnread | 276 - ...ext_markAllActivityCenterNotificationsRead | 415 - ...uext_markAsSeenActivityCenterNotifications | 48 - .../schemas/wakuext_markMessageAsUnread | 59 - .../schemas/wakuext_messageByMessageID | 153 - tests-functional/schemas/wakuext_peers | 41 - .../schemas/wakuext_removeContact | 458 - .../schemas/wakuext_requestTransaction | 480 - .../schemas/wakuext_retractContactRequest | 458 - .../schemas/wakuext_sendChatMessage | 1091 -- .../schemas/wakuext_sendContactRequest | 774 -- .../schemas/wakuext_sendEmojiReaction | 319 - .../wakuext_sendEmojiReactionRetraction | 325 - .../schemas/wakuext_sendGroupChatMessage | 466 - .../schemas/wakuext_sendOneToOneMessage | 412 - .../schemas/wakuext_sendPinMessage | 533 - .../schemas/wakuext_sendTransaction | 480 - .../schemas/wakuext_setContactLocalNickname | 166 - .../schemas/wakuext_setUserStatus | 20 - .../schemas/wakuext_statusUpdates | 51 - .../wakuext_updateMessageOutgoingStatus | 20 - .../wallet_checkRecentHistoryForChainIDs | 20 - .../schemas/wallet_fetchAllCurrencyFormats | 3664 ----- .../schemas/wallet_fetchMarketValues | 457 - tests-functional/schemas/wallet_fetchPrices | 34 - .../schemas/wallet_fetchTokenDetails | 72 - .../schemas/wallet_filterActivityAsync | 53 - .../schemas/wallet_getCachedCurrencyFormats | 3624 ----- .../schemas/wallet_getCryptoOnRamps | 66 - .../schemas/wallet_getEthereumChains | 95 - .../schemas/wallet_getOwnedCollectiblesAsync | 53 - .../schemas/wallet_getPendingTransactions | 91 - ...wallet_getPendingTransactionsForIdentities | 91 - tests-functional/schemas/wallet_getTokenList | 90 - .../wallet_getWalletConnectActiveSessions | 20 - tests-functional/schemas/wallet_startWallet | 20 - ...wallet_stopSuggestedRoutesAsyncCalculation | 20 - tests-functional/steps/eth_rpc.py | 79 - tests-functional/steps/messenger.py | 131 +- tests-functional/steps/network_conditions.py | 10 +- tests-functional/steps/status_backend.py | 28 - tests-functional/steps/wallet.py | 58 - .../tests/benchmark/test_basic_benchmark.py | 85 + tests-functional/tests/conftest.py | 165 + tests-functional/tests/reliability/README.MD | 53 + .../reliability/test_community_messages.py | 22 +- .../tests/reliability/test_contact_request.py | 30 +- .../reliability/test_create_private_groups.py | 13 +- .../reliability/test_join_leave_community.py | 25 +- .../test_light_client_rate_limiting.py | 8 +- .../reliability/test_one_to_one_messages.py | 12 +- .../test_private_groups_messages.py | 28 +- tests-functional/tests/test_accounts.py | 37 +- .../test_activity_center_notifications.py | 52 +- tests-functional/tests/test_add_account.py | 181 + tests-functional/tests/test_app_general.py | 14 +- .../tests/test_backup_mnemonic_and_restore.py | 179 + tests-functional/tests/test_eth_api.py | 99 +- .../tests/test_init_status_app.py | 23 +- tests-functional/tests/test_local_backup.py | 466 + tests-functional/tests/test_local_pairing.py | 323 + tests-functional/tests/test_logging.py | 7 +- .../tests/test_move_wallet_account.py | 66 + .../tests/test_push_notification_server.py | 87 + .../tests/test_resolve_suggested_path.py | 20 + tests-functional/tests/test_router.py | 109 +- .../tests/test_token_preferences.py | 61 + .../tests/test_update_keypair_name.py | 43 + .../tests/test_verify_password.py | 18 + tests-functional/tests/test_wakuext_chats.py | 81 +- .../tests/test_wakuext_contact_requests.py | 66 +- .../tests/test_wakuext_group_chats.py | 198 + .../tests/test_wakuext_message_reactions.py | 20 +- .../tests/test_wakuext_messages_fetching.py | 64 +- .../test_wakuext_messages_interacting.py | 60 +- .../test_wakuext_messages_light_client.py | 21 - .../tests/test_wakuext_messages_sending.py | 55 +- .../test_wakuext_messages_transactions.py | 50 +- .../tests/test_wakuext_profile.py | 23 +- tests-functional/tests/test_wakuext_rpc.py | 12 +- .../tests/test_wakuext_savedAddress.py | 34 +- .../tests/test_wallet_activity_session.py | 53 +- tests-functional/tests/test_wallet_assets.py | 80 + tests-functional/tests/test_wallet_rpc.py | 13 +- tests-functional/tests/test_wallet_signals.py | 23 +- tests-functional/utils/config.py | 20 + tests-functional/utils/keys.py | 18 + tests-functional/utils/schema_builder.py | 22 - tests-functional/utils/wallet_utils.py | 23 +- .../waku_configs/pushfleetconfig.json | 3 + transactions/addrlock.go | 2 +- transactions/pendingtxtracker.go | 8 +- transactions/rpc_wrapper.go | 39 +- transactions/transactor.go | 29 +- transactions/transactor_test.go | 67 +- vendor/github.com/BurntSushi/toml/.gitignore | 2 - vendor/github.com/BurntSushi/toml/COPYING | 21 - vendor/github.com/BurntSushi/toml/README.md | 120 - vendor/github.com/BurntSushi/toml/decode.go | 602 - .../BurntSushi/toml/decode_go116.go | 19 - .../github.com/BurntSushi/toml/deprecated.go | 29 - vendor/github.com/BurntSushi/toml/doc.go | 11 - vendor/github.com/BurntSushi/toml/encode.go | 759 - vendor/github.com/BurntSushi/toml/error.go | 279 - .../github.com/BurntSushi/toml/internal/tz.go | 36 - vendor/github.com/BurntSushi/toml/lex.go | 1283 -- vendor/github.com/BurntSushi/toml/meta.go | 121 - vendor/github.com/BurntSushi/toml/parse.go | 811 -- .../github.com/BurntSushi/toml/type_fields.go | 242 - .../github.com/BurntSushi/toml/type_toml.go | 70 - .../brianvoe/gofakeit/v7/.gitignore | 0 .../brianvoe/gofakeit/v7/BENCHMARKS.md | 323 + .../brianvoe/gofakeit/v7/CODE_OF_CONDUCT.md | 46 + .../brianvoe/gofakeit/v7/CONTRIBUTING.md | 1 + .../brianvoe/gofakeit/v7/LICENSE.txt | 20 + .../github.com/brianvoe/gofakeit/v7/README.md | 876 ++ .../brianvoe/gofakeit/v7/address.go | 420 + .../github.com/brianvoe/gofakeit/v7/animal.go | 178 + vendor/github.com/brianvoe/gofakeit/v7/app.go | 96 + .../github.com/brianvoe/gofakeit/v7/auth.go | 163 + .../github.com/brianvoe/gofakeit/v7/beer.go | 207 + .../github.com/brianvoe/gofakeit/v7/book.go | 88 + vendor/github.com/brianvoe/gofakeit/v7/car.go | 146 + .../brianvoe/gofakeit/v7/celebrity.go | 62 + .../github.com/brianvoe/gofakeit/v7/color.go | 116 + .../brianvoe/gofakeit/v7/company.go | 229 + vendor/github.com/brianvoe/gofakeit/v7/csv.go | 183 + .../brianvoe/gofakeit/v7/data/README.md | 33 + .../brianvoe/gofakeit/v7/data/address.go | 15 + .../brianvoe/gofakeit/v7/data/animals.go | 12 + .../brianvoe/gofakeit/v7/data/beer.go | 10 + .../brianvoe/gofakeit/v7/data/book.go | 101 + .../brianvoe/gofakeit/v7/data/car.go | 10 + .../brianvoe/gofakeit/v7/data/celebrity.go | 7 + .../brianvoe/gofakeit/v7/data/colors.go | 110 + .../brianvoe/gofakeit/v7/data/company.go | 10 + .../brianvoe/gofakeit/v7/data/computer.go | 8 + .../brianvoe/gofakeit/v7/data/currency.go | 7 + .../brianvoe/gofakeit/v7/data/data.go | 91 + .../brianvoe/gofakeit/v7/data/datetime.go | 10 + .../brianvoe/gofakeit/v7/data/emoji.go | 5849 ++++++++ .../brianvoe/gofakeit/v7/data/errors.go | 122 + .../brianvoe/gofakeit/v7/data/files.go | 7 + .../brianvoe/gofakeit/v7/data/food.go | 13 + .../brianvoe/gofakeit/v7/data/hacker.go | 20 + .../brianvoe/gofakeit/v7/data/hipster.go | 6 + .../brianvoe/gofakeit/v7/data/html.go | 7 + .../brianvoe/gofakeit/v7/data/internet.go | 11 + .../brianvoe/gofakeit/v7/data/job.go | 8 + .../brianvoe/gofakeit/v7/data/languages.go | 9 + .../brianvoe/gofakeit/v7/data/log_level.go | 8 + .../brianvoe/gofakeit/v7/data/lorem.go | 6 + .../brianvoe/gofakeit/v7/data/minecraft.go | 23 + .../brianvoe/gofakeit/v7/data/movie.go | 130 + .../brianvoe/gofakeit/v7/data/payment.go | 211 + .../brianvoe/gofakeit/v7/data/person.go | 12 + .../brianvoe/gofakeit/v7/data/product.go | 171 + .../brianvoe/gofakeit/v7/data/school.go | 56 + .../brianvoe/gofakeit/v7/data/sentence.go | 5 + .../brianvoe/gofakeit/v7/data/song.go | 246 + .../brianvoe/gofakeit/v7/data/word.go | 83 + vendor/github.com/brianvoe/gofakeit/v7/doc.go | 4 + .../github.com/brianvoe/gofakeit/v7/emoji.go | 98 + .../github.com/brianvoe/gofakeit/v7/error.go | 241 + .../brianvoe/gofakeit/v7/fakeable.go | 84 + .../github.com/brianvoe/gofakeit/v7/faker.go | 112 + .../github.com/brianvoe/gofakeit/v7/file.go | 41 + .../brianvoe/gofakeit/v7/finance.go | 127 + .../github.com/brianvoe/gofakeit/v7/food.go | 177 + .../github.com/brianvoe/gofakeit/v7/game.go | 101 + .../brianvoe/gofakeit/v7/generate.go | 600 + .../github.com/brianvoe/gofakeit/v7/hacker.go | 137 + .../brianvoe/gofakeit/v7/helpers.go | 374 + .../brianvoe/gofakeit/v7/hipster.go | 130 + .../github.com/brianvoe/gofakeit/v7/html.go | 174 + .../github.com/brianvoe/gofakeit/v7/image.go | 122 + .../brianvoe/gofakeit/v7/internet.go | 440 + .../github.com/brianvoe/gofakeit/v7/json.go | 348 + .../brianvoe/gofakeit/v7/languages.go | 81 + .../github.com/brianvoe/gofakeit/v7/logo.png | Bin 0 -> 26580 bytes .../github.com/brianvoe/gofakeit/v7/lookup.go | 516 + .../github.com/brianvoe/gofakeit/v7/lorem.go | 126 + .../brianvoe/gofakeit/v7/minecraft.go | 365 + .../github.com/brianvoe/gofakeit/v7/misc.go | 164 + .../github.com/brianvoe/gofakeit/v7/movie.go | 68 + .../github.com/brianvoe/gofakeit/v7/number.go | 703 + .../brianvoe/gofakeit/v7/payment.go | 443 + .../github.com/brianvoe/gofakeit/v7/person.go | 423 + .../brianvoe/gofakeit/v7/product.go | 390 + .../github.com/brianvoe/gofakeit/v7/school.go | 25 + .../github.com/brianvoe/gofakeit/v7/slice.go | 15 + .../github.com/brianvoe/gofakeit/v7/song.go | 87 + .../brianvoe/gofakeit/v7/source/BENCHMARKS.md | 16 + .../brianvoe/gofakeit/v7/source/README.md | 65 + .../brianvoe/gofakeit/v7/source/crypto.go | 55 + .../brianvoe/gofakeit/v7/source/dumb.go | 44 + .../brianvoe/gofakeit/v7/source/jsf.go | 50 + .../brianvoe/gofakeit/v7/source/sfc.go | 44 + vendor/github.com/brianvoe/gofakeit/v7/sql.go | 156 + .../github.com/brianvoe/gofakeit/v7/string.go | 270 + .../github.com/brianvoe/gofakeit/v7/struct.go | 619 + .../brianvoe/gofakeit/v7/template.go | 440 + .../github.com/brianvoe/gofakeit/v7/time.go | 501 + .../brianvoe/gofakeit/v7/weighted.go | 106 + .../brianvoe/gofakeit/v7/word_adjective.go | 180 + .../brianvoe/gofakeit/v7/word_adverb.go | 174 + .../brianvoe/gofakeit/v7/word_comment.go | 72 + .../brianvoe/gofakeit/v7/word_connective.go | 159 + .../brianvoe/gofakeit/v7/word_general.go | 37 + .../brianvoe/gofakeit/v7/word_grammar.go | 34 + .../brianvoe/gofakeit/v7/word_helper.go | 45 + .../brianvoe/gofakeit/v7/word_misc.go | 22 + .../brianvoe/gofakeit/v7/word_noun.go | 242 + .../brianvoe/gofakeit/v7/word_phrase.go | 162 + .../brianvoe/gofakeit/v7/word_preposition.go | 92 + .../brianvoe/gofakeit/v7/word_pronoun.go | 202 + .../brianvoe/gofakeit/v7/word_sentence.go | 212 + .../brianvoe/gofakeit/v7/word_verb.go | 126 + vendor/github.com/brianvoe/gofakeit/v7/xml.go | 349 + .../go-ethereum/internal/debug/flags.go | 4 - vendor/github.com/fjl/memsize/.travis.yml | 9 - vendor/github.com/fjl/memsize/LICENSE | 21 - vendor/github.com/fjl/memsize/bitmap.go | 119 - vendor/github.com/fjl/memsize/doc.go | 16 - vendor/github.com/fjl/memsize/mapiter_go12.go | 12 - vendor/github.com/fjl/memsize/mapiter_old.go | 11 - vendor/github.com/fjl/memsize/memsize.go | 246 - .../fjl/memsize/memsizeui/template.go | 106 - vendor/github.com/fjl/memsize/memsizeui/ui.go | 153 - vendor/github.com/fjl/memsize/runtimefunc.go | 14 - vendor/github.com/fjl/memsize/runtimefunc.s | 1 - vendor/github.com/fjl/memsize/type.go | 119 - .../github.com/golang/protobuf/ptypes/any.go | 179 - .../golang/protobuf/ptypes/any/any.pb.go | 62 - .../github.com/golang/protobuf/ptypes/doc.go | 10 - .../golang/protobuf/ptypes/duration.go | 76 - .../protobuf/ptypes/duration/duration.pb.go | 63 - .../golang/protobuf/ptypes/timestamp.go | 112 - .../protobuf/ptypes/timestamp/timestamp.pb.go | 64 - vendor/github.com/okzk/sdnotify/LICENSE | 21 - vendor/github.com/okzk/sdnotify/README.md | 15 - vendor/github.com/okzk/sdnotify/notify.go | 9 - .../github.com/okzk/sdnotify/notify_linux.go | 23 - vendor/github.com/okzk/sdnotify/util.go | 39 - .../siphiuel/lc-proxy-wrapper/.gitignore | 2 - .../siphiuel/lc-proxy-wrapper/Makefile | 13 - .../siphiuel/lc-proxy-wrapper/Makefile.vars | 15 - .../siphiuel/lc-proxy-wrapper/README.md | 6 - .../siphiuel/lc-proxy-wrapper/cb.nim | 27 - .../siphiuel/lc-proxy-wrapper/cfuncs.go | 12 - .../siphiuel/lc-proxy-wrapper/proxy.go | 104 - .../status-im/extkeys/.golangci.yml | 44 + vendor/github.com/status-im/extkeys/hdkey.go | 17 +- vendor/github.com/status-im/extkeys/utils.go | 4 +- .../migrate/v4/database/postgres/README.md | 28 - .../migrate/v4/database/postgres/TUTORIAL.md | 148 - .../migrate/v4/database/postgres/postgres.go | 362 - .../waku-go-bindings/waku/common/config.go | 4 + .../waku-org/waku-go-bindings/waku/nwaku.go | 215 +- .../x/crypto/blake2b/blake2bAVX2_amd64.s | 5167 ++++++- .../x/crypto/blake2b/blake2b_amd64.s | 1681 ++- .../x/crypto/blake2s/blake2s_amd64.s | 2571 +++- .../x/crypto/chacha20/chacha_noasm.go | 2 +- .../{chacha_ppc64le.go => chacha_ppc64x.go} | 2 +- .../{chacha_ppc64le.s => chacha_ppc64x.s} | 114 +- .../chacha20poly1305/chacha20poly1305_amd64.s | 11503 +++++++++++++--- .../x/crypto/internal/poly1305/mac_noasm.go | 2 +- .../x/crypto/internal/poly1305/sum_amd64.s | 133 +- .../{sum_ppc64le.go => sum_ppc64x.go} | 2 +- .../poly1305/{sum_ppc64le.s => sum_ppc64x.s} | 30 +- .../x/crypto/salsa20/salsa/salsa20_amd64.s | 1742 +-- vendor/golang.org/x/crypto/sha3/doc.go | 4 + vendor/golang.org/x/crypto/sha3/hashes.go | 31 +- vendor/golang.org/x/crypto/sha3/sha3.go | 187 +- vendor/golang.org/x/crypto/sha3/shake.go | 89 +- vendor/golang.org/x/crypto/sha3/xor.go | 40 - .../x/crypto/ssh/terminal/terminal.go | 76 - vendor/golang.org/x/image/AUTHORS | 3 - vendor/golang.org/x/image/CONTRIBUTORS | 3 - vendor/golang.org/x/image/LICENSE | 4 +- vendor/golang.org/x/image/bmp/reader.go | 86 +- vendor/golang.org/x/image/draw/draw.go | 6 + vendor/golang.org/x/image/draw/impl.go | 2820 +++- vendor/golang.org/x/image/draw/scale.go | 56 +- .../x/image/font/basicfont/basicfont.go | 65 +- vendor/golang.org/x/image/font/font.go | 79 +- .../x/image/font/opentype/opentype.go | 19 +- vendor/golang.org/x/image/font/sfnt/cmap.go | 3 + vendor/golang.org/x/image/font/sfnt/gpos.go | 4 +- .../x/image/font/sfnt/postscript.go | 12 + vendor/golang.org/x/image/font/sfnt/sfnt.go | 60 +- .../golang.org/x/image/font/sfnt/truetype.go | 14 +- vendor/golang.org/x/image/vector/acc_amd64.go | 1 - vendor/golang.org/x/image/vector/acc_other.go | 1 - .../golang.org/x/image/vector/raster_fixed.go | 3 + vendor/golang.org/x/image/webp/decode.go | 5 + vendor/golang.org/x/mod/modfile/read.go | 5 + vendor/golang.org/x/net/html/doc.go | 7 +- vendor/golang.org/x/net/html/doctype.go | 2 +- vendor/golang.org/x/net/html/foreign.go | 3 +- vendor/golang.org/x/net/html/iter.go | 56 + vendor/golang.org/x/net/html/node.go | 4 + vendor/golang.org/x/net/html/parse.go | 8 +- .../net/internal/socket/zsys_openbsd_ppc64.go | 28 +- .../internal/socket/zsys_openbsd_riscv64.go | 28 +- vendor/golang.org/x/net/route/address.go | 55 +- vendor/golang.org/x/net/route/sys_netbsd.go | 2 +- vendor/golang.org/x/net/route/zsys_darwin.go | 8 +- .../golang.org/x/net/route/zsys_dragonfly.go | 8 +- .../x/net/route/zsys_freebsd_386.go | 20 +- .../x/net/route/zsys_freebsd_amd64.go | 20 +- .../x/net/route/zsys_freebsd_arm.go | 20 +- .../x/net/route/zsys_freebsd_arm64.go | 20 +- .../x/net/route/zsys_freebsd_riscv64.go | 20 +- vendor/golang.org/x/net/route/zsys_netbsd.go | 8 +- vendor/golang.org/x/net/route/zsys_openbsd.go | 5 +- vendor/golang.org/x/sync/errgroup/errgroup.go | 1 + .../golang.org/x/sys/cpu/asm_darwin_x86_gc.s | 17 + vendor/golang.org/x/sys/cpu/cpu.go | 22 + vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go | 61 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 4 +- .../x/sys/cpu/{cpu_x86.s => cpu_gc_x86.s} | 2 +- vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 6 - .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 1 - .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 2 +- .../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 137 + .../cpu/cpu_other_x86.go} | 11 +- vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 11 +- vendor/golang.org/x/sys/cpu/cpu_x86.go | 27 +- .../x/sys/cpu/syscall_darwin_x86_gc.go | 98 + vendor/golang.org/x/sys/plan9/asm.s | 8 - vendor/golang.org/x/sys/plan9/asm_plan9_386.s | 30 - .../golang.org/x/sys/plan9/asm_plan9_amd64.s | 30 - vendor/golang.org/x/sys/plan9/asm_plan9_arm.s | 25 - vendor/golang.org/x/sys/plan9/const_plan9.go | 70 - vendor/golang.org/x/sys/plan9/dir_plan9.go | 212 - vendor/golang.org/x/sys/plan9/env_plan9.go | 31 - vendor/golang.org/x/sys/plan9/errors_plan9.go | 50 - vendor/golang.org/x/sys/plan9/mkall.sh | 150 - vendor/golang.org/x/sys/plan9/mkerrors.sh | 246 - .../golang.org/x/sys/plan9/mksysnum_plan9.sh | 23 - .../golang.org/x/sys/plan9/pwd_go15_plan9.go | 21 - vendor/golang.org/x/sys/plan9/pwd_plan9.go | 23 - vendor/golang.org/x/sys/plan9/race.go | 30 - vendor/golang.org/x/sys/plan9/race0.go | 25 - vendor/golang.org/x/sys/plan9/str.go | 22 - vendor/golang.org/x/sys/plan9/syscall.go | 109 - .../golang.org/x/sys/plan9/syscall_plan9.go | 361 - .../x/sys/plan9/zsyscall_plan9_386.go | 284 - .../x/sys/plan9/zsyscall_plan9_amd64.go | 284 - .../x/sys/plan9/zsyscall_plan9_arm.go | 284 - .../golang.org/x/sys/plan9/zsysnum_plan9.go | 49 - vendor/golang.org/x/sys/unix/README.md | 2 +- vendor/golang.org/x/sys/unix/auxv.go | 36 + .../golang.org/x/sys/unix/auxv_unsupported.go | 13 + vendor/golang.org/x/sys/unix/ioctl_linux.go | 96 + vendor/golang.org/x/sys/unix/mkerrors.sh | 17 +- vendor/golang.org/x/sys/unix/syscall_aix.go | 2 +- .../golang.org/x/sys/unix/syscall_darwin.go | 37 + .../x/sys/unix/syscall_dragonfly.go | 12 + vendor/golang.org/x/sys/unix/syscall_hurd.go | 1 + vendor/golang.org/x/sys/unix/syscall_linux.go | 64 +- .../x/sys/unix/syscall_linux_arm64.go | 2 + .../x/sys/unix/syscall_linux_loong64.go | 2 + .../x/sys/unix/syscall_linux_riscv64.go | 2 + .../golang.org/x/sys/unix/syscall_solaris.go | 87 + .../x/sys/unix/syscall_zos_s390x.go | 104 +- .../golang.org/x/sys/unix/vgetrandom_linux.go | 13 + .../unix/vgetrandom_unsupported.go} | 11 +- .../x/sys/unix/zerrors_darwin_amd64.go | 7 + .../x/sys/unix/zerrors_darwin_arm64.go | 7 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 64 +- .../x/sys/unix/zerrors_linux_386.go | 28 + .../x/sys/unix/zerrors_linux_amd64.go | 28 + .../x/sys/unix/zerrors_linux_arm.go | 28 + .../x/sys/unix/zerrors_linux_arm64.go | 30 + .../x/sys/unix/zerrors_linux_loong64.go | 28 + .../x/sys/unix/zerrors_linux_mips.go | 28 + .../x/sys/unix/zerrors_linux_mips64.go | 28 + .../x/sys/unix/zerrors_linux_mips64le.go | 28 + .../x/sys/unix/zerrors_linux_mipsle.go | 28 + .../x/sys/unix/zerrors_linux_ppc.go | 28 + .../x/sys/unix/zerrors_linux_ppc64.go | 28 + .../x/sys/unix/zerrors_linux_ppc64le.go | 28 + .../x/sys/unix/zerrors_linux_riscv64.go | 28 + .../x/sys/unix/zerrors_linux_s390x.go | 28 + .../x/sys/unix/zerrors_linux_sparc64.go | 28 + .../x/sys/unix/zerrors_zos_s390x.go | 2 + .../x/sys/unix/zsyscall_darwin_amd64.go | 20 + .../x/sys/unix/zsyscall_darwin_amd64.s | 5 + .../x/sys/unix/zsyscall_darwin_arm64.go | 20 + .../x/sys/unix/zsyscall_darwin_arm64.s | 5 + .../golang.org/x/sys/unix/zsyscall_linux.go | 27 +- .../x/sys/unix/zsyscall_solaris_amd64.go | 114 + .../x/sys/unix/zsysnum_linux_386.go | 4 + .../x/sys/unix/zsysnum_linux_amd64.go | 5 + .../x/sys/unix/zsysnum_linux_arm.go | 4 + .../x/sys/unix/zsysnum_linux_arm64.go | 6 +- .../x/sys/unix/zsysnum_linux_loong64.go | 6 + .../x/sys/unix/zsysnum_linux_mips.go | 4 + .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 4 + .../x/sys/unix/zsysnum_linux_ppc.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 4 + .../x/sys/unix/zsysnum_linux_riscv64.go | 6 +- .../x/sys/unix/zsysnum_linux_s390x.go | 4 + .../x/sys/unix/zsysnum_linux_sparc64.go | 4 + .../x/sys/unix/ztypes_darwin_amd64.go | 73 + .../x/sys/unix/ztypes_darwin_arm64.go | 73 + .../x/sys/unix/ztypes_freebsd_386.go | 1 + .../x/sys/unix/ztypes_freebsd_amd64.go | 1 + .../x/sys/unix/ztypes_freebsd_arm.go | 1 + .../x/sys/unix/ztypes_freebsd_arm64.go | 1 + .../x/sys/unix/ztypes_freebsd_riscv64.go | 1 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 228 +- .../x/sys/unix/ztypes_linux_riscv64.go | 33 + .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 6 + .../golang.org/x/sys/windows/dll_windows.go | 13 +- .../x/sys/windows/syscall_windows.go | 40 +- .../golang.org/x/sys/windows/types_windows.go | 128 + .../x/sys/windows/zsyscall_windows.go | 109 + vendor/golang.org/x/term/CONTRIBUTING.md | 26 - vendor/golang.org/x/term/LICENSE | 27 - vendor/golang.org/x/term/PATENTS | 22 - vendor/golang.org/x/term/README.md | 19 - vendor/golang.org/x/term/codereview.cfg | 1 - vendor/golang.org/x/term/term.go | 60 - vendor/golang.org/x/term/term_plan9.go | 42 - vendor/golang.org/x/term/term_unix.go | 91 - vendor/golang.org/x/term/term_unix_bsd.go | 12 - vendor/golang.org/x/term/term_unix_other.go | 12 - vendor/golang.org/x/term/term_unsupported.go | 38 - vendor/golang.org/x/term/term_windows.go | 79 - vendor/golang.org/x/term/terminal.go | 986 -- .../x/tools/cmd/goimports/gotypesalias.go | 12 + .../x/tools/go/analysis/analysis.go | 9 +- .../go/analysis/analysistest/analysistest.go | 237 +- .../x/tools/go/analysis/checker/checker.go | 637 + .../analysis/checker/iter_go122.go} | 12 +- .../analysis/checker/iter_go123.go} | 13 +- .../x/tools/go/analysis/checker/print.go | 88 + .../x/tools/go/analysis/diagnostic.go | 4 +- .../analysis/internal/analysisflags/flags.go | 37 +- .../go/analysis/internal/checker/checker.go | 1083 +- .../x/tools/go/analysis/internal/internal.go | 12 + .../go/analysis/unitchecker/unitchecker.go | 54 +- .../x/tools/go/ast/astutil/imports.go | 5 + .../golang.org/x/tools/go/ast/astutil/util.go | 12 +- .../x/tools/go/ast/inspector/inspector.go | 148 +- .../x/tools/go/ast/inspector/iter.go | 85 + .../x/tools/go/ast/inspector/typeof.go | 5 +- .../x/tools/go/ast/inspector/walk.go | 341 + .../x/tools/go/gcexportdata/gcexportdata.go | 119 +- vendor/golang.org/x/tools/go/packages/doc.go | 15 +- .../x/tools/go/packages/external.go | 15 +- .../golang.org/x/tools/go/packages/golist.go | 48 +- .../x/tools/go/packages/loadmode_string.go | 71 +- .../x/tools/go/packages/packages.go | 398 +- .../x/tools/go/types/objectpath/objectpath.go | 111 +- .../x/tools/go/types/typeutil/callee.go | 68 + .../x/tools/go/types/typeutil/imports.go | 30 + .../x/tools/go/types/typeutil/map.go | 470 + .../tools/go/types/typeutil/methodsetcache.go | 71 + .../x/tools/go/types/typeutil/ui.go | 53 + .../x/tools/internal/aliases/aliases.go | 10 +- .../x/tools/internal/aliases/aliases_go121.go | 35 - .../x/tools/internal/aliases/aliases_go122.go | 33 +- .../internal/analysisinternal/analysis.go | 530 +- .../x/tools/internal/astutil/edge/edge.go | 295 + .../x/tools/internal/diff/lcs/old.go | 1 + .../golang.org/x/tools/internal/diff/merge.go | 81 + .../x/tools/internal/facts/imports.go | 34 +- .../x/tools/internal/gcimporter/bimport.go | 61 - .../x/tools/internal/gcimporter/exportdata.go | 426 +- .../x/tools/internal/gcimporter/gcimporter.go | 182 +- .../x/tools/internal/gcimporter/iexport.go | 284 +- .../x/tools/internal/gcimporter/iimport.go | 55 +- .../internal/gcimporter/iimport_go122.go | 53 + .../internal/gcimporter/newInterface10.go | 22 - .../internal/gcimporter/newInterface11.go | 14 - .../tools/internal/gcimporter/predeclared.go | 91 + .../x/tools/internal/gcimporter/support.go | 30 + .../internal/gcimporter/support_go118.go | 34 - .../x/tools/internal/gcimporter/unified_no.go | 10 - .../tools/internal/gcimporter/unified_yes.go | 10 - .../tools/internal/gcimporter/ureader_yes.go | 59 +- .../x/tools/internal/gocommand/invoke.go | 60 +- .../internal/gocommand/invoke_notunix.go | 13 + .../x/tools/internal/gocommand/invoke_unix.go | 13 + .../x/tools/internal/imports/fix.go | 251 +- .../x/tools/internal/imports/imports.go | 33 +- .../x/tools/internal/imports/mod.go | 9 +- .../x/tools/internal/imports/source.go | 63 + .../x/tools/internal/imports/source_env.go | 129 + .../tools/internal/imports/source_modindex.go | 103 + .../x/tools/internal/modindex/directories.go | 135 + .../x/tools/internal/modindex/index.go | 266 + .../x/tools/internal/modindex/lookup.go | 178 + .../x/tools/internal/modindex/modindex.go | 164 + .../x/tools/internal/modindex/symbols.go | 218 + .../x/tools/internal/modindex/types.go | 25 + .../internal/packagesinternal/packages.go | 6 +- .../x/tools/internal/pkgbits/decoder.go | 34 +- .../x/tools/internal/pkgbits/encoder.go | 43 +- .../x/tools/internal/pkgbits/frames_go1.go | 21 - .../x/tools/internal/pkgbits/frames_go17.go | 28 - .../x/tools/internal/pkgbits/support.go | 2 +- .../x/tools/internal/pkgbits/sync.go | 23 + .../internal/pkgbits/syncmarker_string.go | 7 +- .../x/tools/internal/pkgbits/version.go | 85 + .../tools/internal/robustio/gopls_windows.go | 16 - .../x/tools/internal/robustio/robustio.go | 69 - .../internal/robustio/robustio_darwin.go | 21 - .../tools/internal/robustio/robustio_flaky.go | 92 - .../tools/internal/robustio/robustio_other.go | 28 - .../tools/internal/robustio/robustio_plan9.go | 26 - .../tools/internal/robustio/robustio_posix.go | 26 - .../internal/robustio/robustio_windows.go | 51 - .../x/tools/internal/stdlib/manifest.go | 221 +- .../x/tools/internal/testenv/testenv.go | 107 + .../internal/tokeninternal/tokeninternal.go | 137 - .../x/tools/internal/typeparams/common.go | 68 + .../x/tools/internal/typeparams/coretype.go | 155 + .../x/tools/internal/typeparams/free.go | 131 + .../x/tools/internal/typeparams/normalize.go | 218 + .../x/tools/internal/typeparams/termlist.go | 163 + .../x/tools/internal/typeparams/typeterm.go | 169 + .../x/tools/internal/typesinternal/element.go | 133 + .../tools/internal/typesinternal/errorcode.go | 10 +- .../tools/internal/typesinternal/qualifier.go | 46 + .../x/tools/internal/typesinternal/recv.go | 11 +- .../x/tools/internal/typesinternal/types.go | 62 + .../x/tools/internal/typesinternal/varkind.go | 40 + .../tools/internal/typesinternal/zerovalue.go | 392 + .../x/tools/internal/versions/constraint.go | 13 - .../x/tools/internal/versions/toolchain.go | 14 - .../x/tools/internal/versions/types.go | 28 +- .../x/tools/internal/versions/types_go121.go | 30 - .../x/tools/internal/versions/types_go122.go | 41 - vendor/golang.org/x/tools/txtar/fs.go | 6 +- .../protobuf/types/known/anypb/any.pb.go | 496 - .../types/known/durationpb/duration.pb.go | 374 - vendor/modules.txt | 67 +- waku/types/mailserver_test.go | 28 - wakuv2/common/stats.go | 124 - wakuv2/persistence/queries.go | 103 - wakuv2/telemetry.go | 67 - 823 files changed, 83048 insertions(+), 39369 deletions(-) create mode 100644 .github/workflows/pr.yml create mode 100644 Dockerfile create mode 120000 _assets/ci/Jenkinsfile.linux-nix create mode 120000 _assets/ci/Jenkinsfile.macos-nix create mode 100644 _assets/ci/Jenkinsfile.nix create mode 100644 _assets/ci/Jenkinsfile.tests-benchmark create mode 100755 _assets/scripts/push_benchmark.sh create mode 100755 _assets/scripts/run_benchmark.sh create mode 100644 accounts-management/README.md create mode 100644 accounts-management/accounts.go create mode 100644 accounts-management/common/address.go create mode 100644 accounts-management/common/address_test.go create mode 100644 accounts-management/common/const.go create mode 100644 accounts-management/common/mnemonic.go create mode 100644 accounts-management/common/mnemonic_test.go create mode 100644 accounts-management/common/publickey.go create mode 100644 accounts-management/common/publickey_test.go create mode 100644 accounts-management/common/utils.go create mode 100644 accounts-management/core/errors.go create mode 100644 accounts-management/core/keystore_operations.go create mode 100644 accounts-management/core/manager.go create mode 100644 accounts-management/core/manager_test.go create mode 100644 accounts-management/core/persistence_operations.go create mode 100644 accounts-management/errors/errors.go create mode 100644 accounts-management/errors/errors_test.go create mode 100644 accounts-management/errors/errors_test_data.go create mode 100644 accounts-management/generator/README.md create mode 100644 accounts-management/generator/errors.go create mode 100644 accounts-management/generator/generator.go create mode 100644 accounts-management/generator/generator_test.go create mode 100644 accounts-management/generator/path_decoder.go create mode 100644 accounts-management/generator/path_decoder_test.go create mode 100644 accounts-management/generator/types.go create mode 100644 accounts-management/generator/types_test.go create mode 100644 accounts-management/keystore/geth/adapter.go create mode 100644 accounts-management/keystore/geth/const.go create mode 100644 accounts-management/keystore/geth/decryption.go create mode 100644 accounts-management/keystore/geth/encryption.go create mode 100644 accounts-management/keystore/geth/helper.go create mode 100644 accounts-management/keystore/geth/migration.go create mode 100644 accounts-management/keystore/geth/reencryption.go create mode 100644 accounts-management/keystore/interface.go create mode 100644 accounts-management/keystore/types/account.go create mode 100644 accounts-management/keystore/types/account_test.go create mode 100644 accounts-management/persistence/interface.go create mode 100644 accounts-management/types/key.go create mode 100644 accounts-management/types/keypair.go create mode 100644 accounts-management/types/types.go create mode 100644 accounts-management/types/types_test.go create mode 100644 appdatabase/migrations/sql/1752869164_drop_telemetry_server_url.up.sql create mode 100644 appdatabase/migrations/sql/1753221199_add_add_backup_path_setting.up.sql create mode 100644 appdatabase/migrations/sql/1754574769_drop_mailservers.up.sql create mode 100644 appdatabase/migrations/sql/1754667909_drop_http_config.up.sql create mode 100644 appdatabase/migrations/sql/1754670349_drop_ipc_config.up.sql create mode 100644 appdatabase/migrations/sql/1754670350_drop_cluster_nodes.up.sql create mode 100644 appdatabase/migrations/sql/1754670351_drop_wakuv2_custom_nodes.up.sql create mode 100644 appdatabase/migrations/sql/1754670352_cleanup_wakuv2_config.up.sql create mode 100644 appdatabase/migrations/sql/1754923284_cleanup_node_config.up.sql create mode 100644 appdatabase/migrations/sql/1755017956_drop_app_metrics.up.sql create mode 100644 appdatabase/migrations/sql/1755264069_cleanup_node_config.up.sql create mode 100644 cmd/generate-db/README.md create mode 100644 cmd/generate-db/main.go create mode 100644 cmd/push-notification-server/main.go create mode 100644 cmd/status-backend/server/options.go create mode 100644 common/errors.go create mode 100644 common/errors_test.go create mode 100644 contracts/namewrapper/namewrapper.go create mode 100644 crypto/README.md create mode 100644 crypto/crypto.go create mode 100644 crypto/ethereum_crypto.go create mode 100644 crypto/geth/provider.go create mode 100644 crypto/interface.go create mode 100644 crypto/types/address.go create mode 100644 crypto/types/errors.go create mode 100644 crypto/types/hash.go create mode 100644 crypto/types/hex.go create mode 100644 crypto/types/utils.go create mode 100644 crypto/types/utils_test.go create mode 100644 internal/enr/enr.go create mode 100644 internal/multiaddr/multiaddr.go create mode 100644 internal/timesource/timesource.go create mode 100644 messaging/adapters/encryption_subscriptions.go create mode 100644 messaging/adapters/hash_ratchet.go create mode 100644 messaging/adapters/installation.go create mode 100644 messaging/adapters/peers.go create mode 100644 messaging/adapters/received_messages.go create mode 100644 messaging/adapters/shard.go create mode 100644 messaging/adapters/shared_secret.go create mode 100644 messaging/adapters/transport_stats.go create mode 100644 messaging/common/message_segmentation.go create mode 100644 messaging/common/message_segmentation_test.go create mode 100644 messaging/common/message_sender.go create mode 100644 messaging/common/message_sender_test.go create mode 100644 messaging/common/persistence_stub_test.go create mode 100644 messaging/common/testdata/segmentationProtobufMissDecoding.bin create mode 100644 messaging/core_config.go create mode 100644 messaging/core_test_utils.go create mode 100644 messaging/datasync/datasync.go create mode 100644 messaging/datasync/peer/utils.go create mode 100644 messaging/datasync/transport.go create mode 100644 messaging/datasync/utils.go create mode 100644 messaging/events/message_event.go create mode 100644 messaging/layers/encryption/README.md create mode 100644 messaging/layers/encryption/encryption_multi_device_test.go create mode 100644 messaging/layers/encryption/encryption_test.go create mode 100644 messaging/layers/encryption/encryptor.go create mode 100644 messaging/layers/encryption/helpers.go create mode 100644 messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1540715431_add_version.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1540715431_add_version.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1558588866_add_version.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1558588866_add_version.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.down.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1636536507_add_index_bundles.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1698137564_add_migration_index.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/1709200114_add_migration_index.up.sql create mode 100644 messaging/layers/encryption/migrations/sqlite/doc.go create mode 100644 messaging/layers/encryption/multidevice/multidevice.go create mode 100644 messaging/layers/encryption/multidevice/persistence.go create mode 100644 messaging/layers/encryption/multidevice/persistence_test.go create mode 100644 messaging/layers/encryption/persistence.go create mode 100644 messaging/layers/encryption/persistence_keys_storage_test.go create mode 100644 messaging/layers/encryption/persistence_test.go create mode 100644 messaging/layers/encryption/protocol.go create mode 100644 messaging/layers/encryption/protocol_message.proto create mode 100644 messaging/layers/encryption/protocol_test.go create mode 100644 messaging/layers/encryption/publisher/doc.go create mode 100644 messaging/layers/encryption/publisher/persistence.go create mode 100644 messaging/layers/encryption/publisher/publisher.go create mode 100644 messaging/layers/encryption/publisher/publisher_test.go create mode 100644 messaging/layers/encryption/sharedsecret/persistence.go create mode 100644 messaging/layers/encryption/sharedsecret/service_test.go create mode 100644 messaging/layers/encryption/sharedsecret/sharedsecret.go create mode 100644 messaging/layers/encryption/x3dh.go create mode 100644 messaging/layers/encryption/x3dh_test.go create mode 100644 messaging/types/chat_entity.go create mode 100644 messaging/types/encryption_subscriptions.go create mode 100644 messaging/types/handle_message_response.go create mode 100644 messaging/types/hash_ratchet.go create mode 100644 messaging/types/installation.go create mode 100644 messaging/types/message.go create mode 100644 messaging/types/peers.go create mode 100644 messaging/types/raw_message.go create mode 100644 messaging/types/received_messages.go create mode 100644 messaging/types/segment_message.go create mode 100644 messaging/types/shard.go create mode 100644 messaging/types/shared_secret.go create mode 100644 messaging/types/store_node.go create mode 100644 messaging/types/transport_stats.go rename {wakuv2 => messaging/waku}/README.md (100%) rename {wakuv2 => messaging/waku}/api.go (83%) rename {wakuv2 => messaging/waku}/api_test.go (94%) rename {wakuv2 => messaging/waku}/bridge.go (78%) rename {wakuv2 => messaging/waku}/common/README.md (100%) rename {wakuv2 => messaging/waku}/common/const.go (100%) rename {wakuv2 => messaging/waku}/common/envelope.go (99%) rename {wakuv2 => messaging/waku}/common/envelope_test.go (99%) rename {wakuv2 => messaging/waku}/common/events.go (100%) rename {wakuv2 => messaging/waku}/common/filter.go (99%) rename {wakuv2 => messaging/waku}/common/filter_test.go (100%) rename {wakuv2 => messaging/waku}/common/helpers.go (93%) rename {wakuv2 => messaging/waku}/common/helpers_test.go (100%) rename {wakuv2 => messaging/waku}/common/message.go (100%) rename {wakuv2 => messaging/waku}/common/metrics.go (100%) rename {wakuv2 => messaging/waku}/common/topic.go (96%) rename {wakuv2 => messaging/waku}/common/topic_test.go (100%) rename {wakuv2 => messaging/waku}/config.go (94%) rename {wakuv2 => messaging/waku}/const.go (100%) rename {wakuv2 => messaging/waku}/gowaku.go (96%) rename {wakuv2 => messaging/waku}/gowaku_test.go (100%) rename {wakuv2 => messaging/waku}/history_processor_wrapper.go (92%) rename {wakuv2 => messaging/waku}/message_publishing.go (98%) rename {wakuv2 => messaging/waku}/nwaku.go (66%) rename {wakuv2 => messaging/waku}/nwaku_test.go (100%) rename {wakuv2 => messaging/waku}/nwaku_test_utils.go (100%) rename {wakuv2 => messaging/waku}/nwaku_utils.go (98%) rename {wakuv2 => messaging/waku}/persistence/dbkey.go (100%) rename {wakuv2 => messaging/waku}/persistence/dbstore.go (100%) rename {wakuv2 => messaging/waku}/persistence/signed_messages.go (98%) rename {wakuv2 => messaging/waku}/pinger.go (100%) rename {wakuv2 => messaging/waku}/publisher.go (100%) rename {wakuv2 => messaging/waku}/result.go (100%) rename {wakuv2 => messaging/waku}/shard.go (93%) rename {wakuv2 => messaging/waku}/store_message_verifier.go (100%) rename {wakuv2 => messaging/waku}/storenode_requestor.go (100%) rename {wakuv2 => messaging/waku}/tracer.go (100%) rename {waku => messaging/waku}/types/envelopes.go (92%) rename {waku => messaging/waku}/types/filter.go (100%) rename {waku => messaging/waku}/types/mailserver.go (56%) rename {waku => messaging/waku}/types/rpc.go (73%) rename {waku => messaging/waku}/types/stats.go (100%) rename {waku => messaging/waku}/types/subscribe.go (100%) rename {waku => messaging/waku}/types/topic.go (94%) rename {waku => messaging/waku}/types/waku.go (96%) rename {waku => messaging/waku}/types/wrapped.go (100%) rename {wakuv2 => messaging/waku}/waku_test.go (64%) rename {wakuv2 => messaging/waku}/waku_unsupported.go (100%) create mode 100644 messaging/wakumetrics/client.go create mode 100644 messaging/wakumetrics/client_test.go create mode 100644 messaging/wakumetrics/metrics.go create mode 100644 metrics/metrics_test.go create mode 100644 multiaccounts/accounts/accounts_manager_adapter.go create mode 100644 multiaccounts/accounts/accounts_manager_types_mapper.go create mode 100644 multiaccounts/settings/events.go create mode 100644 node/backup/controller.go create mode 100644 node/backup/controller_test.go create mode 100644 node/backup/core.go create mode 100644 params/storenode_test.go create mode 100644 pkg/pubsub/README.md create mode 100644 pkg/pubsub/publisher.go create mode 100644 pkg/pubsub/pubsub.go create mode 100644 pkg/pubsub/pubsub_test.go create mode 100644 pkg/pubsub/type_publisher.go create mode 100644 protocol/accounts_manager_interface.go create mode 100644 protocol/messaging_persistence.go create mode 100644 protocol/messaging_persistence_test.go create mode 100644 protocol/messenger_local_backup.go create mode 100644 protocol/messenger_local_backup_test.go create mode 100644 protocol/messenger_pubsub_events.go create mode 100644 protocol/migrations/sqlite/1754570630_drop_community_storenodes.up.sql create mode 100644 protocol/protobuf/accounts_local_backup.proto create mode 100644 protocol/protobuf/messenger_local_backup.proto create mode 100644 protocol/protobuf/wallet_local_backup.proto create mode 100644 protocol/requests/load_local_backup.go create mode 100644 rpc/events.go create mode 100644 rpc/network/events.go create mode 100644 rpc/signals_transmitter.go create mode 100644 services/ens/ensresolver/address.go create mode 100644 services/ens/ensresolver/address_test.go create mode 100644 services/personal/service_test.go create mode 100644 services/wallet/leaderboard/utils.go create mode 100644 services/wallet/thirdparty/utils/chunk_fetcher.go create mode 100644 services/wallet/thirdparty/utils/chunk_fetcher_test.go create mode 100644 signal/events_networks.go create mode 100644 signal/events_peerstats.go create mode 100644 tests-functional/.dockerignore create mode 100644 tests-functional/.gitignore create mode 100644 tests-functional/Makefile create mode 100644 tests-functional/clients/expvar.py create mode 100644 tests-functional/clients/gorush_stub.py create mode 100644 tests-functional/clients/metrics.py create mode 100644 tests-functional/clients/push_notification_server.py create mode 100644 tests-functional/clients/statusgo_container.py create mode 100644 tests-functional/resources/images/test-image-200x200.jpg create mode 100644 tests-functional/resources/test_data/__init__.py create mode 100644 tests-functional/resources/test_data/mnemonic_12.py create mode 100644 tests-functional/resources/test_data/mnemonic_15.py create mode 100644 tests-functional/resources/test_data/mnemonic_24.py create mode 100644 tests-functional/resources/test_data/profile_showcase_utils.py create mode 100644 tests-functional/resources/test_data/test_old_user_data.bkp create mode 100644 tests-functional/resources/utils.py create mode 100644 tests-functional/schemas/accounts_addKeypairViaSeedPhrase delete mode 100644 tests-functional/schemas/wakuext_editMessage delete mode 100644 tests-functional/schemas/wakuext_emojiReactionsByChatID delete mode 100644 tests-functional/schemas/wakuext_emojiReactionsByChatIDMessageID delete mode 100644 tests-functional/schemas/wakuext_firstUnseenMessageID delete mode 100644 tests-functional/schemas/wakuext_getActivityCenterState delete mode 100644 tests-functional/schemas/wakuext_getLatestContactRequestForContact delete mode 100644 tests-functional/schemas/wakuext_getSavedAddresses delete mode 100644 tests-functional/schemas/wakuext_getSavedAddressesPerMode delete mode 100644 tests-functional/schemas/wakuext_hasUnseenActivityCenterNotifications delete mode 100644 tests-functional/schemas/wakuext_markActivityCenterNotificationsRead delete mode 100644 tests-functional/schemas/wakuext_markActivityCenterNotificationsUnread delete mode 100644 tests-functional/schemas/wakuext_markAllActivityCenterNotificationsRead delete mode 100644 tests-functional/schemas/wakuext_markAsSeenActivityCenterNotifications delete mode 100644 tests-functional/schemas/wakuext_markMessageAsUnread delete mode 100644 tests-functional/schemas/wakuext_messageByMessageID delete mode 100644 tests-functional/schemas/wakuext_peers delete mode 100644 tests-functional/schemas/wakuext_removeContact delete mode 100644 tests-functional/schemas/wakuext_requestTransaction delete mode 100644 tests-functional/schemas/wakuext_retractContactRequest delete mode 100644 tests-functional/schemas/wakuext_sendChatMessage delete mode 100644 tests-functional/schemas/wakuext_sendContactRequest delete mode 100644 tests-functional/schemas/wakuext_sendEmojiReaction delete mode 100644 tests-functional/schemas/wakuext_sendEmojiReactionRetraction delete mode 100644 tests-functional/schemas/wakuext_sendGroupChatMessage delete mode 100644 tests-functional/schemas/wakuext_sendOneToOneMessage delete mode 100644 tests-functional/schemas/wakuext_sendPinMessage delete mode 100644 tests-functional/schemas/wakuext_sendTransaction delete mode 100644 tests-functional/schemas/wakuext_setContactLocalNickname delete mode 100644 tests-functional/schemas/wakuext_setUserStatus delete mode 100644 tests-functional/schemas/wakuext_statusUpdates delete mode 100644 tests-functional/schemas/wakuext_updateMessageOutgoingStatus delete mode 100644 tests-functional/schemas/wallet_checkRecentHistoryForChainIDs delete mode 100644 tests-functional/schemas/wallet_fetchAllCurrencyFormats delete mode 100644 tests-functional/schemas/wallet_fetchMarketValues delete mode 100644 tests-functional/schemas/wallet_fetchPrices delete mode 100644 tests-functional/schemas/wallet_fetchTokenDetails delete mode 100644 tests-functional/schemas/wallet_filterActivityAsync delete mode 100644 tests-functional/schemas/wallet_getCachedCurrencyFormats delete mode 100644 tests-functional/schemas/wallet_getCryptoOnRamps delete mode 100644 tests-functional/schemas/wallet_getEthereumChains delete mode 100644 tests-functional/schemas/wallet_getOwnedCollectiblesAsync delete mode 100644 tests-functional/schemas/wallet_getPendingTransactions delete mode 100644 tests-functional/schemas/wallet_getPendingTransactionsForIdentities delete mode 100644 tests-functional/schemas/wallet_getTokenList delete mode 100644 tests-functional/schemas/wallet_getWalletConnectActiveSessions delete mode 100644 tests-functional/schemas/wallet_startWallet delete mode 100644 tests-functional/schemas/wallet_stopSuggestedRoutesAsyncCalculation delete mode 100644 tests-functional/steps/eth_rpc.py delete mode 100644 tests-functional/steps/status_backend.py delete mode 100644 tests-functional/steps/wallet.py create mode 100644 tests-functional/tests/benchmark/test_basic_benchmark.py create mode 100644 tests-functional/tests/conftest.py create mode 100644 tests-functional/tests/reliability/README.MD create mode 100644 tests-functional/tests/test_add_account.py create mode 100644 tests-functional/tests/test_backup_mnemonic_and_restore.py create mode 100644 tests-functional/tests/test_local_backup.py create mode 100644 tests-functional/tests/test_local_pairing.py create mode 100644 tests-functional/tests/test_move_wallet_account.py create mode 100644 tests-functional/tests/test_push_notification_server.py create mode 100644 tests-functional/tests/test_resolve_suggested_path.py create mode 100644 tests-functional/tests/test_token_preferences.py create mode 100644 tests-functional/tests/test_update_keypair_name.py create mode 100644 tests-functional/tests/test_verify_password.py create mode 100644 tests-functional/tests/test_wakuext_group_chats.py delete mode 100644 tests-functional/tests/test_wakuext_messages_light_client.py create mode 100644 tests-functional/tests/test_wallet_assets.py create mode 100644 tests-functional/utils/config.py create mode 100644 tests-functional/utils/keys.py delete mode 100644 tests-functional/utils/schema_builder.py create mode 100644 tests-functional/waku_configs/pushfleetconfig.json delete mode 100644 vendor/github.com/BurntSushi/toml/.gitignore delete mode 100644 vendor/github.com/BurntSushi/toml/COPYING delete mode 100644 vendor/github.com/BurntSushi/toml/README.md delete mode 100644 vendor/github.com/BurntSushi/toml/decode.go delete mode 100644 vendor/github.com/BurntSushi/toml/decode_go116.go delete mode 100644 vendor/github.com/BurntSushi/toml/deprecated.go delete mode 100644 vendor/github.com/BurntSushi/toml/doc.go delete mode 100644 vendor/github.com/BurntSushi/toml/encode.go delete mode 100644 vendor/github.com/BurntSushi/toml/error.go delete mode 100644 vendor/github.com/BurntSushi/toml/internal/tz.go delete mode 100644 vendor/github.com/BurntSushi/toml/lex.go delete mode 100644 vendor/github.com/BurntSushi/toml/meta.go delete mode 100644 vendor/github.com/BurntSushi/toml/parse.go delete mode 100644 vendor/github.com/BurntSushi/toml/type_fields.go delete mode 100644 vendor/github.com/BurntSushi/toml/type_toml.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/.gitignore create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/BENCHMARKS.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/CONTRIBUTING.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/LICENSE.txt create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/README.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/address.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/animal.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/app.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/auth.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/beer.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/book.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/car.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/celebrity.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/color.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/company.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/csv.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/README.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/address.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/animals.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/beer.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/book.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/car.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/celebrity.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/colors.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/company.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/computer.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/currency.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/data.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/datetime.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/emoji.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/errors.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/files.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/food.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/hacker.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/hipster.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/html.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/internet.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/job.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/languages.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/log_level.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/lorem.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/minecraft.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/movie.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/payment.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/person.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/product.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/school.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/sentence.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/song.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/data/word.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/doc.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/emoji.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/error.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/fakeable.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/faker.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/file.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/finance.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/food.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/game.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/generate.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/hacker.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/helpers.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/hipster.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/html.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/image.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/internet.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/json.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/languages.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/logo.png create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/lookup.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/lorem.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/minecraft.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/misc.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/movie.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/number.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/payment.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/person.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/product.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/school.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/slice.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/song.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/source/BENCHMARKS.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/source/README.md create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/source/crypto.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/source/dumb.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/source/jsf.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/source/sfc.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/sql.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/string.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/struct.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/template.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/time.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/weighted.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_adjective.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_adverb.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_comment.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_connective.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_general.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_grammar.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_helper.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_misc.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_noun.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_phrase.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_preposition.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_pronoun.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_sentence.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/word_verb.go create mode 100644 vendor/github.com/brianvoe/gofakeit/v7/xml.go delete mode 100644 vendor/github.com/fjl/memsize/.travis.yml delete mode 100644 vendor/github.com/fjl/memsize/LICENSE delete mode 100644 vendor/github.com/fjl/memsize/bitmap.go delete mode 100644 vendor/github.com/fjl/memsize/doc.go delete mode 100644 vendor/github.com/fjl/memsize/mapiter_go12.go delete mode 100644 vendor/github.com/fjl/memsize/mapiter_old.go delete mode 100644 vendor/github.com/fjl/memsize/memsize.go delete mode 100644 vendor/github.com/fjl/memsize/memsizeui/template.go delete mode 100644 vendor/github.com/fjl/memsize/memsizeui/ui.go delete mode 100644 vendor/github.com/fjl/memsize/runtimefunc.go delete mode 100644 vendor/github.com/fjl/memsize/runtimefunc.s delete mode 100644 vendor/github.com/fjl/memsize/type.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/any.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/any/any.pb.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/doc.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/duration.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go delete mode 100644 vendor/github.com/okzk/sdnotify/LICENSE delete mode 100644 vendor/github.com/okzk/sdnotify/README.md delete mode 100644 vendor/github.com/okzk/sdnotify/notify.go delete mode 100644 vendor/github.com/okzk/sdnotify/notify_linux.go delete mode 100644 vendor/github.com/okzk/sdnotify/util.go delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/.gitignore delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile.vars delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/README.md delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/cb.nim delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/cfuncs.go delete mode 100644 vendor/github.com/siphiuel/lc-proxy-wrapper/proxy.go create mode 100644 vendor/github.com/status-im/extkeys/.golangci.yml delete mode 100644 vendor/github.com/status-im/migrate/v4/database/postgres/README.md delete mode 100644 vendor/github.com/status-im/migrate/v4/database/postgres/TUTORIAL.md delete mode 100644 vendor/github.com/status-im/migrate/v4/database/postgres/postgres.go rename vendor/golang.org/x/crypto/chacha20/{chacha_ppc64le.go => chacha_ppc64x.go} (89%) rename vendor/golang.org/x/crypto/chacha20/{chacha_ppc64le.s => chacha_ppc64x.s} (76%) rename vendor/golang.org/x/crypto/internal/poly1305/{sum_ppc64le.go => sum_ppc64x.go} (95%) rename vendor/golang.org/x/crypto/internal/poly1305/{sum_ppc64le.s => sum_ppc64x.s} (89%) delete mode 100644 vendor/golang.org/x/crypto/sha3/xor.go delete mode 100644 vendor/golang.org/x/crypto/ssh/terminal/terminal.go delete mode 100644 vendor/golang.org/x/image/AUTHORS delete mode 100644 vendor/golang.org/x/image/CONTRIBUTORS create mode 100644 vendor/golang.org/x/net/html/iter.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go rename vendor/golang.org/x/sys/cpu/{cpu_x86.s => cpu_gc_x86.s} (94%) create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go rename vendor/golang.org/x/{tools/internal/versions/constraint_go121.go => sys/cpu/cpu_other_x86.go} (50%) create mode 100644 vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go delete mode 100644 vendor/golang.org/x/sys/plan9/asm.s delete mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_386.s delete mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s delete mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_arm.s delete mode 100644 vendor/golang.org/x/sys/plan9/const_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/dir_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/env_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/errors_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/mkall.sh delete mode 100644 vendor/golang.org/x/sys/plan9/mkerrors.sh delete mode 100644 vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh delete mode 100644 vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/pwd_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/race.go delete mode 100644 vendor/golang.org/x/sys/plan9/race0.go delete mode 100644 vendor/golang.org/x/sys/plan9/str.go delete mode 100644 vendor/golang.org/x/sys/plan9/syscall.go delete mode 100644 vendor/golang.org/x/sys/plan9/syscall_plan9.go delete mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go delete mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go delete mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go delete mode 100644 vendor/golang.org/x/sys/plan9/zsysnum_plan9.go create mode 100644 vendor/golang.org/x/sys/unix/auxv.go create mode 100644 vendor/golang.org/x/sys/unix/auxv_unsupported.go create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_linux.go rename vendor/golang.org/x/{tools/internal/versions/toolchain_go119.go => sys/unix/vgetrandom_unsupported.go} (56%) delete mode 100644 vendor/golang.org/x/term/CONTRIBUTING.md delete mode 100644 vendor/golang.org/x/term/LICENSE delete mode 100644 vendor/golang.org/x/term/PATENTS delete mode 100644 vendor/golang.org/x/term/README.md delete mode 100644 vendor/golang.org/x/term/codereview.cfg delete mode 100644 vendor/golang.org/x/term/term.go delete mode 100644 vendor/golang.org/x/term/term_plan9.go delete mode 100644 vendor/golang.org/x/term/term_unix.go delete mode 100644 vendor/golang.org/x/term/term_unix_bsd.go delete mode 100644 vendor/golang.org/x/term/term_unix_other.go delete mode 100644 vendor/golang.org/x/term/term_unsupported.go delete mode 100644 vendor/golang.org/x/term/term_windows.go delete mode 100644 vendor/golang.org/x/term/terminal.go create mode 100644 vendor/golang.org/x/tools/cmd/goimports/gotypesalias.go create mode 100644 vendor/golang.org/x/tools/go/analysis/checker/checker.go rename vendor/golang.org/x/tools/{internal/versions/toolchain_go121.go => go/analysis/checker/iter_go122.go} (53%) rename vendor/golang.org/x/tools/{internal/versions/toolchain_go120.go => go/analysis/checker/iter_go123.go} (55%) create mode 100644 vendor/golang.org/x/tools/go/analysis/checker/print.go create mode 100644 vendor/golang.org/x/tools/go/analysis/internal/internal.go create mode 100644 vendor/golang.org/x/tools/go/ast/inspector/iter.go create mode 100644 vendor/golang.org/x/tools/go/ast/inspector/walk.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/callee.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/imports.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/map.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/ui.go delete mode 100644 vendor/golang.org/x/tools/internal/aliases/aliases_go121.go create mode 100644 vendor/golang.org/x/tools/internal/astutil/edge/edge.go create mode 100644 vendor/golang.org/x/tools/internal/diff/merge.go create mode 100644 vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go create mode 100644 vendor/golang.org/x/tools/internal/gcimporter/predeclared.go create mode 100644 vendor/golang.org/x/tools/internal/gcimporter/support.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/support_go118.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/unified_no.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/invoke_notunix.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/invoke_unix.go create mode 100644 vendor/golang.org/x/tools/internal/imports/source.go create mode 100644 vendor/golang.org/x/tools/internal/imports/source_env.go create mode 100644 vendor/golang.org/x/tools/internal/imports/source_modindex.go create mode 100644 vendor/golang.org/x/tools/internal/modindex/directories.go create mode 100644 vendor/golang.org/x/tools/internal/modindex/index.go create mode 100644 vendor/golang.org/x/tools/internal/modindex/lookup.go create mode 100644 vendor/golang.org/x/tools/internal/modindex/modindex.go create mode 100644 vendor/golang.org/x/tools/internal/modindex/symbols.go create mode 100644 vendor/golang.org/x/tools/internal/modindex/types.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go create mode 100644 vendor/golang.org/x/tools/internal/pkgbits/version.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/gopls_windows.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio_darwin.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio_flaky.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio_other.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio_plan9.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio_posix.go delete mode 100644 vendor/golang.org/x/tools/internal/robustio/robustio_windows.go delete mode 100644 vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/common.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/coretype.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/free.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/normalize.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/termlist.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeterm.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/element.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/qualifier.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/varkind.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/constraint.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/toolchain.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/types_go121.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/types_go122.go delete mode 100644 vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go delete mode 100644 vendor/google.golang.org/protobuf/types/known/durationpb/duration.pb.go delete mode 100644 waku/types/mailserver_test.go delete mode 100644 wakuv2/common/stats.go delete mode 100644 wakuv2/persistence/queries.go delete mode 100644 wakuv2/telemetry.go diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000000..7b2d9960a8 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,67 @@ +name: Go Lint +on: + pull_request: + branches: + - develop + - release/** + +permissions: + contents: read + +jobs: + golangci: + name: golangci-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Cache Go dependencies + uses: actions/cache@v4 + id: cache-go-deps + with: + path: ~/go/bin + key: go-deps-${{ runner.os }}-mockgen-v0.4.0-go-bindata-v4.0.2-protoc-gen-go-v1.34.1-gopls-latest + restore-keys: | + go-deps-${{ runner.os }}- + + - name: Install Go dependencies + if: steps.cache-go-deps.outputs.cache-hit != 'true' + run: | + go install go.uber.org/mock/mockgen@v0.4.0 + go install github.com/kevinburke/go-bindata/v4/...@v4.0.2 + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1 + go install golang.org/x/tools/gopls@latest + which gopls + + - name: Setup Protocol Buffer Compiler + uses: arduino/setup-protoc@v3 + with: + version: "29.3" + + - name: Cache go-generate-fast + uses: actions/cache@v4 + with: + path: ~/.cache/go-generate-fast + key: go-generate-fast-${{ runner.os }}-${{ hashFiles('**/*.go', '**/go.mod', '**/go.sum') }} + restore-keys: | + go-generate-fast-${{ runner.os }}- + + - name: Generate + env: + GO_GENERATE_FAST_DIR: ~/.cache/go-generate-fast + run: | + make generate + + - name: golangci-lint + uses: golangci/golangci-lint-action@v8 + with: + version: v2.3.1 + args: --build-tags=gowaku_no_rln + + - name: lint-panics + run: | + make lint-panics diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..8e17277261 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,63 @@ +# Build status-go in a Go builder container +FROM golang:1.23.10-bookworm AS builder + +# Set environment variables to use Clang +ENV CC=clang +ENV CXX=clang++ + +RUN apt-get update \ + && apt-get install -y git bash make llvm clang protobuf-compiler build-essential pkg-config \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +ARG build_tags='gowaku_no_rln' +ARG build_flags='' +ARG build_target='cmd' + +RUN mkdir -p /go/src/github.com/status-im/status-go +WORKDIR /go/src/github.com/status-im/status-go + +ADD go.mod go.sum ./ +RUN go mod download -x +RUN go install go.uber.org/mock/mockgen@v0.4.0 +RUN go install github.com/kevinburke/go-bindata/v4/...@v4.0.2 +RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1 + +ADD . . +ARG cache_id='local' +ARG enable_go_cache=true + +RUN if [ "$enable_go_cache" = "true" ]; then \ + go env -w GOCACHE=/root/.cache/go-build; \ + fi +RUN --mount=type=cache,target="/root/.cache/go-build",id=statusgo-build-$cache_id \ + --mount=type=cache,target="/root/.cache/go-generate-fast",id=statusgo-build-$cache_id \ + make $build_target BUILD_TAGS="$build_tags" BUILD_FLAGS="$build_flags" \ + GO_GENERATE_FAST_RECACHE=$([ "$enable_go_cache" = "true" ] && echo false || echo true) \ + GO_GENERATE_FAST_DIR="/root/.cache/go-generate-fast" + +# Copy binaries to the second image +FROM debian:bookworm-slim + +LABEL maintainer="support@status.im" +LABEL source="https://github.com/status-im/status-go" +LABEL description="status-go is an underlying part of Status - a browser, messenger, and gateway to a decentralized world." + +RUN apt-get update \ + && apt-get install -y ca-certificates bash curl \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /usr/status-user && chmod -R 777 /usr/status-user +RUN mkdir -p /static/keys +RUN mkdir -p /static/configs + +COPY --from=builder /go/src/github.com/status-im/status-go/build/bin/status-backend /usr/local/bin/ +COPY --from=builder /go/src/github.com/status-im/status-go/build/bin/push-notification-server /usr/local/bin/ +COPY --from=builder /go/src/github.com/status-im/status-go/static/keys/* /static/keys/ +COPY --from=builder /go/src/github.com/status-im/status-go/tests-functional/waku_configs/* /static/configs/ + +# 30304 is used for Discovery v5 +EXPOSE 8080 8545 30303 30303/udp 30304/udp +ENTRYPOINT ["status-backend"] +CMD ["--help"] \ No newline at end of file diff --git a/_assets/ci/Jenkinsfile.linux-nix b/_assets/ci/Jenkinsfile.linux-nix new file mode 120000 index 0000000000..abf56c852e --- /dev/null +++ b/_assets/ci/Jenkinsfile.linux-nix @@ -0,0 +1 @@ +Jenkinsfile.nix \ No newline at end of file diff --git a/_assets/ci/Jenkinsfile.macos-nix b/_assets/ci/Jenkinsfile.macos-nix new file mode 120000 index 0000000000..abf56c852e --- /dev/null +++ b/_assets/ci/Jenkinsfile.macos-nix @@ -0,0 +1 @@ +Jenkinsfile.nix \ No newline at end of file diff --git a/_assets/ci/Jenkinsfile.nix b/_assets/ci/Jenkinsfile.nix new file mode 100644 index 0000000000..c803bab6ec --- /dev/null +++ b/_assets/ci/Jenkinsfile.nix @@ -0,0 +1,48 @@ +#!/usr/bin/env groovy +// vim: ft=groovy +library 'status-jenkins-lib@v1.9.26' + +pipeline { + agent { label "${params.AGENT_LABEL} && nix-2.24" } + + parameters { + string( + name: 'AGENT_LABEL', + description: 'Label for targetted CI slave host.', + defaultValue: params.AGENT_LABEL ?: jenkins.getAgentLabelFromJob(), + ) + } + + options { + disableConcurrentBuilds() + disableRestartFromStage() + /* manage how many builds we keep */ + buildDiscarder(logRotator( + numToKeepStr: '20', + daysToKeepStr: '30', + )) + } + + stages { + stage('Build library') { + steps { + script { + nix.flake("status-go-library") + } + } + } + + stage('Build Android library') { + when { expression { env.NODE_LABELS?.contains('linux') } } + steps { + script { + nix.flake("status-go-mobile-android") + } + } + } + } + + post { + cleanup { cleanWs() } + } +} diff --git a/_assets/ci/Jenkinsfile.tests-benchmark b/_assets/ci/Jenkinsfile.tests-benchmark new file mode 100644 index 0000000000..9459ba8788 --- /dev/null +++ b/_assets/ci/Jenkinsfile.tests-benchmark @@ -0,0 +1,71 @@ +#!/usr/bin/env groovy +library 'status-jenkins-lib@v1.9.24' + +pipeline { + agent { label 'benchmark' } + + triggers { + // Nightly at 2am + cron 'H 2 * * *' + } + + parameters { + string( + name: 'BRANCH', + defaultValue: 'develop', + description: 'Name of branch to build.' + ) + } + + options { + timestamps() + /* Prevent Jenkins jobs from running forever */ + timeout(time: 50, unit: 'MINUTES') + disableConcurrentBuilds() + disableRestartFromStage() + /* manage how many builds we keep */ + buildDiscarder(logRotator( + numToKeepStr: '10', + daysToKeepStr: '30', + artifactNumToKeepStr: '1', + )) + } + + stages { + stage('Benchmark Tests') { + steps { + script { + nix.develop('make benchmark', pure: false) + } + } + } + stage('Push Results') { + steps { + sshagent(credentials: ['status-go-benchmarks-deploy-key']) { + sh './_assets/scripts/push_benchmark.sh' + } + } + } + } // stages + + post { + always { + script { + junit( + testResults: 'tests-functional/.results/reports/*.xml', + skipOldReports: true, + skipPublishingChecks: true, + skipMarkingBuildUnstable: true, + ) + } + } + cleanup { + script { + sh ''' + docker ps -a --filter "name=status-go-func-tests-${BUILD_ID}" -q | xargs -r docker rm -f + ''' + cleanWs(disableDeferredWipeout: true, deleteDirs: true) + } + } + } // post +} // pipeline \ No newline at end of file diff --git a/_assets/scripts/push_benchmark.sh b/_assets/scripts/push_benchmark.sh new file mode 100755 index 0000000000..985489d3ca --- /dev/null +++ b/_assets/scripts/push_benchmark.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -o nounset +set -o errexit +set -o pipefail + +REPO_URL="git@github.com:status-im/status-go-benchmarks.git" + +GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel) +source "${GIT_ROOT}/_assets/scripts/colors.sh" + +echo -e "${GRN}Pushing benchmark results${RST}" + +cd "${GIT_ROOT}" +# Get the commit SHA from the status-go repo BEFORE cloning bench-repo +commit_sha=$(git rev-parse --short HEAD) + +git clone "${REPO_URL}" benchmarks-repo +cd benchmarks-repo + +timestamp=$(date -u '+%Y%m%dT%H%M%S') +benchmark_dir="${timestamp}_${commit_sha}" + +echo -e "${GRN}Creating benchmark directory${RST}" +mkdir -p "benchmarks/${benchmark_dir}" + +echo -e "${GRN}Copying benchmark results${RST}" +cp -r "${GIT_ROOT}/tests-functional/.results/benchmarks"/* "benchmarks/${benchmark_dir}/" + +echo -e "${GRN}Creating virtual environment${RST}" +python3 -m venv .venv +source .venv/bin/activate + +echo -e "${GRN}Installing dependencies${RST}" +pip install --upgrade pip +pip install -r requirements.txt + +echo -e "${GRN}Updating README${RST}" +python ./scripts/update_readme.py + +echo -e "${GRN}Committing changes${RST}" +git add . +git commit -m "Add benchmark results ${benchmark_dir}" + +echo -e "${GRN}Pushing changes${RST}" +git push "${REPO_URL}" + +echo -e "${GRN}Push finished${RST}" diff --git a/_assets/scripts/run_benchmark.sh b/_assets/scripts/run_benchmark.sh new file mode 100755 index 0000000000..f574d46d47 --- /dev/null +++ b/_assets/scripts/run_benchmark.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +set -o nounset + +GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel) +source "${GIT_ROOT}/_assets/scripts/colors.sh" + +echo -e "${GRN}Running benchmark${RST}" + +root_path="${GIT_ROOT}/tests-functional" +test_results_path="${root_path}/.results/reports" +benchmark_results_path="${root_path}/.results/benchmarks" + +rm -rf "${test_results_path}" +rm -rf "${benchmark_results_path}" + +mkdir -p "${test_results_path}" +mkdir -p "${benchmark_results_path}" +# Create coverage directory as jenkins user +mkdir -p "${GIT_ROOT}/coverage/binary" + +all_compose_files="-f ${root_path}/docker-compose.anvil.yml -f ${root_path}/docker-compose.waku.yml" +identifier=${BUILD_ID:-$(git rev-parse --short HEAD)} +project_name="status-go-func-tests-${identifier}" +image_name="statusgo-${identifier}" + +# Remove orphans +echo -e "${GRN}Cleanup old containers${RST}" +docker ps -a --filter "name=status-go-func-tests-${identifier}" --filter "status=exited" -q | xargs -r docker rm -f + +# Build statusgo image +echo -e "${GRN}Building status-go${RST}" +docker build . \ + --build-arg "enable_go_cache=false" \ + --tag "${image_name}" + +# Run docker +echo -e "${GRN}Running status-go external dependencies${RST}" +docker compose -p ${project_name} ${all_compose_files} up -d --build --remove-orphans + +# Set up virtual environment +venv_path="${root_path}/.venv" + +if [[ -d "${venv_path}" ]]; then + echo -e "${GRN}Using existing virtual environment${RST}" +else + echo -e "${GRN}Creating new virtual environment${RST}" + python3 -m venv "${venv_path}" +fi + +source "${venv_path}/bin/activate" + +# Upgrade pip and install requirements +echo -e "${GRN}Installing dependencies${RST}" +pip install --upgrade pip +pip install -r "${root_path}/requirements.txt" + +# Run functional tests +echo -e "${GRN}Running benchmark${RST}, HEAD: $(git rev-parse HEAD)" +pytest \ + -m benchmark \ + -c "${root_path}/pytest.ini" \ + --log-cli-level="INFO" \ + --docker_project_name="${project_name}" \ + --docker-image="${image_name}" \ + --benchmark-results-dir="${benchmark_results_path}" \ + --junitxml="${test_results_path}/report.xml" +exit_code=$? + +# Stop containers +echo -e "${GRN}Stopping docker containers${RST}" +docker compose -p ${project_name} ${all_compose_files} stop + +# Cleanup containers +echo -e "${GRN}Removing docker containers${RST}" +docker compose -p ${project_name} ${all_compose_files} down + +echo -e "${GRN}Testing finished${RST}" +exit $exit_code diff --git a/accounts-management/README.md b/accounts-management/README.md new file mode 100644 index 0000000000..0e058e6e38 --- /dev/null +++ b/accounts-management/README.md @@ -0,0 +1,426 @@ +# Accounts Management Package + +The Accounts Management package provides a comprehensive solution for Status chat and wallet accounts creation, storage, and management within the Status application. It handles account generation, keystore operations, and secure storage of private keys. For cryptographic operations, see the separate `crypto` package. + +## Package Structure + +The package is organized into focused subpackages: + +``` +accounts-management/ +├── accounts.go # Main package with public API and re-exports +├── core/ # Main account manager implementation +│ ├── manager.go # AccountsManager and core business logic +│ ├── keystore_operations.go # Keystore-related operations +│ ├── persistence_operations.go # Database operations +│ └── manager_test.go # Test suite for core functionality + +├── errors/ # Structured error handling system +│ ├── errors.go # Error definitions, codes, and categories +│ ├── errors_test.go # Error system tests +│ ├── errors_test_data.go # Test data for error tests +│ └── README.md # Error handling documentation +├── keystore/ # Cryptographic key storage operations +│ ├── interface.go # KeyStore interface definition +│ └── geth/ # Geth-compatible keystore implementation +│ ├── adapter.go # Geth keystore adapter +│ ├── encryption.go # Encryption operations +│ ├── decryption.go # Decryption operations +│ ├── reencryption.go # Re-encryption operations +│ ├── migration.go # Migration utilities +│ ├── helper.go # Helper functions +│ └── const.go # Constants +├── persistence/ # Database operations for account data +│ └── interface.go # Persistence interface definition +├── generator/ # Account creation and derivation +│ ├── generator.go # Account generation functions +│ ├── types.go # Account types and methods +│ ├── path_decoder.go # BIP32 path parsing +│ ├── README.md # Generator-specific documentation +│ └── *_test.go # Generator tests +├── types/ # Core type definitions +│ ├── types.go # Core type definitions +│ ├── key.go # Key type structure +│ ├── account.go # Account-related types +│ ├── keypair.go # Keypair-related types +│ └── *_test.go # Type tests +├── common/ # Shared utilities +│ ├── const.go # Constants and paths +│ ├── mnemonic.go # Mnemonic generation utilities +│ ├── address.go # Address utilities +│ ├── publickey.go # Public key utilities +│ ├── utils.go # General utilities +│ └── *_test.go # Common tests +└── mock/ # Mock implementations for testing + └── persistence.go # Mock persistence implementation +``` + +## Key Components + +### Core Package + +The main account management operations are in the `core` package: + +- **AccountsManager**: Main interface for account management operations including account creation, selection, and verification +- **Keystore Operations**: Methods for keystore management and account loading +- **Persistence Operations**: Methods for database operations including keypair and account management + +### Errors Package + +A structured error handling system in the `errors` package: + +- **Structured Errors**: Rich error types with codes, categories, and context +- **Error Codes**: Numeric error codes for programmatic error handling +- **Error Categories**: Logical grouping for different error types +- **Context Support**: Add key-value metadata to errors for debugging +- **Helper Functions**: Pre-built error creation functions for common patterns + +### Keystore Package + +Handles secure cryptographic key storage: + +- **KeyStore Interface**: Defines the contract for keystore implementations +- **Geth Implementation**: Complete Geth-compatible keystore adapter with encryption, decryption, re-encryption, and migration capabilities + +### Persistence Package + +Manages account data storage: + +- **Persistence Interface**: Defines the contract for data persistence operations including keypair, account, and keycard management +- **Database Operations**: Account, keypair, and keycard management with comprehensive CRUD operations + +### Generator Package + +Account creation and derivation logic: + +- **Account Creation**: From mnemonics, private keys, and extended keys +- **Account Derivation**: BIP32/BIP44 path-based derivation with support for single and multiple derivations +- **Path Decoding**: BIP32 path parsing and validation +- **Batch Operations**: Support for creating multiple accounts from a single mnemonic + +### Types Package + +Core data structures: + +- **Account**: Represents an Ethereum account with address, keyUID, wallet/chat flags, and metadata +- **Keypair**: Represents a collection of related accounts with type, derivation info, and keycard support +- **Keycard**: Represents a hardware keycard with associated accounts +- **KeystoreAccount**: Represents a keystore entry with address and URL +- **AccountCreationDetails**: Contains account creation information including path and name +- **AccountType/KeypairType**: Type enumerations for accounts and keypairs +- **AccountOperable**: Enumeration for account operability status (fully, partially, non-operable) + + + +### Common Package + +Shared utilities and constants: + +- **Constants**: BIP32/BIP44 path constants and other shared constants +- **Mnemonic Utilities**: Mnemonic generation and validation +- **Address Utilities**: Address validation and formatting +- **Public Key Utilities**: Public key operations and conversions +- **General Utilities**: Common helper functions + +## Usage + +### Basic Usage + +```go +package main + +import ( + "log" + + "github.com/status-im/status-go/accounts-management" + "go.uber.org/zap" +) + +func main() { + // Initialize logger + logger, _ := zap.NewDevelopment() + + // Create account manager + manager, err := accountsmanagement.NewAccountsManager(logger) + if err != nil { + log.Fatal(err) + } + + // Set up persistence and root data directory + persistence := yourPersistenceImplementation() + manager.SetPersistence(persistence) + + // Set the root data directory for keystore management + manager.SetRootDataDir("/path/to/root/data/dir") + + // Create a new keypair from mnemonic + walletAccount := &types.AccountCreationDetails{ + Path: "m/44'/60'/0'/0/0", + Name: "Wallet Account", + } + + keypair, err := manager.CreateKeypairFromMnemonicAndStore( + mnemonic, + "my-password", + "My Keypair", + walletAccount, + true, // profile keypair + false, // not keycard + 0, // clock + ) + if err != nil { + log.Fatal(err) + } + + log.Printf("Created keypair: %s", keypair.Name) + log.Printf("Keypair UID: %s", keypair.KeyUID) + + // Select the account (this will also switch the keystore internally) + err = manager.SetChatAccount(account.Address(), "my-password", nil) + if err != nil { + log.Fatal(err) + } + + // Get selected account + selectedAccount, err := manager.SelectedChatAccount() + if err != nil { + log.Fatal(err) + } + + log.Printf("Selected account: %s", selectedAccount.Address().Hex()) +} +``` + +### Advanced Usage + +For more advanced usage, you can import specific subpackages: + +```go +import ( + "github.com/status-im/status-go/accounts-management/core" + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/accounts-management/types" + "github.com/status-im/status-go/accounts-management/errors" +) + +// Use specific types and functions +account := generator.CreateAccountFromMnemonic(mnemonic, passphrase) +keypair := &types.Keypair{...} + +// Use structured error handling +if err != nil { + var accountsErr *errors.AccountsError + if errors.As(err, &accountsErr) { + switch accountsErr.Category { + case errors.ErrorCategoryAccount: + log.Printf("Account error: %s", accountsErr.Message) + case errors.ErrorCategoryValidation: + log.Printf("Validation error: %s", accountsErr.Message) + } + } +} + +// Use account management functions +account := generator.CreateAccountFromMnemonic(mnemonic, passphrase) +keypair := &types.Keypair{...} +``` + + + +### Error Handling + +The errors package provides a structured error handling system: + +```go +import "github.com/status-im/status-go/accounts-management/errors" + +// Create structured errors +err := errors.NewError(errors.ErrCodeLoggerMissing, "logger is missing", errors.getErrorCategory) + +// Add context to errors +err = err.WithContext("function", "LoadAccount") + +// Wrap existing errors +wrappedErr := errors.WrapError(errors.ErrCodeWrongPasswordProvided, "wrong password", originalErr, errors.getErrorCategory) + +// Use helper functions +func ErrDerivingAddress(keyUID string, path string) *AccountsError { + return NewError(ErrCodeErrorDerivingAddress, "error deriving address from keypair", getErrorCategory). + WithContext("keyuid", keyUID). + WithContext("path", path) +} + +err := errors.ErrDerivingAddress("0x123", "m/1'") +``` + +### Account Generation + +The generator package provides flexible account creation: + +```go +import "github.com/status-im/status-go/accounts-management/generator" + +// Create account from mnemonic +account := generator.CreateAccountFromMnemonic(mnemonic, passphrase) + +// Create account from private key +account := generator.CreateAccountFromPrivateKey(privateKeyHex) + +// Derive child account +childAccount := generator.DeriveChildFromAccount(account, "m/44'/60'/0'/0/1") + +// Create multiple accounts +accounts, mnemonics := generator.CreateAccountsOfMnemonicLength(12, 5, passphrase) +``` + +### Keypair Creation + +The main package provides keypair creation methods: + +```go +// Create keypair from mnemonic +walletAccount := &types.AccountCreationDetails{ + Path: "m/44'/60'/0'/0/0", + Name: "Wallet Account", +} +keypair, err := manager.CreateKeypairFromMnemonicAndStore( + mnemonic, + password, + "My Keypair", + walletAccount, + true, // profile keypair + false, // not keycard + clock, +) + +// Create keypair from private key +keypair, err := manager.CreateKeypairFromPrivateKeyAndStore( + privateKeyHex, + password, + "Private Key Keypair", + walletAccount, + clock, +) +``` + +## Main Types and Interfaces + +### AccountsManager + +The main interface for account management: + +```go +type AccountsManager struct { + // Core account management operations + CreateKeypairFromMnemonicAndStore(mnemonic string, password string, keypairName string, walletAccount *types.AccountCreationDetails, profile bool, keycard bool, clock uint64) (*types.Keypair, error) + CreateKeypairFromPrivateKeyAndStore(privateKey string, password string, keypairName string, walletAccount *types.AccountCreationDetails, clock uint64) (*types.Keypair, error) + SetChatAccount(address ethtypes.Address, password string, privateKey *ecdsa.PrivateKey) error + SelectedChatAccount() (*generator.Account, error) + LoadAccount(address ethtypes.Address, password string) (*generator.Account, error) + VerifyAccountPassword(address ethtypes.Address, password string) (bool, error) + GetVerifiedWalletAccount(address ethtypes.Address, password string) (*generator.Account, error) + Logout() + Accounts() ([]ethtypes.Address, error) +} +``` + + + +### KeyStore Interface + +Defines keystore operations: + +```go +type KeyStore interface { + AccountDecryptedKey(address types.Address, password string) (types.KeystoreAccount, *ecdsa.PrivateKey, *extkeys.ExtendedKey, error) + ImportECDSA(priv *ecdsa.PrivateKey, password string) (types.KeystoreAccount, error) + // ... other keystore operations +} +``` + +### Persistence Interface + +Defines data persistence operations: + +```go +type Persistence interface { + AddressExists(address ethtypes.Address) (bool, error) + GetProfileKeypair() (*types.Keypair, error) + GetWalletRootAddress() (ethtypes.Address, error) + GetPath(address ethtypes.Address) (string, error) + GetKeypairByKeyUID(keyUID string) (*types.Keypair, error) + GetActiveKeypairs() ([]*types.Keypair, error) + SaveOrUpdateKeypair(keypair *types.Keypair) error + SaveOrUpdateAccounts(accounts []*types.Account, updateKeypairClock bool) error + SaveOrUpdateKeycard(keycard *types.Keycard, clock uint64, updateKeypairClock bool) error + MarkKeypairFullyOperable(keyUID string, clock uint64, updateKeypairClock bool) error + MarkAccountFullyOperable(address ethtypes.Address) error + DeleteAllKeycardsWithKeyUID(keyUID string, clock uint64) error + GetPositionForNextNewAccount() (int64, error) + GetAccountByAddress(address ethtypes.Address) (*types.Account, error) + RemoveAccount(address ethtypes.Address, clock uint64) error + RemoveKeypair(keyUID string, clock uint64) error +} +``` + +## Account Types and Operability + +The package defines different account types and operability levels: + +### Account Types +- **Generated**: Account created from mnemonic +- **Key**: Account created from private key +- **Seed**: Account derived from seed +- **Watch**: Watch-only account + +### Keypair Types +- **Profile**: Keypair used for chat profile +- **Key**: Keypair created from private key +- **Seed**: Keypair created from seed/mnemonic + +### Account Operability +- **Fully Operable**: Account has keystore file and can sign transactions +- **Partially Operable**: Account has keystore file for derived address but not for itself +- **Non-Operable**: Account has no keystore file and cannot sign transactions + +## Error Handling + +The package provides comprehensive error handling with specific error types: + +```go +var ( + ErrLoggerIsMissing = core.ErrLoggerIsMissing + ErrAccountKeyStoreMissing = core.ErrAccountKeyStoreMissing + ErrNoAccountSelected = core.ErrNoAccountSelected + ErrPersistenceIsMissing = core.ErrPersistenceIsMissing + ErrAccountDoesNotExist = core.ErrAccountDoesNotExist + ErrAddressAndPasswordOrPrivateKeyRequired = core.ErrAddressAndPasswordOrPrivateKeyRequired + ErrAccountIsNil = core.ErrAccountIsNil + ErrKeypairIsNil = core.ErrKeypairIsNil + ErrCannotRemoveChatAccount = core.ErrCannotRemoveChatAccount + ErrCannotRemoveDefaultWalletAccount = core.ErrCannotRemoveDefaultWalletAccount + ErrCannotRemoveProfileKeypair = core.ErrCannotRemoveProfileKeypair +) +``` + +## Testing + +The package includes comprehensive test coverage: + +- **Unit Tests**: Each subpackage includes its own test suite +- **Mock Implementations**: Mock persistence and keystore implementations for testing +- **Integration Tests**: End-to-end testing of account management workflows + +## Contributing + +When contributing to this package: + +1. Ensure all new functionality includes appropriate tests +2. Follow the existing code style and patterns +3. Update documentation for any new public APIs +4. Consider security implications of any changes +5. Test keystore compatibility with existing accounts +6. Place new code in the appropriate subpackage based on its responsibility +7. Maintain backward compatibility for the main package exports +8. Use the mock implementations for testing new functionality +9. Use interfaces for external dependencies \ No newline at end of file diff --git a/accounts-management/accounts.go b/accounts-management/accounts.go new file mode 100644 index 0000000000..ab736399c1 --- /dev/null +++ b/accounts-management/accounts.go @@ -0,0 +1,49 @@ +// Package accounts provides account management functionality. +// It is split into subpackages: +// - core: main account manager implementation +// - errors: structured error handling system +// - keystore: cryptographic key storage operations +// - persistence: database operations for key pairs and accounts +// - generator: account creation and derivation +// - types: type definitions +// - common: shared utilities +package accountsmanagement + +import ( + "github.com/status-im/status-go/accounts-management/core" + "github.com/status-im/status-go/accounts-management/keystore" + keystoretypes "github.com/status-im/status-go/accounts-management/keystore/types" + "github.com/status-im/status-go/accounts-management/persistence" + "github.com/status-im/status-go/accounts-management/types" + + "go.uber.org/zap" +) + +// Re-export main types and interfaces for backward compatibility +type AccountsManager = core.AccountsManager +type KeyStore = keystore.KeyStore +type Persistence = persistence.Persistence + +// Re-export errors for convenience +var ( + ErrNoAccountSelected = core.ErrNoAccountSelected + ErrKeystoreFileMissing = core.ErrKeystoreFileMissing + ErrAccountDoesNotExist = core.ErrAccountDoesNotExist +) + +// NewAccountsManager creates a new accounts manager instance +func NewAccountsManager(logger *zap.Logger) (*AccountsManager, error) { + return core.NewAccountsManager(logger) +} + +// Re-export types for convenience +type ( + Account = types.Account + Keypair = types.Keypair + Keycard = types.Keycard + KeystoreAccount = keystoretypes.KeystoreAccount + AccountCreationDetails = types.AccountCreationDetails + KeypairType = types.KeypairType + AccountType = types.AccountType + AccountOperable = types.AccountOperable +) diff --git a/accounts-management/common/address.go b/accounts-management/common/address.go new file mode 100644 index 0000000000..5b4b34d511 --- /dev/null +++ b/accounts-management/common/address.go @@ -0,0 +1,23 @@ +package common + +import ( + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" +) + +func CreateAddress() (address, pubKey, privKey string, err error) { + key, err := crypto.GenerateKey() + if err != nil { + return "", "", "", err + } + + privKeyBytes := crypto.FromECDSA(key) + pubKeyBytes := crypto.FromECDSAPub(&key.PublicKey) + addressBytes := crypto.PubkeyToAddress(key.PublicKey) + + privKey = types.EncodeHex(privKeyBytes) + pubKey = types.EncodeHex(pubKeyBytes) + address = addressBytes.Hex() + + return +} diff --git a/accounts-management/common/address_test.go b/accounts-management/common/address_test.go new file mode 100644 index 0000000000..24ac44445d --- /dev/null +++ b/accounts-management/common/address_test.go @@ -0,0 +1,24 @@ +package common + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" +) + +func TestCreateAddress(t *testing.T) { + addr, pub, priv, err := CreateAddress() + require.NoError(t, err) + require.Equal(t, types.IsHexAddress(addr), true) + + privECDSA, err := crypto.HexToECDSA(priv[2:]) + require.NoError(t, err) + + pubECDSA := privECDSA.PublicKey + expectedPubStr := types.EncodeHex(crypto.FromECDSAPub(&pubECDSA)) + + require.Equal(t, expectedPubStr, pub) +} diff --git a/accounts-management/common/const.go b/accounts-management/common/const.go new file mode 100644 index 0000000000..28894aeeb2 --- /dev/null +++ b/accounts-management/common/const.go @@ -0,0 +1,15 @@ +package common + +const WalletAccountDefaultName = "Account 1" + +const PathMaster = "m" + +const PathEIP1581Root = "m/43'/60'/1581'" +const PathEIP1581Chat = PathEIP1581Root + "/0'/0" +const PathEIP1581Encryption = PathEIP1581Root + "/1'/0" + +const WalletPath = "m/44'" +const PathWalletRoot = "m/44'/60'/0'/0" +const PathDefaultWalletAccount = PathWalletRoot + "/0" +const CustomWalletPath1 = PathWalletRoot + "/1" +const CustomWalletPath2 = PathWalletRoot + "/2" diff --git a/accounts-management/common/mnemonic.go b/accounts-management/common/mnemonic.go new file mode 100644 index 0000000000..55ad49a28e --- /dev/null +++ b/accounts-management/common/mnemonic.go @@ -0,0 +1,52 @@ +package common + +import ( + "errors" + "fmt" + + "github.com/status-im/extkeys" +) + +var ( + ErrInvalidMnemonicPhraseLength = errors.New("invalid mnemonic phrase length; valid lengths are 12, 15, 18, 21, and 24") +) + +// CreateRandomMnemonic generates a random mnemonic phrase with the specified length +func CreateRandomMnemonic(length int) (string, error) { + entropyStrength, err := LengthToEntropyStrength(length) + if err != nil { + return "", err + } + + mnemonic := extkeys.NewMnemonic() + return mnemonic.MnemonicPhrase(entropyStrength, extkeys.EnglishLanguage) +} + +// CreateRandomMnemonicWithDefaultLength generates a random mnemonic phrase with default length (12 words) +func CreateRandomMnemonicWithDefaultLength() (string, error) { + const defaultLength = 12 + return CreateRandomMnemonic(defaultLength) +} + +// CreateExtendedKeyFromMnemonic creates an extended key from a mnemonic phrase +func CreateExtendedKeyFromMnemonic(phrase, passphrase string) (*extkeys.ExtendedKey, error) { + mnemonic := extkeys.NewMnemonic() + seed := mnemonic.MnemonicSeed(phrase, passphrase) + masterKey, err := extkeys.NewMaster(seed) + if err != nil { + return nil, fmt.Errorf("failed to create master key: %w", err) + } + return masterKey, nil +} + +// LengthToEntropyStrength converts a mnemonic phrase length to its corresponding entropy strength +func LengthToEntropyStrength(length int) (extkeys.EntropyStrength, error) { + if length < 12 || length > 24 || length%3 != 0 { + return 0, ErrInvalidMnemonicPhraseLength + } + + bitsLength := length * 11 + checksumLength := bitsLength % 32 + + return extkeys.EntropyStrength(bitsLength - checksumLength), nil +} diff --git a/accounts-management/common/mnemonic_test.go b/accounts-management/common/mnemonic_test.go new file mode 100644 index 0000000000..c0e17a0724 --- /dev/null +++ b/accounts-management/common/mnemonic_test.go @@ -0,0 +1,118 @@ +package common + +import ( + "testing" + + "github.com/status-im/extkeys" + "github.com/stretchr/testify/assert" +) + +func TestCreateRandomMnemonic(t *testing.T) { + + tests := []struct { + name string + length int + expectError bool + }{ + {"valid length 12", 12, false}, + {"valid length 15", 15, false}, + {"valid length 18", 18, false}, + {"valid length 21", 21, false}, + {"valid length 24", 24, false}, + {"invalid length 11", 11, true}, + {"invalid length 13", 13, true}, + {"invalid length 25", 25, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mnemonic, err := CreateRandomMnemonic(tt.length) + if tt.expectError { + assert.Error(t, err) + assert.Equal(t, ErrInvalidMnemonicPhraseLength, err) + assert.Empty(t, mnemonic) + } else { + assert.NoError(t, err) + assert.NotEmpty(t, mnemonic) + } + }) + } +} + +func TestCreateRandomMnemonicWithDefaultLength(t *testing.T) { + mnemonic, err := CreateRandomMnemonicWithDefaultLength() + assert.NoError(t, err) + assert.NotEmpty(t, mnemonic) +} + +func TestCreateExtendedKeyFromMnemonic(t *testing.T) { + tests := []struct { + name string + phrase string + passphrase string + expectError bool + }{ + { + name: "valid mnemonic", + phrase: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + passphrase: "", + expectError: false, + }, + { + name: "invalid mnemonic", + phrase: "invalid mnemonic phrase", + passphrase: "", + expectError: false, + }, + { + name: "empty mnemonic", + phrase: "", + passphrase: "", + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + key, err := CreateExtendedKeyFromMnemonic(tt.phrase, tt.passphrase) + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, key) + } else { + assert.NoError(t, err) + assert.NotNil(t, key) + } + }) + } +} + +func TestLengthToEntropyStrength(t *testing.T) { + tests := []struct { + name string + length int + expectError bool + }{ + {"valid length 12", 12, false}, + {"valid length 15", 15, false}, + {"valid length 18", 18, false}, + {"valid length 21", 21, false}, + {"valid length 24", 24, false}, + {"invalid length 11", 11, true}, + {"invalid length 13", 13, true}, + {"invalid length 25", 25, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + strength, err := LengthToEntropyStrength(tt.length) + if tt.expectError { + assert.Error(t, err) + assert.Equal(t, ErrInvalidMnemonicPhraseLength, err) + assert.Equal(t, extkeys.EntropyStrength(0), strength) + } else { + assert.NoError(t, err) + assert.NotZero(t, strength) + } + }) + } +} diff --git a/accounts-management/common/publickey.go b/accounts-management/common/publickey.go new file mode 100644 index 0000000000..0aff56c9ed --- /dev/null +++ b/accounts-management/common/publickey.go @@ -0,0 +1,66 @@ +package common + +import ( + "reflect" + + "github.com/status-im/status-go/accounts-management/types" + "github.com/status-im/status-go/api/multiformat" + "github.com/status-im/status-go/protocol/identity/emojihash" +) + +// GetPublicKeyData processes a public key and returns its compressed form and emoji hash +func GetPublicKeyData(publicKey string) (*types.PublicKeyData, error) { + if publicKey == "" { + return nil, nil + } + + compressedKey, err := multiformat.SerializeLegacyKey(publicKey) + if err != nil { + return nil, err + } + + emojiHash, err := emojihash.GenerateFor(publicKey) + if err != nil { + return nil, err + } + + return &types.PublicKeyData{ + CompressedKey: compressedKey, + EmojiHash: emojiHash, + }, nil +} + +func ExtendStructWithPubKeyData(publicKey string, item any) (any, error) { + // If the public key is empty, do not attempt to extend the incoming item + if publicKey == "" { + return item, nil + } + + pkd, err := GetPublicKeyData(publicKey) + if err != nil { + return nil, err + } + + // Create a struct with 2 embedded substruct fields in order to circumvent + // "embedded field type cannot be a (pointer to a) type parameter" + // compiler error that arises if we were to use a generic function instead + typ := reflect.StructOf([]reflect.StructField{ + { + Name: "Item", + Anonymous: true, + Type: reflect.TypeOf(item), + }, + { + Name: "Pkd", + Anonymous: true, + Type: reflect.TypeOf(pkd), + }, + }) + + v := reflect.New(typ).Elem() + v.Field(0).Set(reflect.ValueOf(item)) + v.Field(1).Set(reflect.ValueOf(pkd)) + s := v.Addr().Interface() + + return s, nil +} diff --git a/accounts-management/common/publickey_test.go b/accounts-management/common/publickey_test.go new file mode 100644 index 0000000000..321eb0dfb0 --- /dev/null +++ b/accounts-management/common/publickey_test.go @@ -0,0 +1,84 @@ +package common + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetPublicKeyData(t *testing.T) { + tests := []struct { + name string + publicKey string + expectError bool + }{ + { + name: "valid public key", + publicKey: "0x0498593ff6c560f5dad6e947cd9c8aa41d687126fa253eb5d917f1f5911519c570651268c40f818b98ec18b00d2b59e16075a162f1bba6b568b753444b4c5a6a79", + expectError: false, + }, + { + name: "empty public key", + publicKey: "", + expectError: false, + }, + { + name: "invalid public key", + publicKey: "invalid", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := GetPublicKeyData(tt.publicKey) + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, data) + } else if tt.publicKey == "" { + assert.NoError(t, err) + assert.Nil(t, data) + } else { + assert.NoError(t, err) + assert.NotNil(t, data) + assert.NotEmpty(t, data.CompressedKey) + assert.NotEmpty(t, data.EmojiHash) + } + }) + } +} + +func TestExtendStructWithPubKeyData(t *testing.T) { + tests := []struct { + name string + publicKey string + item any + expectError bool + }{ + { + name: "valid public key", + publicKey: "0x0498593ff6c560f5dad6e947cd9c8aa41d687126fa253eb5d917f1f5911519c570651268c40f818b98ec18b00d2b59e16075a162f1bba6b568b753444b4c5a6a79", + item: struct { + ID string `json:"id"` + }{ + ID: "1234", + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fmt.Printf("item: %+v\n", tt.item) + fmt.Printf("publicKey: %s\n", tt.publicKey) + + item, err := ExtendStructWithPubKeyData(tt.publicKey, tt.item) + fmt.Printf("item: %+v\n", item) + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, item) + } + }) + } +} diff --git a/accounts-management/common/utils.go b/accounts-management/common/utils.go new file mode 100644 index 0000000000..ddc67f4836 --- /dev/null +++ b/accounts-management/common/utils.go @@ -0,0 +1,12 @@ +package common + +import ( + "github.com/status-im/status-go/accounts-management/keystore/geth" + "github.com/status-im/status-go/accounts-management/types" +) + +// This function is exposed from here just to be used for validating transferred keystore files while local pairing. +// The rest of the code should use the keystore package, via KeyStore interface. +func DecryptKey(keyjson []byte, auth string) (*types.Key, error) { + return geth.DecryptKey(keyjson, auth) +} diff --git a/accounts-management/core/errors.go b/accounts-management/core/errors.go new file mode 100644 index 0000000000..feff3f1e92 --- /dev/null +++ b/accounts-management/core/errors.go @@ -0,0 +1,104 @@ +package core + +import "github.com/status-im/status-go/accounts-management/errors" + +const ( + ErrorCategorySystem errors.ErrorCategory = "system" + ErrorCategoryAccount errors.ErrorCategory = "account" + ErrorCategoryKeystore errors.ErrorCategory = "keystore" + ErrorCategoryValidation errors.ErrorCategory = "validation" + ErrorCategoryDatabase errors.ErrorCategory = "database" +) + +const ( + ErrCodeLoggerMissing errors.ErrorCode = iota + 1 + ErrCodeKeystoreMissing + ErrCodePersistenceMissing + ErrCodeAccountIsNil + ErrCodeKeypairIsNil + ErrCodeKeystoreFileMissing + ErrCodeAccountMismatch + ErrCodeAddressAndPasswordOrPrivateKeyRequired + ErrCodeNoAccountSelected + ErrCodeAccountDoesNotExist + ErrCodeKeystoreDirectoryError + ErrCodeKeypairDoesNotHaveWalletAccount + ErrCodeUnsupportedWalletAccountPath + ErrCodeKeypairAlreadyAdded + ErrCodeAccountAlreadyAdded + ErrCodeChatAccountNotFoundInDerivedAccounts + ErrCodeKeypairMustHaveAtLeastOneWalletAccount + ErrCodeCannotAddAccountsToKeypairImportedViaPrivateKey + ErrCodeCannotAddDefaultWalletAccount + ErrCodeCannotRemoveDefaultWalletAccount + ErrCodeCannotAddDefaultChatAccount + ErrCodeCannotRemoveDefaultChatAccount + ErrCodeCannotMigrateProfileKeypair + ErrCodeKeypairIsNotKeycard + ErrCodeWrongPasswordProvided + ErrCodeKeycardDoesNotHaveAnyAccounts + ErrCodeKeycardDoesNotRelateToAnyKeypair + ErrCodeCannotRemoveProfileKeypair +) + +var ( + ErrLoggerIsMissing = errors.NewError(ErrCodeLoggerMissing, "logger is missing", getErrorCategory) + ErrKeystoreMissing = errors.NewError(ErrCodeKeystoreMissing, "keystore is missing", getErrorCategory) + ErrPersistenceMissing = errors.NewError(ErrCodePersistenceMissing, "persistence is missing", getErrorCategory) + ErrAccountIsNil = errors.NewError(ErrCodeAccountIsNil, "account is nil", getErrorCategory) + ErrKeypairIsNil = errors.NewError(ErrCodeKeypairIsNil, "keypair is nil", getErrorCategory) + ErrKeystoreFileMissing = errors.NewError(ErrCodeKeystoreFileMissing, "keystore file is missing", getErrorCategory) + ErrAccountMismatch = errors.NewError(ErrCodeAccountMismatch, "account mismatch", getErrorCategory) + ErrAddressAndPasswordOrPrivateKeyRequired = errors.NewError(ErrCodeAddressAndPasswordOrPrivateKeyRequired, "address and password or private key are required", getErrorCategory) + ErrNoAccountSelected = errors.NewError(ErrCodeNoAccountSelected, "no account selected", getErrorCategory) + ErrAccountDoesNotExist = errors.NewError(ErrCodeAccountDoesNotExist, "account does not exist", getErrorCategory) + ErrKeypairDoesNotHaveWalletAccount = errors.NewError(ErrCodeKeypairDoesNotHaveWalletAccount, "keypair does not have wallet account", getErrorCategory) + ErrUnsupportedWalletAccountPath = errors.NewError(ErrCodeUnsupportedWalletAccountPath, "unsupported profile or seed imported key pair wallet account", getErrorCategory) + ErrKeypairAlreadyAdded = errors.NewError(ErrCodeKeypairAlreadyAdded, "keypair already added", getErrorCategory) + ErrAccountAlreadyAdded = errors.NewError(ErrCodeAccountAlreadyAdded, "account already added", getErrorCategory) + ErrChatAccountNotFoundInDerivedAccounts = errors.NewError(ErrCodeChatAccountNotFoundInDerivedAccounts, "chat account not found in derived accounts", getErrorCategory) + ErrKeypairMustHaveAtLeastOneWalletAccount = errors.NewError(ErrCodeKeypairMustHaveAtLeastOneWalletAccount, "keypair must have at least one wallet account", getErrorCategory) + ErrCannotAddAccountsToKeypairImportedViaPrivateKey = errors.NewError(ErrCodeCannotAddAccountsToKeypairImportedViaPrivateKey, "cannot add accounts to keypair imported via private key", getErrorCategory) + ErrCannotAddDefaultWalletAccount = errors.NewError(ErrCodeCannotAddDefaultWalletAccount, "cannot add default wallet account", getErrorCategory) + ErrCannotRemoveDefaultWalletAccount = errors.NewError(ErrCodeCannotRemoveDefaultWalletAccount, "cannot remove default wallet account", getErrorCategory) + ErrCannotAddDefaultChatAccount = errors.NewError(ErrCodeCannotAddDefaultChatAccount, "cannot add default chat account", getErrorCategory) + ErrCannotRemoveDefaultChatAccount = errors.NewError(ErrCodeCannotRemoveDefaultChatAccount, "cannot remove default chat account", getErrorCategory) + ErrCannotMigrateProfileKeypair = errors.NewError(ErrCodeCannotMigrateProfileKeypair, "cannot migrate profile keypair", getErrorCategory) + ErrKeypairIsNotKeycard = errors.NewError(ErrCodeKeypairIsNotKeycard, "keypair is not a keycard keypair", getErrorCategory) + ErrKeycardDoesNotHaveAnyAccounts = errors.NewError(ErrCodeKeycardDoesNotHaveAnyAccounts, "keycard does not have any accounts", getErrorCategory) + ErrCannotRemoveProfileKeypair = errors.NewError(ErrCodeCannotRemoveProfileKeypair, "cannot remove profile keypair", getErrorCategory) +) + +func ErrKeystoreDirectoryError(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeKeystoreDirectoryError, "make keystore directory", err, getErrorCategory) +} + +func ErrWrongPasswordProvided(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeWrongPasswordProvided, "wrong password provided", err, getErrorCategory) +} + +func ErrKeycardDoesNotRelateToAnyKeypair(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeKeycardDoesNotRelateToAnyKeypair, "keycard does not relate to any keypair", err, getErrorCategory) +} + +func getErrorCategory(code errors.ErrorCode) errors.ErrorCategory { + switch code { + case ErrCodeLoggerMissing, ErrCodeKeystoreMissing, ErrCodePersistenceMissing: + return ErrorCategorySystem + case ErrCodeAccountMismatch, ErrCodeNoAccountSelected, ErrCodeAccountDoesNotExist, ErrCodeAccountIsNil, ErrCodeKeypairIsNil: + return ErrorCategoryAccount + case ErrCodeKeystoreDirectoryError, ErrCodeKeystoreFileMissing: + return ErrorCategoryKeystore + case ErrCodeAddressAndPasswordOrPrivateKeyRequired, ErrCodeKeypairDoesNotHaveWalletAccount, ErrCodeUnsupportedWalletAccountPath, + ErrCodeKeypairAlreadyAdded, ErrCodeAccountAlreadyAdded, ErrCodeChatAccountNotFoundInDerivedAccounts, + ErrCodeKeypairMustHaveAtLeastOneWalletAccount, ErrCodeCannotAddAccountsToKeypairImportedViaPrivateKey, + ErrCodeCannotMigrateProfileKeypair, ErrCodeKeypairIsNotKeycard, ErrCodeWrongPasswordProvided, ErrCodeKeycardDoesNotHaveAnyAccounts, + ErrCodeKeycardDoesNotRelateToAnyKeypair: + return ErrorCategoryValidation + case ErrCodeCannotAddDefaultWalletAccount, ErrCodeCannotAddDefaultChatAccount, ErrCodeCannotRemoveDefaultWalletAccount, + ErrCodeCannotRemoveDefaultChatAccount, ErrCodeCannotRemoveProfileKeypair: + return ErrorCategoryDatabase + default: + return errors.ErrorCategoryUnknown + } +} diff --git a/accounts-management/core/keystore_operations.go b/accounts-management/core/keystore_operations.go new file mode 100644 index 0000000000..5abe058c80 --- /dev/null +++ b/accounts-management/core/keystore_operations.go @@ -0,0 +1,316 @@ +package core + +import ( + "os" + "path/filepath" + "strings" + + "go.uber.org/zap" + + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/accounts-management/keystore" + "github.com/status-im/status-go/accounts-management/keystore/geth" + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +// ReloadKeystore reloads the keystore for the selected chat account +func (m *AccountsManager) ReloadKeystore() error { + m.mu.Lock() + defer m.mu.Unlock() + + if m.selectedChatAccount == nil || m.profileKeyUID == "" { + return ErrNoAccountSelected + } + + keystore, err := m.createKeystore(m.profileKeyUID) + if err != nil { + return err + } + m.setKeystore(keystore) + return nil +} + +// StoreKeystoreFilesForMnemonic stores the keystore files for an account created from a given mnemonic and for all derived accounts from given paths +func (m *AccountsManager) StoreKeystoreFilesForMnemonic(mnemonic string, password string, paths []string) (account *generator.Account, derivedAccounts map[string]*generator.Account, err error) { + m.mu.Lock() + defer m.mu.Unlock() + + return m.storeKeystoreFilesForMnemonicInternally(mnemonic, password, paths) +} + +func (m *AccountsManager) storeKeystoreFilesForMnemonicInternally(mnemonic string, password string, paths []string) (account *generator.Account, derivedAccounts map[string]*generator.Account, err error) { + account, derivedAccounts, err = generator.CreateAndDeriveAccountsFromMnemonic(mnemonic, paths, "") + if err != nil { + return + } + + err = m.storeKeystoreFilesForAccounts(account, derivedAccounts, password) + if err != nil { + return + } + + return +} + +// StoreKeystoreFilesForPrivateKey stores the keystore file for an account created from a given private key +func (m *AccountsManager) StoreKeystoreFilesForPrivateKey(privateKey string, password string) (account *generator.Account, err error) { + m.mu.Lock() + defer m.mu.Unlock() + + return m.storeKeystoreFilesForPrivateKeyInternally(privateKey, password) +} + +func (m *AccountsManager) storeKeystoreFilesForPrivateKeyInternally(privateKey string, password string) (account *generator.Account, err error) { + + account, err = generator.CreateAccountFromPrivateKey(privateKey) + if err != nil { + return + } + + err = m.storeKeystoreFilesForAccounts(account, nil, password) + if err != nil { + return + } + + return +} + +func (m *AccountsManager) storeKeystoreFilesForAccounts(account *generator.Account, derivedAccounts map[string]*generator.Account, password string) (err error) { + err = m.storeToKeystore(account, password) + if err != nil { + return + } + + m.logger.Info("master account stored (mnemonic)", zap.String("address", account.Address().Hex())) + + for path, acc := range derivedAccounts { + err = m.storeToKeystore(acc, password) + if err != nil { + return + } + m.logger.Info("account on path created and stored (mnemonic)", zap.String("path", path), zap.String("address", acc.Address().Hex())) + } + + return +} + +func (m *AccountsManager) storeToKeystore(acc *generator.Account, password string) (err error) { + if m.keystore == nil { + return ErrKeystoreMissing + } + + if acc == nil { + return ErrAccountIsNil + } + + m.logger.Info("storing account to keystore", zap.String("address", acc.Address().Hex())) + + if acc.HasExtendedKey() { + _, err = m.keystore.ImportSingleExtendedKey(acc.ExtendedKey(), password) + return + } + + _, err = m.keystore.ImportECDSA(acc.PrivateKey(), password) + return +} + +func (m *AccountsManager) createKeystore(keyUID string) (keystore.KeyStore, error) { + // prepare keystore path + const DefaultKeystoreRelativePath = "keystore" + relativePath := filepath.Join(DefaultKeystoreRelativePath, keyUID) + absoluteKeystorePath := filepath.Join(m.rootDataDir, relativePath) + + if _, err := os.Stat(absoluteKeystorePath); os.IsNotExist(err) { + if err := os.MkdirAll(filepath.Clean(absoluteKeystorePath), os.ModePerm); err != nil { + return nil, ErrKeystoreDirectoryError(err) + } + } + + return geth.NewGethKeystoreAdapter(absoluteKeystorePath) +} + +// deleteAccountFromKeystore deletes an account from the keystore +func (m *AccountsManager) deleteAccountFromKeystore(address cryptotypes.Address) error { + if m.keystore == nil { + m.logger.Error("cannot delete account, keystore is missing", zap.String("address", address.Hex())) + return ErrKeystoreMissing + } + m.logger.Info("deleting account", zap.String("address", address.Hex())) + return m.keystore.Delete(address) +} + +// DeleteKeystoreFileForAccount deletes the keystore file for an account +// if the account is non-operable or partially operable, it does nothing +// if the account is a watch account, it does nothing +// if the account is a key account, it deletes the keystore file for the account +// if the account is a key account and it is the last account of the keypair, it deletes the master account keystore file +// trying to delete a non-existent keystore file for an account does not result in an error +func (m *AccountsManager) DeleteKeystoreFileForAccount(address cryptotypes.Address) error { + m.mu.Lock() + defer m.mu.Unlock() + + return m.deleteKeystoreFileForAccountInternally(address) +} + +func (m *AccountsManager) deleteKeystoreFileForAccountInternally(address cryptotypes.Address) error { + if m.persistence == nil { + return ErrPersistenceMissing + } + + acc, err := m.persistence.GetAccountByAddress(address) + if err != nil { + return err + } + + if acc.Operable == types.AccountNonOperable || acc.Operable == types.AccountPartiallyOperable { + return nil + } + + if acc.Type != types.AccountTypeWatch { + kp, err := m.persistence.GetKeypairByKeyUID(acc.KeyUID) + if err != nil { + return err + } + + if !kp.MigratedToKeycard() { + err = m.deleteAccountFromKeystore(address) + if err != nil { + return err + } + + if acc.Type != types.AccountTypeKey { + lastAcccountOfKeypairWithTheSameKey := len(kp.Accounts) == 1 + if lastAcccountOfKeypairWithTheSameKey { + err = m.deleteAccountFromKeystore(cryptotypes.HexToAddress(kp.DerivedFrom)) + if err != nil { + return err + } + } + } + } + } + + return nil +} + +// DeleteKeystoreFilesForKeypair deletes the keystore files for a keypair +// if the keypair is already migrated to keycard, it does nothing +// trying to delete a non-existent keystore file does not result in an error +func (m *AccountsManager) DeleteKeystoreFilesForKeypair(keypair *types.Keypair) (err error) { + m.mu.Lock() + defer m.mu.Unlock() + + return m.deleteKeystoreFilesForKeypairInternally(keypair) +} + +func (m *AccountsManager) deleteKeystoreFilesForKeypairInternally(keypair *types.Keypair) (err error) { + if keypair == nil { + return ErrKeypairIsNil + } + + if keypair.MigratedToKeycard() { + return nil + } + + if m.persistence == nil { + return ErrPersistenceMissing + } + + anyAccountFullyOrPartiallyOperable := false + for _, acc := range keypair.Accounts { + if acc.Removed || acc.Operable == types.AccountNonOperable { + continue + } + if !anyAccountFullyOrPartiallyOperable { + anyAccountFullyOrPartiallyOperable = true + } + if acc.Operable == types.AccountPartiallyOperable { + continue + } + err = m.deleteAccountFromKeystore(acc.Address) + if err != nil { + return err + } + } + + if anyAccountFullyOrPartiallyOperable && keypair.Type != types.KeypairTypeKey { + err = m.deleteAccountFromKeystore(cryptotypes.HexToAddress(keypair.DerivedFrom)) + if err != nil { + return err + } + } + + return +} + +// MigrateKeyStoreDir migrates the keystore directory from the current location to the provided new location +func (m *AccountsManager) MigrateKeyStoreDir(newDir string) error { + m.mu.Lock() + defer m.mu.Unlock() + + if m.keystore == nil { + return ErrKeystoreMissing + } + m.logger.Info("migrating keystore directory", zap.String("new location", newDir)) + return m.keystore.MigrateKeyStoreDir(newDir) +} + +// ReEncryptKeyStoreDir re-encrypts the keystore directory with the provided old and new passwords +func (m *AccountsManager) ReEncryptKeyStoreDir(oldPass, newPass string) error { + m.mu.RLock() + defer m.mu.RUnlock() + + if m.keystore == nil { + return ErrKeystoreMissing + } + m.logger.Info("re-encrypting keystore directory") + return m.keystore.ReEncryptKeyStoreDir(oldPass, newPass) +} + +func (m *AccountsManager) generatePartialAccountKey(address cryptotypes.Address, password string) (*generator.Account, error) { + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + rootAddress, err := m.persistence.GetWalletRootAddress() + if err != nil { + return nil, err + } + + acc, err := m.persistence.GetAccountByAddress(address) + if err != nil { + return nil, err + } + + dbPath, err := m.persistence.GetPath(acc.Address) + if err != nil { + return nil, err + } + path := "m/" + dbPath[strings.LastIndex(dbPath, "/")+1:] + + return m.deriveChildAccountForPathAndStore(rootAddress, path, password) +} + +func (m *AccountsManager) deriveChildAccountForPath(deriveFrom cryptotypes.Address, path string, password string) (*generator.Account, error) { + account, err := m.loadAccountInternally(deriveFrom, password) + if err != nil { + return nil, err + } + + return generator.DeriveChildFromAccount(account, path) +} + +func (m *AccountsManager) deriveChildAccountForPathAndStore(deriveFrom cryptotypes.Address, path string, password string) (*generator.Account, error) { + childAccount, err := m.deriveChildAccountForPath(deriveFrom, path, password) + if err != nil { + return nil, err + } + + err = m.storeToKeystore(childAccount, password) + if err != nil { + return nil, err + } + + return childAccount, nil +} diff --git a/accounts-management/core/manager.go b/accounts-management/core/manager.go new file mode 100644 index 0000000000..ffb1c3633b --- /dev/null +++ b/accounts-management/core/manager.go @@ -0,0 +1,237 @@ +package core + +import ( + "crypto/ecdsa" + "errors" + "sync" + + "go.uber.org/zap" + + accsmanagementerrors "github.com/status-im/status-go/accounts-management/errors" + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/accounts-management/keystore" + "github.com/status-im/status-go/accounts-management/persistence" + gocommon "github.com/status-im/status-go/common" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +// AccountsManager represents the default account manager implementation +type AccountsManager struct { + mu sync.RWMutex + keystore keystore.KeyStore + persistence persistence.Persistence + + rootDataDir string + profileKeyUID string + selectedChatAccount *generator.Account + + logger *zap.Logger +} + +func NewAccountsManager(logger *zap.Logger) (*AccountsManager, error) { + if logger == nil { + return nil, ErrLoggerIsMissing + } + + logger.Info("accounts manager created") + return &AccountsManager{ + logger: logger, + }, nil +} + +// SetPersistence sets the persistence for the accounts manager +func (m *AccountsManager) SetPersistence(persistence persistence.Persistence) { + m.mu.Lock() + defer m.mu.Unlock() + + m.persistence = persistence +} + +// SetRootDataDir sets the root data directory for the accounts manager +func (m *AccountsManager) SetRootDataDir(rootDataDir string) { + m.mu.Lock() + defer m.mu.Unlock() + + m.rootDataDir = rootDataDir +} + +func (m *AccountsManager) setKeystore(keystore keystore.KeyStore) { + m.keystore = keystore +} + +func (m *AccountsManager) setChatAccountAndProfileKeyUID(account *generator.Account, profileKeyUID string) { + m.selectedChatAccount = account + m.profileKeyUID = profileKeyUID +} + +func (m *AccountsManager) isChatAccountSet(address cryptotypes.Address) bool { + return m.selectedChatAccount != nil && m.selectedChatAccount.Address() == address +} + +// VerifyAccountPassword verifies if the account key for a given address and password is correct. +func (m *AccountsManager) VerifyAccountPassword(address cryptotypes.Address, password string) (bool, error) { + account, err := m.LoadAccount(address, password) + if err != nil { + return false, err + } + + if account.Address() != address { + return false, ErrAccountMismatch. + WithContext("got", gocommon.TruncateWithDot(account.Address().Hex())). + WithContext("want", gocommon.TruncateWithDot(address.Hex())) + } + + return true, nil +} + +// LoadAccount loads an account key from the keystore for a given address and password. +// If either address or password is incorrect, an error is returned. +func (m *AccountsManager) LoadAccount(address cryptotypes.Address, password string) (*generator.Account, error) { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.loadAccountInternally(address, password) +} + +func (m *AccountsManager) loadAccountInternally(address cryptotypes.Address, password string) (*generator.Account, error) { + if m.keystore == nil { + return nil, ErrKeystoreMissing + } + + _, privateKey, extendedKey, err := m.keystore.AccountDecryptedKey(address, password) + if err != nil { + m.logger.Error("error loading account", zap.String("address", address.Hex()), zap.Error(err)) + if errors.Is(err, keystore.ErrNoMatch) { + m.logger.Error("cannot locate account for address", zap.String("address", address.Hex())) + return nil, ErrKeystoreFileMissing.WithContext("address", address.Hex()) + } + return nil, err + } + + account := generator.NewAccount(privateKey, extendedKey) + if err := account.ValidateExtendedKey(); err != nil { + m.logger.Error("error validating account", zap.String("address", address.Hex()), zap.Error(err)) + return nil, err + } + + m.logger.Info("account loaded", zap.String("address", address.Hex())) + return account, nil +} + +// SetChatAccount sets the chat account and keystore either by address and password or by private key +func (m *AccountsManager) SetChatAccount(address cryptotypes.Address, password string, privateKey *ecdsa.PrivateKey) error { + if address == cryptotypes.ZeroAddress() && privateKey == nil { + return ErrAddressAndPasswordOrPrivateKeyRequired + } + + m.mu.Lock() + defer m.mu.Unlock() + + if m.isChatAccountSet(address) { + m.logger.Info("chat account already set", zap.String("address", address.Hex())) + return nil + } + + profileKeypair, err := m.persistence.GetProfileKeypair() + if err != nil { + return err + } + + keystore, err := m.createKeystore(profileKeypair.KeyUID) + if err != nil { + return err + } + m.setKeystore(keystore) + + var selectedChatAccount *generator.Account + if privateKey != nil { + selectedChatAccount = generator.NewAccount(privateKey, nil) + } else { + selectedChatAccount, err = m.loadAccountInternally(address, password) + if err != nil { + return err + } + } + + m.setChatAccountAndProfileKeyUID(selectedChatAccount, profileKeypair.KeyUID) + + return nil +} + +// SelectedChatAccount returns currently selected chat account +func (m *AccountsManager) SelectedChatAccount() (*generator.Account, error) { + m.mu.RLock() + defer m.mu.RUnlock() + + if m.selectedChatAccount == nil { + return nil, ErrNoAccountSelected + } + return m.selectedChatAccount, nil +} + +// Logout clears everything. +func (m *AccountsManager) Logout() { + m.mu.Lock() + defer m.mu.Unlock() + + m.keystore = nil + m.persistence = nil + m.rootDataDir = "" + m.selectedChatAccount = nil + m.profileKeyUID = "" + m.logger.Info("logout") +} + +// Accounts returns list of addresses for selected account, including subaccounts. +func (m *AccountsManager) Accounts() ([]cryptotypes.Address, error) { + m.mu.RLock() + defer m.mu.RUnlock() + + if m.keystore == nil { + return nil, ErrKeystoreMissing + } + + ksAccounts := m.keystore.Accounts() + addresses := make([]cryptotypes.Address, 0, len(ksAccounts)) + for _, account := range ksAccounts { + addresses = append(addresses, account.Address) + } + + return addresses, nil +} + +// GetVerifiedWalletAccount gets a verified wallet account by address and password +// If the account is not found, it tries to generate the account if there is an account this account can be derived from +// TODO: need to check it that's needed at all, cause `generatePartialAccountKey` was used for the old mobile app - maybe we should remove it +func (m *AccountsManager) GetVerifiedWalletAccount(address cryptotypes.Address, password string) (*generator.Account, error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + exists, err := m.persistence.AddressExists(address) + if err != nil { + return nil, err + } + + if !exists { + return nil, ErrAccountDoesNotExist.WithContext("address", address.Hex()) + } + + account, err := m.loadAccountInternally(address, password) + if err != nil { + var accountsErr *accsmanagementerrors.AccountsError + if errors.As(err, &accountsErr) && accountsErr.Is(ErrKeystoreFileMissing) { + account, err = m.generatePartialAccountKey(address, password) + if err != nil { + return nil, err + } + } else { + return nil, err + } + } + + return account, nil +} diff --git a/accounts-management/core/manager_test.go b/accounts-management/core/manager_test.go new file mode 100644 index 0000000000..fdb6c619ae --- /dev/null +++ b/accounts-management/core/manager_test.go @@ -0,0 +1,517 @@ +package core + +import ( + "bytes" + "errors" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/status-im/status-go/accounts-management/common" + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/accounts-management/keystore" + mock_persistence "github.com/status-im/status-go/accounts-management/mock" + "github.com/status-im/status-go/accounts-management/types" + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/protocol/tt" + "github.com/status-im/status-go/t/utils" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + gomock "go.uber.org/mock/gomock" + + customerrors "github.com/status-im/status-go/accounts-management/errors" +) + +const testPassword = "test-password" +const newTestPassword = "new-test-password" + +func TestVerifyAccountPassword(t *testing.T) { + accManager, err := NewAccountsManager(tt.MustCreateTestLogger()) + require.NoError(t, err) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + persistence := mock_persistence.NewMockPersistence(ctrl) + accManager.SetPersistence(persistence) + + utils.Init() // initialize the test config + + testCases := []struct { + name string + keyUID string + address string + password string + keystoreSet bool + importToLocation bool + expectedError error + }{ + { + "correct address, correct password (decrypt should succeed)", + utils.TestConfig.Account1.KeyUID, + utils.TestConfig.Account1.WalletAddress, + utils.TestConfig.Account1.Password, + true, + true, + nil, + }, + { + "correct address, correct password, non-existent key store", + utils.TestConfig.Account1.KeyUID, + utils.TestConfig.Account1.WalletAddress, + utils.TestConfig.Account1.Password, + false, + false, + ErrKeystoreMissing, + }, + { + "correct address, correct password, empty key store (pk is not there)", + utils.TestConfig.Account1.KeyUID, + utils.TestConfig.Account1.WalletAddress, + utils.TestConfig.Account1.Password, + true, + false, + keystore.ErrNoMatch, + }, + { + "wrong address, correct password", + utils.TestConfig.Account1.KeyUID, + "0x79791d3e8f2daa1f7fec29649d152c0ada3cc535", + utils.TestConfig.Account1.Password, + true, + true, + keystore.ErrNoMatch, + }, + { + "correct address, wrong password", + utils.TestConfig.Account1.KeyUID, + utils.TestConfig.Account1.WalletAddress, + "wrong password", // wrong password + true, + true, + keystore.ErrDecrypt, + }, + } + for _, testCase := range testCases { + + rootDataDir := t.TempDir() + accManager.SetRootDataDir(rootDataDir) + keystore, err := accManager.createKeystore(testCase.keyUID) + require.NoError(t, err) + + if testCase.importToLocation { + err = utils.ImportTestAccount(keystore.KeystorePath(), utils.GetAccount1PKFile()) + require.NoError(t, err) + + // now we need to re-create the keystore in order to make the get-keystore aware of the copied account + keystore, err = accManager.createKeystore(testCase.keyUID) + require.NoError(t, err) + } + + if testCase.keystoreSet { + accManager.setKeystore(keystore) + } else { + accManager.setKeystore(nil) + } + + ok, err := accManager.VerifyAccountPassword(cryptotypes.HexToAddress(testCase.address), testCase.password) + if testCase.expectedError != nil && err != nil { + if !errors.Is(err, testCase.expectedError) { + var accountsErr *customerrors.AccountsError + if errors.As(err, &accountsErr) { + if testCase.expectedError.Error() == "no key for given address or file" { + require.Contains(t, accountsErr.Error(), "keystore file is missing") + } else { + require.Equal(t, testCase.expectedError.Error(), accountsErr.Error()) + } + } else { + require.Equal(t, testCase.expectedError.Error(), err.Error()) + } + } + } else if (testCase.expectedError == nil || err == nil) && testCase.expectedError != err { + require.FailNow(t, fmt.Sprintf("unexpected error: expected \n'%v', got \n'%v'", testCase.expectedError, err)) + } + if err == nil { + require.True(t, ok) + } else { + require.False(t, ok) + } + } +} + +// TestVerifyAccountPasswordWithAccountBeforeEIP55 verifies if VerifyAccountPassword +// can handle accounts before introduction of EIP55. +func TestVerifyAccountPasswordWithAccountBeforeEIP55(t *testing.T) { + rootDataDir := t.TempDir() + + utils.Init() // initialize the test config + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + accManager, err := NewAccountsManager(tt.MustCreateTestLogger()) + require.NoError(t, err) + + persistence := mock_persistence.NewMockPersistence(ctrl) + accManager.SetPersistence(persistence) + + accManager.SetRootDataDir(rootDataDir) + + keystore, err := accManager.createKeystore(utils.TestConfig.Account3.KeyUID) + require.NoError(t, err) + + err = utils.ImportTestAccount(keystore.KeystorePath(), "test-account3-before-eip55.pk") // Import keys and make sure one was created before EIP55 introduction. + require.NoError(t, err) + + // now we need to reload the keystore (re-create it) in order to make the get-keystore aware of the copied account + err = accManager.ReloadKeystore() + require.Error(t, err) + require.Equal(t, ErrNoAccountSelected, err) + + persistence.EXPECT().GetProfileKeypair().Return( + &types.Keypair{ + KeyUID: utils.TestConfig.Account3.KeyUID, + }, + nil, + ).Times(1) + + // Set the chat account, this will create a new keystore + err = accManager.SetChatAccount(cryptotypes.HexToAddress(utils.TestConfig.Account3.ChatAddress), utils.TestConfig.Account3.Password, nil) + require.NoError(t, err) + + address := cryptotypes.HexToAddress(utils.TestConfig.Account3.ChatAddress) + ok, err := accManager.VerifyAccountPassword(address, utils.TestConfig.Account3.Password) + require.NoError(t, err) + require.True(t, ok) +} + +func TestManagerTestSuite(t *testing.T) { + suite.Run(t, new(ManagerTestSuite)) +} + +type ManagerTestSuite struct { + suite.Suite + testAccount + accManager *AccountsManager + persistence *mock_persistence.MockPersistence + rootDataDir string +} + +type testAccount struct { + password string + walletAddress cryptotypes.Address + walletPubKey string + chatAddress cryptotypes.Address + chatPubKey string + mnemonic string + masterAccount *generator.Account +} + +// SetupTest is used here for reinitializing the mock before every +// test function to avoid faulty execution. +func (s *ManagerTestSuite) SetupTest() { + ctrl := gomock.NewController(s.T()) + defer ctrl.Finish() + + var err error + s.accManager, err = NewAccountsManager(tt.MustCreateTestLogger()) + s.Require().NoError(err) + + s.persistence = mock_persistence.NewMockPersistence(ctrl) + s.accManager.SetPersistence(s.persistence) + + s.rootDataDir = s.T().TempDir() + s.accManager.SetRootDataDir(s.rootDataDir) + + // Initial test - create test account + mnemonic, err := common.CreateRandomMnemonicWithDefaultLength() + s.Require().NoError(err) + + paths := []string{common.PathEIP1581Chat, common.PathDefaultWalletAccount} + genAcc, derivedAccounts, err := generator.CreateAndDeriveAccountsFromMnemonic(mnemonic, paths, "") + s.Require().NoError(err) + + s.testAccount = testAccount{ + testPassword, + derivedAccounts[common.PathDefaultWalletAccount].Address(), + derivedAccounts[common.PathDefaultWalletAccount].PublicKeyHex(), + derivedAccounts[common.PathEIP1581Chat].Address(), + derivedAccounts[common.PathEIP1581Chat].PublicKeyHex(), + mnemonic, + genAcc, + } +} + +func (s *ManagerTestSuite) getKeyDir() string { + return fmt.Sprintf("%s/keystore/%s", s.rootDataDir, s.masterAccount.KeyUID()) +} + +func (s *ManagerTestSuite) createAndStoreProfileKeypair() *types.Keypair { + s.persistence.EXPECT().GetKeypairByKeyUID(s.masterAccount.KeyUID()).Return( + nil, types.ErrDbKeypairNotFound, + ).Times(1) + + s.persistence.EXPECT().GetPositionForNextNewAccount().Return(int64(0), nil).Times(1) + + s.persistence.EXPECT().SaveOrUpdateKeypair(gomock.Any()).Return(nil).Times(1) + + s.persistence.EXPECT().GetProfileKeypair().Return( + &types.Keypair{ + KeyUID: s.masterAccount.KeyUID(), + }, + nil, + ).Times(1) + + walletAccount := &types.AccountCreationDetails{ + Path: common.PathDefaultWalletAccount, + } + + keypair, err := s.accManager.CreateKeypairFromMnemonicAndStore(s.mnemonic, s.password, "kp-name", walletAccount, true, 0) + s.Require().NoError(err) + s.Require().NotEmpty(s.mnemonic) + s.Require().NotNil(keypair) + s.Require().Equal(s.masterAccount.KeyUID(), keypair.KeyUID) + s.Require().Equal(s.masterAccount.Address().Hex(), keypair.DerivedFrom) + s.Require().Len(keypair.Accounts, 2) + + chatAccountOk := false + walletAccountOk := false + for _, kpAcc := range keypair.Accounts { + if kpAcc.Chat { + chatAccountOk = kpAcc.Path == common.PathEIP1581Chat && + kpAcc.Address == s.chatAddress && + bytes.Equal(kpAcc.PublicKey, cryptotypes.Hex2Bytes(s.chatPubKey)) && + kpAcc.KeyUID == keypair.KeyUID && + !kpAcc.Removed && + kpAcc.Clock == 0 && + !kpAcc.Wallet && + kpAcc.AddressWasNotShown && + kpAcc.Position == -1 && + kpAcc.Operable == types.AccountFullyOperable + } + if kpAcc.Wallet { + walletAccountOk = kpAcc.Path == common.PathDefaultWalletAccount && + kpAcc.Address == s.walletAddress && + bytes.Equal(kpAcc.PublicKey, cryptotypes.Hex2Bytes(s.walletPubKey)) && + kpAcc.KeyUID == keypair.KeyUID && + !kpAcc.Removed && + kpAcc.Clock == 0 && + !kpAcc.Chat && + kpAcc.AddressWasNotShown && + kpAcc.Position == 0 && + kpAcc.Operable == types.AccountFullyOperable + } + } + s.Require().True(chatAccountOk) + s.Require().True(walletAccountOk) + + return keypair +} + +func (s *ManagerTestSuite) TestRecoverAccount() { + s.createAndStoreProfileKeypair() +} + +func (s *ManagerTestSuite) TestSetChatAccountSuccess() { + s.testSetChatAccount(s.testAccount.chatAddress, s.testAccount.password, nil) +} + +func (s *ManagerTestSuite) TestSetChatAccountWrongAddress() { + s.testSetChatAccount(cryptotypes.HexToAddress("0x0000000000000000000000000000000000000001"), s.testAccount.password, keystore.ErrNoMatch) +} + +func (s *ManagerTestSuite) TestSetChatAccountWrongPassword() { + s.testSetChatAccount(s.testAccount.chatAddress, "wrong", keystore.ErrDecrypt) +} + +func (s *ManagerTestSuite) testSetChatAccount(chat cryptotypes.Address, password string, expErr error) { + s.createAndStoreProfileKeypair() + s.accManager.setChatAccountAndProfileKeyUID(nil, "") // clear the chat account set by `createAndStoreProfileKeypair` + + s.persistence.EXPECT().GetProfileKeypair().Return( + &types.Keypair{ + KeyUID: s.masterAccount.KeyUID(), + }, + nil, + ).Times(1) + + err := s.accManager.SetChatAccount(chat, password, nil) + if expErr != nil { + if !errors.Is(err, expErr) { + var accountsErr *customerrors.AccountsError + if errors.As(err, &accountsErr) { + if expErr.Error() == "no key for given address or file" { + s.Require().Contains(accountsErr.Error(), "keystore file is missing") + } else { + s.Require().Equal(expErr.Error(), accountsErr.Error()) + } + } else { + s.Require().Equal(expErr, err) + } + } + } else { + s.Require().NoError(err) + } + + selectedChatAccount, err := s.accManager.SelectedChatAccount() + + if expErr == nil { + s.Require().NoError(err) + s.Equal(chat, crypto.PubkeyToAddress(selectedChatAccount.PrivateKey().PublicKey)) + s.Require().NotNil(s.accManager.keystore) + s.Equal(s.getKeyDir(), s.accManager.keystore.KeystorePath()) + } else { + s.Nil(selectedChatAccount) + s.Equal(err, ErrNoAccountSelected) + } + + s.accManager.Logout() +} + +func (s *ManagerTestSuite) TestSetChatAccountForExistingProfile() { + s.createAndStoreProfileKeypair() + s.accManager.setChatAccountAndProfileKeyUID(nil, "") // clear the chat account set by `createAndStoreProfileKeypair` + + genAcc, err := generator.CreateAccountFromMnemonic(s.mnemonic, "") + s.Require().NoError(err) + + s.persistence.EXPECT().GetProfileKeypair().Return( + &types.Keypair{ + KeyUID: s.masterAccount.KeyUID(), + }, + nil, + ).Times(1) + + s.Require().NoError(s.accManager.SetChatAccount(genAcc.Address(), s.password, nil)) + selectedChatAccount, err := s.accManager.SelectedChatAccount() + s.Require().NoError(err) + s.Require().NotNil(selectedChatAccount) + s.Equal(genAcc.PrivateKeyHex(), selectedChatAccount.PrivateKeyHex()) + s.Equal(genAcc.Address(), selectedChatAccount.Address()) +} + +func (s *ManagerTestSuite) TestLogout() { + s.accManager.Logout() + s.Nil(s.accManager.selectedChatAccount) + s.Nil(s.accManager.keystore) + s.Nil(s.accManager.persistence) + s.Empty(s.accManager.rootDataDir) +} + +// TestAccounts tests cases for (*Manager).Accounts. +func (s *ManagerTestSuite) TestAccounts() { + s.persistence.EXPECT().GetProfileKeypair().Return( + &types.Keypair{ + KeyUID: s.masterAccount.KeyUID(), + }, + nil, + ).Times(1) + + // Select the test account, when the profile keypair is not stored + err := s.accManager.SetChatAccount(s.chatAddress, s.password, nil) + s.Require().Error(err) + if !errors.Is(err, keystore.ErrNoMatch) { + var accountsErr *customerrors.AccountsError + if errors.As(err, &accountsErr) { + s.Contains(accountsErr.Error(), "keystore file is missing") + } else { + s.Equal(keystore.ErrNoMatch, err) + } + } + + s.createAndStoreProfileKeypair() + + selectedChatAccount, err := s.accManager.SelectedChatAccount() + s.Require().NoError(err) + s.Equal(s.chatAddress, selectedChatAccount.Address()) + + err = s.accManager.SetChatAccount(s.chatAddress, s.password, nil) + s.Require().NoError(err) + + // Success + accs, err := s.accManager.Accounts() + s.NoError(err) + s.Len(accs, 3) + + checkAccount := func(address cryptotypes.Address) bool { + return address == s.chatAddress || address == s.walletAddress || address == s.masterAccount.Address() + } + s.True(checkAccount(accs[0])) + s.True(checkAccount(accs[1])) + s.True(checkAccount(accs[2])) +} + +func (s *ManagerTestSuite) TestAddressToAccountSuccess() { + s.testAddressToAccount(s.walletAddress, s.password, nil) +} + +func (s *ManagerTestSuite) TestAddressToAccountWrongAddress() { + s.testAddressToAccount(cryptotypes.HexToAddress("0x0001"), s.password, ErrKeystoreFileMissing) +} + +func (s *ManagerTestSuite) TestAddressToAccountWrongPassword() { + s.testAddressToAccount(s.walletAddress, "wrong", keystore.ErrDecrypt) +} + +func (s *ManagerTestSuite) testAddressToAccount(wallet cryptotypes.Address, password string, expErr error) { + s.createAndStoreProfileKeypair() + + key, err := s.accManager.LoadAccount(wallet, password) + if expErr != nil { + if !errors.Is(err, expErr) { + var accountsErr *customerrors.AccountsError + if errors.As(err, &accountsErr) { + s.Equal(expErr.Error(), accountsErr.Error()) + } else { + s.Equal(expErr, err) + } + } + } else { + s.Require().NoError(err) + s.Require().NotNil(key) + s.Equal(wallet, key.Address()) + } +} + +func (s *ManagerTestSuite) TestMigrateKeyStoreDir() { + s.createAndStoreProfileKeypair() + + oldKeyDir := s.getKeyDir() + newKeyDir := filepath.Join(oldKeyDir, "new_dir") + err := os.Mkdir(newKeyDir, 0777) + s.Require().NoError(err) + + files, _ := os.ReadDir(newKeyDir) + s.Equal(0, len(files)) + + err = s.accManager.MigrateKeyStoreDir(newKeyDir) + s.Require().NoError(err) + + files, _ = os.ReadDir(newKeyDir) + s.Equal(3, len(files)) +} + +func (s *ManagerTestSuite) TestReEncryptKeyStoreDir() { + keypair := s.createAndStoreProfileKeypair() + + err := s.accManager.ReEncryptKeyStoreDir(testPassword, newTestPassword) + s.Require().NoError(err) + + accountsToCheck := []string{keypair.DerivedFrom} + for _, acc := range keypair.Accounts { + accountsToCheck = append(accountsToCheck, acc.Address.Hex()) + } + + for _, acc := range accountsToCheck { + account, err := s.accManager.LoadAccount(cryptotypes.HexToAddress(acc), testPassword) + s.Require().Error(err) + s.Require().Nil(account) + + account, err = s.accManager.LoadAccount(cryptotypes.HexToAddress(acc), newTestPassword) + s.Require().NoError(err) + s.Require().NotNil(account) + } +} diff --git a/accounts-management/core/persistence_operations.go b/accounts-management/core/persistence_operations.go new file mode 100644 index 0000000000..609939e1c6 --- /dev/null +++ b/accounts-management/core/persistence_operations.go @@ -0,0 +1,646 @@ +package core + +import ( + "strings" + + "github.com/status-im/status-go/accounts-management/common" + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/accounts-management/keystore" + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +// CreateKeypairFromMnemonicAndStore creates a keypair with provided `walletAccount` and optionally a chat account if +// it's a profile keypair. It also stores the keypair/accounts to db and accounts to keystore if it's not a keycard. +// If it's a profile keypair, it also sets the chat account. +// Passed `walletAccount` is used to generate address using its path and set other details accordingly. +func (m *AccountsManager) CreateKeypairFromMnemonicAndStore(mnemonic string, password string, keypairName string, + walletAccount *types.AccountCreationDetails, profile bool, clock uint64) (keypair *types.Keypair, err error) { + + if walletAccount == nil { + err = ErrKeypairDoesNotHaveWalletAccount + return + } + + if !strings.HasPrefix(walletAccount.Path, common.WalletPath) { + err = ErrUnsupportedWalletAccountPath. + WithContext("path", walletAccount.Path). + WithContext("expected path", common.WalletPath) + return + } + + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + paths := []string{ + walletAccount.Path, + } + if profile { + paths = append(paths, common.PathEIP1581Chat) + } + + // generate accounts from mnemonic + var masterAccount *generator.Account + var derivedAccounts map[string]*generator.Account + masterAccount, derivedAccounts, err = generator.CreateAndDeriveAccountsFromMnemonic(mnemonic, paths, "") + if err != nil { + return + } + + dbKeypair, err := m.persistence.GetKeypairByKeyUID(masterAccount.KeyUID()) + if err != nil { + if err != types.ErrDbKeypairNotFound { + return + } + } + if dbKeypair != nil { + err = ErrKeypairAlreadyAdded.WithContext("keyuid", masterAccount.KeyUID()) + return + } + + keypairType := types.KeypairTypeSeed + // make sure the keystore is created for the profile keypair + if profile { + keypairType = types.KeypairTypeProfile + + var keystore keystore.KeyStore + keystore, err = m.createKeystore(masterAccount.KeyUID()) + if err != nil { + return + } + m.setKeystore(keystore) + } + + // prepare keypair + keypair, err = m.prepareKeypair(masterAccount, derivedAccounts, keypairName, walletAccount, keypairType, profile, clock) + if err != nil { + return + } + + // store keypair to db + err = m.persistence.SaveOrUpdateKeypair(keypair) + if err != nil { + return + } + + // store accounts to keystore + err = m.storeKeystoreFilesForAccounts(masterAccount, derivedAccounts, password) + if err != nil { + return + } + + // set the chat account if it's a profile keypair + if profile { + chatDerivedAccount, ok := derivedAccounts[common.PathEIP1581Chat] + if !ok { + return nil, ErrChatAccountNotFoundInDerivedAccounts + } + m.setChatAccountAndProfileKeyUID(chatDerivedAccount, masterAccount.KeyUID()) + } + + return +} + +func (m *AccountsManager) AddKeypairStoredToKeycard(keyUID string, masterAddress string, name string, + walletAccounts []*types.Account, clock uint64) (keypair *types.Keypair, err error) { + + if len(walletAccounts) == 0 { + err = ErrKeypairMustHaveAtLeastOneWalletAccount + return + } + + for _, walletAccount := range walletAccounts { + if !strings.HasPrefix(walletAccount.Path, common.WalletPath) { + err = ErrUnsupportedWalletAccountPath. + WithContext("path", walletAccount.Path). + WithContext("expected path", common.WalletPath) + return + } + } + + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + var dbKeypair *types.Keypair + dbKeypair, err = m.persistence.GetKeypairByKeyUID(keyUID) + if err != nil { + if err != types.ErrDbKeypairNotFound { + return + } + } + if dbKeypair != nil { + err = ErrKeypairAlreadyAdded.WithContext("keyuid", keyUID) + return + } + + // prepare keypair + keypair = &types.Keypair{ + Name: name, + KeyUID: keyUID, + Type: types.KeypairTypeSeed, + DerivedFrom: masterAddress, + LastUsedDerivationIndex: 0, + Clock: clock, + Accounts: walletAccounts, + } + + // store keypair to db + err = m.persistence.SaveOrUpdateKeypair(keypair) + + return +} + +func (m *AccountsManager) prepareKeypair(account *generator.Account, derivedAccounts map[string]*generator.Account, keypairName string, + walletAccount *types.AccountCreationDetails, keypairType types.KeypairType, profile bool, clock uint64) (*types.Keypair, error) { + // set up keypair + keypair := &types.Keypair{ + Name: keypairName, + KeyUID: account.KeyUID(), + Type: keypairType, + DerivedFrom: account.Address().Hex(), + LastUsedDerivationIndex: 0, + Clock: clock, + } + + // add chat account + chatDerivedAccount, ok := derivedAccounts[common.PathEIP1581Chat] + if ok { + keypair.Accounts = append(keypair.Accounts, &types.Account{ + PublicKey: cryptotypes.Hex2Bytes(chatDerivedAccount.PublicKeyHex()), + KeyUID: keypair.KeyUID, + Address: chatDerivedAccount.Address(), + Chat: profile, + Path: common.PathEIP1581Chat, + AddressWasNotShown: true, + Position: -1, + Operable: types.AccountFullyOperable, + }) + } + + position, err := m.persistence.GetPositionForNextNewAccount() + if err != nil { + return nil, err + } + + // add wallet accounts + walletDerivedAccount, ok := derivedAccounts[walletAccount.Path] + if ok { + keypair.Accounts = append(keypair.Accounts, &types.Account{ + PublicKey: cryptotypes.Hex2Bytes(walletDerivedAccount.PublicKeyHex()), + KeyUID: keypair.KeyUID, + Address: walletDerivedAccount.Address(), + ColorID: walletAccount.ColorID, + Emoji: walletAccount.Emoji, + Wallet: profile, // default wallet account makes sense only for profile keypair + Path: walletAccount.Path, + Name: walletAccount.Name, + AddressWasNotShown: true, + Position: position, + Operable: types.AccountFullyOperable, + }) + } + + if keypairType == types.KeypairTypeKey { + keypair.DerivedFrom = "" + + keypair.Accounts = append(keypair.Accounts, &types.Account{ + PublicKey: cryptotypes.Hex2Bytes(account.PublicKeyHex()), + KeyUID: keypair.KeyUID, + Address: account.Address(), + ColorID: walletAccount.ColorID, + Emoji: walletAccount.Emoji, + Path: common.PathMaster, + Name: walletAccount.Name, + AddressWasNotShown: true, + Position: position, + Operable: types.AccountFullyOperable, + }) + } + + return keypair, nil +} + +// CreateKeypairFromPrivateKeyAndStore creates a keypair with a single master account. +func (m *AccountsManager) CreateKeypairFromPrivateKeyAndStore(privateKey string, password string, keypairName string, + walletAccount *types.AccountCreationDetails, clock uint64) (keypair *types.Keypair, err error) { + if walletAccount == nil { + err = ErrKeypairDoesNotHaveWalletAccount + return + } + + if walletAccount.Path != common.PathMaster { + err = ErrUnsupportedWalletAccountPath. + WithContext("path", walletAccount.Path). + WithContext("expected path", common.PathMaster) + return + } + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + masterAccount, err := generator.CreateAccountFromPrivateKey(privateKey) + if err != nil { + return nil, err + } + + dbKeypair, err := m.persistence.GetKeypairByKeyUID(masterAccount.KeyUID()) + if err != nil { + if err != types.ErrDbKeypairNotFound { + return + } + } + if dbKeypair != nil { + err = ErrKeypairAlreadyAdded.WithContext("keyuid", masterAccount.KeyUID()) + return + } + + // prepare keypair + keypair, err = m.prepareKeypair(masterAccount, nil, keypairName, walletAccount, types.KeypairTypeKey, false, clock) + if err != nil { + return nil, err + } + + // store keypair to db + err = m.persistence.SaveOrUpdateKeypair(keypair) + if err != nil { + return + } + + // store the accounts to keystore, cause private key imported keypairs cannot be migrated to keycard + err = m.storeKeystoreFilesForAccounts(masterAccount, nil, password) + if err != nil { + return + } + + return keypair, nil +} + +// MakeSeedPhraseKeypairFullyOperable checks if corresponding keypair exists in db and if yes, creates the keystore files +// for the keypair and associated accounts and marks the keypair as fully operable +func (m *AccountsManager) MakeSeedPhraseKeypairFullyOperable(mnemonic string, password string, clock uint64) (string, error) { + acc, err := generator.CreateAccountFromMnemonic(mnemonic, "") + if err != nil { + return "", err + } + + keyUID := acc.KeyUID() + + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return "", ErrPersistenceMissing + } + + kp, err := m.persistence.GetKeypairByKeyUID(keyUID) + if err != nil { + return "", err + } + + var paths []string + for _, acc := range kp.Accounts { + paths = append(paths, acc.Path) + } + + _, _, err = m.storeKeystoreFilesForMnemonicInternally(mnemonic, password, paths) + if err != nil { + return "", err + } + + return keyUID, m.persistence.MarkKeypairFullyOperable(keyUID, clock, true) +} + +// MakePrivateKeyKeypairFullyOperable checks if corresponding keypair exists in db and if yes, creates the keystore file for the keypair +func (m *AccountsManager) MakePrivateKeyKeypairFullyOperable(privateKey string, password string, clock uint64) (string, error) { + acc, err := generator.CreateAccountFromPrivateKey(privateKey) + if err != nil { + return "", err + } + + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return "", ErrPersistenceMissing + } + + kp, err := m.persistence.GetKeypairByKeyUID(acc.KeyUID()) + if err != nil { + return "", err + } + + _, err = m.storeKeystoreFilesForPrivateKeyInternally(privateKey, password) + if err != nil { + return "", err + } + + return kp.KeyUID, m.persistence.MarkKeypairFullyOperable(kp.KeyUID, clock, true) +} + +func (m *AccountsManager) MakePartiallyOperableAccoutsFullyOperable(password string) (addresses []cryptotypes.Address, err error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + keypairs, err := m.persistence.GetActiveKeypairs() + if err != nil { + return + } + + for _, kp := range keypairs { + if kp.MigratedToKeycard() { + continue + } + + for _, acc := range kp.Accounts { + if acc.Operable != types.AccountPartiallyOperable { + continue + } + _, err = m.deriveChildAccountForPathAndStore(cryptotypes.HexToAddress(kp.DerivedFrom), acc.Path, password) + if err != nil { + return + } + err = m.persistence.MarkAccountFullyOperable(acc.Address) + if err != nil { + return + } + addresses = append(addresses, acc.Address) + } + } + return +} + +func (m *AccountsManager) AddAccounts(keyUID string, accounts []*types.Account, password string) error { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return ErrPersistenceMissing + } + + kp, err := m.persistence.GetKeypairByKeyUID(keyUID) + if err != nil { + return err + } + + if kp.Type == types.KeypairTypeKey { + return ErrCannotAddAccountsToKeypairImportedViaPrivateKey + } + + if !kp.MigratedToKeycard() { + for _, acc := range accounts { + if acc.KeyUID != keyUID { + return ErrAccountMismatch. + WithContext("keyuid", acc.KeyUID). + WithContext("expected keyuid", keyUID) + } + + if kp.Type == types.KeypairTypeProfile { + if acc.Chat { + return ErrCannotAddDefaultChatAccount + } + if acc.Wallet { + return ErrCannotAddDefaultWalletAccount + } + } + + for _, kpAcc := range kp.Accounts { + if acc.Address == kpAcc.Address { + return ErrAccountAlreadyAdded + } + } + + childAccount, err := m.deriveChildAccountForPath(cryptotypes.HexToAddress(kp.DerivedFrom), acc.Path, password) + if err != nil { + return err + } + + if childAccount.Address() != acc.Address { + return ErrAccountMismatch. + WithContext("address", acc.Address.Hex()). + WithContext("derived address", childAccount.Address().Hex()) + } + } + } + + err = m.persistence.SaveOrUpdateAccounts(accounts, true) + if err != nil { + return err + } + + if !kp.MigratedToKeycard() { + for _, acc := range accounts { + _, err := m.deriveChildAccountForPathAndStore(cryptotypes.HexToAddress(kp.DerivedFrom), acc.Path, password) + if err != nil { + return err + } + } + } + + return nil +} + +func (m *AccountsManager) RemoveAccounts(keyUID string, accounts []*types.Account) error { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return ErrPersistenceMissing + } + + kp, err := m.persistence.GetKeypairByKeyUID(keyUID) + if err != nil { + return err + } + + if !kp.MigratedToKeycard() { + for _, acc := range accounts { + err = m.deleteAccountFromKeystore(acc.Address) + if err != nil { + return err + } + } + } + + return m.persistence.SaveOrUpdateAccounts(accounts, true) + +} + +func (m *AccountsManager) MigrateNonProfileKeycardKeypairToApp(mnemonic string, password string, clock uint64) (string, error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return "", ErrPersistenceMissing + } + + acc, err := generator.CreateAccountFromMnemonic(mnemonic, "") + if err != nil { + return "", err + } + + kp, err := m.persistence.GetKeypairByKeyUID(acc.KeyUID()) + if err != nil { + return "", err + } + + if kp.Type == types.KeypairTypeProfile { + return "", ErrCannotMigrateProfileKeypair + } + + if !kp.MigratedToKeycard() { + return "", ErrKeypairIsNotKeycard + } + + profileKeypair, err := m.persistence.GetProfileKeypair() + if err != nil { + return "", err + } + + if !profileKeypair.MigratedToKeycard() { + _, err = m.loadAccountInternally(cryptotypes.HexToAddress(profileKeypair.DerivedFrom), password) + if err != nil { + return "", ErrWrongPasswordProvided(err) + } + } + + var paths []string + for _, acc := range kp.Accounts { + paths = append(paths, acc.Path) + } + + _, _, err = m.storeKeystoreFilesForMnemonicInternally(mnemonic, password, paths) + if err != nil { + return "", err + } + + return kp.KeyUID, m.persistence.DeleteAllKeycardsWithKeyUID(kp.KeyUID, clock) +} + +// SaveOrUpdateKeycard saves or updates a keycard and its accounts +// If `removeKeystoreFiles` is true, then corresponding keystore files will be deleted if keypair is not already migrated. +// In case of migration to a keycard, corresponding keystore files need to be deleted if the keypair being migrated is not already migrated. +func (m *AccountsManager) SaveOrUpdateKeycard(keycard *types.Keycard, clock uint64, removeKeystoreFiles bool) error { + if len(keycard.AccountsAddresses) == 0 { + return ErrKeycardDoesNotHaveAnyAccounts + } + + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return ErrPersistenceMissing + } + + kpDb, err := m.persistence.GetKeypairByKeyUID(keycard.KeyUID) + if err != nil { + return ErrKeycardDoesNotRelateToAnyKeypair(err) + } + + err = m.persistence.SaveOrUpdateKeycard(keycard, clock, true) + if err != nil { + return err + } + + if removeKeystoreFiles { + // Once we migrate a keypair, corresponding keystore files need to be deleted + // if the keypair being migrated is not already migrated (in case user is creating a copy of an existing Keycard) + // and if keypair operability is different from non operable (otherwise there are not keystore files to be deleted). + if !kpDb.MigratedToKeycard() && kpDb.Operability() != types.AccountNonOperable { + for _, acc := range kpDb.Accounts { + if acc.Operable != types.AccountFullyOperable { + continue + } + err = m.deleteAccountFromKeystore(acc.Address) + if err != nil { + return err + } + } + + err = m.deleteAccountFromKeystore(cryptotypes.HexToAddress(kpDb.DerivedFrom)) + if err != nil { + return err + } + } + + err = m.persistence.MarkKeypairFullyOperable(keycard.KeyUID, clock, true) + if err != nil { + return err + } + } + + return nil +} + +func (m *AccountsManager) DeleteAccount(address cryptotypes.Address, clock uint64) (account *types.Account, err error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + account, err = m.persistence.GetAccountByAddress(address) + if err != nil { + return + } + + if account.Chat { + err = ErrCannotRemoveDefaultChatAccount + return + } + + if account.Wallet { + err = ErrCannotRemoveDefaultWalletAccount + return + } + + err = m.deleteKeystoreFileForAccountInternally(address) + if err != nil { + return + } + + err = m.persistence.RemoveAccount(address, clock) + return +} + +func (m *AccountsManager) DeleteKeypair(keyUID string, clock uint64) (keypair *types.Keypair, err error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.persistence == nil { + return nil, ErrPersistenceMissing + } + + keypair, err = m.persistence.GetKeypairByKeyUID(keyUID) + if err != nil { + return + } + + if keypair.Type == types.KeypairTypeProfile { + err = ErrCannotRemoveProfileKeypair + return + } + + err = m.deleteKeystoreFilesForKeypairInternally(keypair) + if err != nil { + return + } + + err = m.persistence.RemoveKeypair(keyUID, clock) + return +} diff --git a/accounts-management/errors/errors.go b/accounts-management/errors/errors.go new file mode 100644 index 0000000000..d75ab53200 --- /dev/null +++ b/accounts-management/errors/errors.go @@ -0,0 +1,81 @@ +package errors + +import ( + "errors" + "fmt" +) + +type ErrorCode int + +type ErrorCategory string + +const ( + ErrorCategoryUnknown ErrorCategory = "unknown" +) + +type AccountsError struct { + Code ErrorCode + Category ErrorCategory + Message string + Err error + Context map[string]interface{} +} + +// NewError creates a new AccountsError with the given code and message +func NewError(code ErrorCode, message string, getErrorCategory func(code ErrorCode) ErrorCategory) *AccountsError { + category := ErrorCategoryUnknown + if getErrorCategory != nil { + category = getErrorCategory(code) + } + return &AccountsError{ + Code: code, + Category: category, + Message: message, + } +} + +// WrapError wraps an existing error with additional context +func WrapError(code ErrorCode, message string, err error, getErrorCategory func(code ErrorCode) ErrorCategory) *AccountsError { + accountsErr := NewError(code, message, getErrorCategory) + accountsErr.Err = err + return accountsErr +} + +// WithContext adds additional context to the error +func (e *AccountsError) WithContext(key string, value interface{}) *AccountsError { + if e.Context == nil { + e.Context = make(map[string]interface{}) + } + e.Context[key] = value + return e +} + +// Error implements the error interface +func (e *AccountsError) Error() string { + if e.Err != nil { + return fmt.Sprintf("[%s] %s: %v", e.Category, e.Message, e.Err) + } + if e.Context != nil { + message := "" + for k, v := range e.Context { + message += fmt.Sprintf(" %s: %v", k, v) + } + return fmt.Sprintf("[%s] %s - %s", e.Category, e.Message, message) + } + return fmt.Sprintf("[%s] %s", e.Category, e.Message) +} + +// Is checks if the error matches a specific error code +func (e *AccountsError) Is(target error) bool { + if target == nil { + return false + } + + // Check if target is an AccountsError with the same code + var targetAccountsErr *AccountsError + if errors.As(target, &targetAccountsErr) { + return e.Code == targetAccountsErr.Code && e.Category == targetAccountsErr.Category + } + + return false +} diff --git a/accounts-management/errors/errors_test.go b/accounts-management/errors/errors_test.go new file mode 100644 index 0000000000..d2d30d55ca --- /dev/null +++ b/accounts-management/errors/errors_test.go @@ -0,0 +1,102 @@ +package errors + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAccountsError_Error(t *testing.T) { + tests := []struct { + name string + err *AccountsError + expected string + }{ + { + name: "simple error without underlying error", + err: NewError(ErrCode1, "message 1", getErrorCategoryTest), + expected: "[1] message 1", + }, + { + name: "error with underlying error", + err: NewError(ErrCode2, "message 2", getErrorCategoryTest), + expected: "[2] message 2", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, tt.err.Error()) + }) + } +} + +func TestAccountsError_Is(t *testing.T) { + err1 := NewError(ErrCode1, "message 1", getErrorCategoryTest) + err2 := NewError(ErrCode1, "different message", getErrorCategoryTest) + err3 := NewError(ErrCode2, "message 2", getErrorCategoryTest) + + assert.True(t, err1.Is(err2), "errors with same code should match") + assert.False(t, err1.Is(err3), "errors with different codes should not match") +} + +func TestAccountsError_WithContext(t *testing.T) { + err := NewError(ErrCode1, "invalid address", getErrorCategoryTest) + err = err.WithContext("address", "0x123") + err = err.WithContext("reason", "checksum failed") + + assert.Equal(t, "0x123", err.Context["address"]) + assert.Equal(t, "checksum failed", err.Context["reason"]) +} + +func TestErrorCode_Categories(t *testing.T) { + tests := []struct { + code ErrorCode + expected ErrorCategory + }{ + {ErrCode1, ErrorCategory1}, + {ErrCode2, ErrorCategory2}, + {ErrCode3, ErrorCategory3}, + {ErrCode4, ErrorCategory4}, + } + + for _, tt := range tests { + t.Run(string(tt.expected), func(t *testing.T) { + err := NewError(tt.code, "test error", getErrorCategoryTest) + assert.Equal(t, tt.expected, err.Category) + }) + } +} + +func TestHelperFunctions(t *testing.T) { + t.Run("Err3", func(t *testing.T) { + err := Err3("0x123", "0x456") + + assert.Equal(t, ErrCode3, err.Code) + assert.Equal(t, ErrorCategory3, err.Category) + assert.Equal(t, "0x123", err.Context["arg"]) + assert.Equal(t, "0x456", err.Context["arg2"]) + }) + t.Run("Err4", func(t *testing.T) { + underlyingErr := errors.New("crypto error") + err := Err4(underlyingErr) + + assert.Equal(t, ErrCode4, err.Code) + assert.Equal(t, ErrorCategory4, err.Category) + assert.Equal(t, underlyingErr, err.Err) + }) +} + +func TestErrorComparison(t *testing.T) { + err1 := NewError(ErrCode1, "message 1", getErrorCategoryTest) + err2 := NewError(ErrCode1, "different message", getErrorCategoryTest) + err3 := NewError(ErrCode2, "message 2", getErrorCategoryTest) + + assert.True(t, errors.Is(err1, err2)) + assert.False(t, errors.Is(err1, err3)) + + assert.Equal(t, ErrCode1, err1.Code) + assert.Equal(t, ErrCode1, err2.Code) + assert.Equal(t, ErrCode2, err3.Code) +} diff --git a/accounts-management/errors/errors_test_data.go b/accounts-management/errors/errors_test_data.go new file mode 100644 index 0000000000..0c24b3b295 --- /dev/null +++ b/accounts-management/errors/errors_test_data.go @@ -0,0 +1,38 @@ +package errors + +const ( + ErrorCategory1 ErrorCategory = "1" + ErrorCategory2 ErrorCategory = "2" + ErrorCategory3 ErrorCategory = "3" + ErrorCategory4 ErrorCategory = "4" +) + +const ( + ErrCode1 ErrorCode = iota + 1 + ErrCode2 + ErrCode3 + ErrCode4 +) + +// Common errors +func Err3(arg string, arg2 string) *AccountsError { + return NewError(ErrCode3, "error 3 message", getErrorCategoryTest).WithContext("arg", arg).WithContext("arg2", arg2) +} + +func Err4(err error) *AccountsError { + return WrapError(ErrCode4, "error 4 message", err, getErrorCategoryTest) +} + +func getErrorCategoryTest(code ErrorCode) ErrorCategory { + switch code { + case ErrCode1: + return ErrorCategory1 + case ErrCode2: + return ErrorCategory2 + case ErrCode3: + return ErrorCategory3 + case ErrCode4: + return ErrorCategory4 + } + return ErrorCategoryUnknown +} diff --git a/accounts-management/generator/README.md b/accounts-management/generator/README.md new file mode 100644 index 0000000000..34e8369520 --- /dev/null +++ b/accounts-management/generator/README.md @@ -0,0 +1,34 @@ +# Account Generator + +The Account Generator package provides functionality for creating and deriving Ethereum accounts. It offers several ways to create accounts and derive child keys from them. + +## Account Creation + +The generator provides three main ways to create accounts: + +1. **From Mnemonic**: Using `CreateAccountFromMnemonic(mnemonic, bip39Passphrase)` to create an account from a mnemonic phrase. +2. **From Private Key**: Using `CreateAccountFromPrivateKey(privateKeyHex)` to create an account from a private key. +3. **From Key**: Using `CreateAccountFromKey(key)` to create an account from an existing key. + +For batch account creation, you can use `CreateAccountsOfMnemonicLength(mnemonicPhraseLength, n, bip39Passphrase)` which returns both the created accounts and their corresponding mnemonic phrases. + +## Account Derivation + +The package provides functionality to derive child accounts from existing accounts: + +1. **Single Derivation**: Using `DeriveChildFromAccount(account, pathString)` to derive a single child account at a specified path. +2. **Multiple Derivations**: Using `DeriveChildrenFromAccount(account, pathStrings)` to derive multiple child accounts at different paths. + +The derivation paths follow the BIP44 standard format (e.g., "m/44'/60'/0'/0/0"). + +## Account Types + +The package defines several types for working with accounts: + +- `Account`: Represents an Ethereum account with a private key and optional extended key. +- `AccountInfo`: Contains basic account information (private key, public key, address). +- `IdentifiedAccountInfo`: Extends AccountInfo with KeyUID. +- `GeneratedAccountInfo`: Extends IdentifiedAccountInfo with a mnemonic phrase. +- `GeneratedAndDerivedAccountInfo`: Extends GeneratedAccountInfo with derived accounts. + +Note: This package is focused on account creation and derivation. For account storage and management, please refer to the main account package. \ No newline at end of file diff --git a/accounts-management/generator/errors.go b/accounts-management/generator/errors.go new file mode 100644 index 0000000000..1f0a43dd75 --- /dev/null +++ b/accounts-management/generator/errors.go @@ -0,0 +1,81 @@ +package generator + +import "github.com/status-im/status-go/accounts-management/errors" + +const ( + ErrorCategoryGenerator errors.ErrorCategory = "generator" +) + +const ( + ErrCodeInvalidKeystoreExtendedKey errors.ErrorCode = iota + 1 + ErrCodeMnemonicCreationFailed + ErrCodeAccountCreationFromMnemonicFailed + ErrCodeAccountCreationFromPrivateKeyFailed + ErrCodeAccountCreationFromKeyFailed + ErrCodePathDecodingFailed + ErrCodeZeroedExtendedKey + ErrCodeExtendedKeyDerivationFailed + ErrCodeChildAccountDerivationFailed + ErrCodePathParsingFailed + ErrCodeInvalidDerivationIndex + ErrCodeUnexpectedToken + ErrCodeUnexpectedEOF +) + +var ( + ErrInvalidKeystoreExtendedKey = errors.NewError(ErrCodeInvalidKeystoreExtendedKey, "PrivateKey and ExtendedKey are different", getErrorCategory) + ErrZeroedExtendedKey = errors.NewError(ErrCodeZeroedExtendedKey, "can not derive child account from zeroed extended key", getErrorCategory) + ErrPathParsingFailed = errors.NewError(ErrCodePathParsingFailed, "error parsing derivation path", getErrorCategory) + ErrInvalidDerivationIndex = errors.NewError(ErrCodeInvalidDerivationIndex, "index must be lower than 2^31", getErrorCategory) + ErrUnexpectedToken = errors.NewError(ErrCodeUnexpectedToken, "unexpected token in derivation path", getErrorCategory) + ErrUnexpectedEOF = errors.NewError(ErrCodeUnexpectedEOF, "unexpected end of derivation path", getErrorCategory) +) + +func ErrMnemonicCreationFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeMnemonicCreationFailed, "failed to create mnemonic seed", err, getErrorCategory) +} + +func ErrAccountCreationFromMnemonicFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeAccountCreationFromMnemonicFailed, "can not create account from mnemonic", err, getErrorCategory) +} + +func ErrAccountCreationFromPrivateKeyFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeAccountCreationFromPrivateKeyFailed, "can not create account from private key", err, getErrorCategory) +} + +func ErrAccountCreationFromKeyFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeAccountCreationFromKeyFailed, "can not create account from key", err, getErrorCategory) +} + +func ErrPathDecodingFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodePathDecodingFailed, "can not decode path", err, getErrorCategory) +} + +func ErrExtendedKeyDerivationFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeExtendedKeyDerivationFailed, "can not derive child account from extended key", err, getErrorCategory) +} + +func ErrChildAccountDerivationFailed(err error) *errors.AccountsError { + return errors.WrapError(ErrCodeChildAccountDerivationFailed, "can not derive child account from path", err, getErrorCategory) +} + +func getErrorCategory(code errors.ErrorCode) errors.ErrorCategory { + switch code { + case ErrCodeInvalidKeystoreExtendedKey, + ErrCodeMnemonicCreationFailed, + ErrCodeAccountCreationFromMnemonicFailed, + ErrCodeAccountCreationFromPrivateKeyFailed, + ErrCodeAccountCreationFromKeyFailed, + ErrCodePathDecodingFailed, + ErrCodeZeroedExtendedKey, + ErrCodeExtendedKeyDerivationFailed, + ErrCodeChildAccountDerivationFailed, + ErrCodePathParsingFailed, + ErrCodeInvalidDerivationIndex, + ErrCodeUnexpectedToken, + ErrCodeUnexpectedEOF: + return ErrorCategoryGenerator + default: + return errors.ErrorCategoryUnknown + } +} diff --git a/accounts-management/generator/generator.go b/accounts-management/generator/generator.go new file mode 100644 index 0000000000..b06190f19e --- /dev/null +++ b/accounts-management/generator/generator.go @@ -0,0 +1,116 @@ +package generator + +import ( + "strings" + + "github.com/status-im/status-go/accounts-management/common" + "github.com/status-im/status-go/accounts-management/types" + "github.com/status-im/status-go/crypto" +) + +// CreateAccountFromMnemonic creates an account from a mnemonic phrase. +func CreateAccountFromMnemonic(mnemonicPhrase string, bip39Passphrase string) (*Account, error) { + masterExtendedKey, err := common.CreateExtendedKeyFromMnemonic(mnemonicPhrase, bip39Passphrase) + if err != nil { + return nil, ErrAccountCreationFromMnemonicFailed(err) + } + + return NewAccount(masterExtendedKey.ToECDSA(), masterExtendedKey), nil +} + +// CreateAccountFromPrivateKey creates an account from a private key. +func CreateAccountFromPrivateKey(privateKeyHex string) (*Account, error) { + privateKeyWithoutPrefix := strings.TrimPrefix(privateKeyHex, "0x") + privateKey, err := crypto.HexToECDSA(privateKeyWithoutPrefix) + if err != nil { + return nil, ErrAccountCreationFromPrivateKeyFailed(err) + } + + return NewAccount(privateKey, nil), nil +} + +// CreateAccountFromKey creates an account from a key. +func CreateAccountFromKey(key *types.Key) (*Account, error) { + account := NewAccount(key.PrivateKey, key.ExtendedKey) + if err := account.ValidateExtendedKey(); err != nil { + return nil, ErrAccountCreationFromKeyFailed(err) + } + return account, nil +} + +// CreateAccountsOfMnemonicLength creates n accounts from a mnemonic phrase of length mnemonicPhraseLength. +// It returns the accounts and the mnemonic phrases, the order matches. +func CreateAccountsOfMnemonicLength(mnemonicPhraseLength int, n int, bip39Passphrase string) ([]*Account, []string, error) { + accounts := make([]*Account, 0) + mnemonicPhrases := make([]string, 0) + + for i := 0; i < n; i++ { + mnemonicPhrase, err := common.CreateRandomMnemonic(mnemonicPhraseLength) + if err != nil { + return nil, nil, ErrMnemonicCreationFailed(err) + } + + acc, err := CreateAccountFromMnemonic(mnemonicPhrase, bip39Passphrase) + if err != nil { + return nil, nil, ErrAccountCreationFromMnemonicFailed(err) + } + + accounts = append(accounts, acc) + mnemonicPhrases = append(mnemonicPhrases, mnemonicPhrase) + } + + return accounts, mnemonicPhrases, nil +} + +// DeriveChildFromAccount derives a child account from an account. +func DeriveChildFromAccount(acc *Account, pathString string) (*Account, error) { + _, path, err := decodePath(pathString) + if err != nil { + return nil, ErrPathDecodingFailed(err) + } + + if acc.extendedKey.IsZeroed() && len(path) == 0 { + return acc, nil + } + + if acc.extendedKey.IsZeroed() { + return nil, ErrZeroedExtendedKey + } + + childExtendedKey, err := acc.extendedKey.Derive(path) + if err != nil { + return nil, ErrExtendedKeyDerivationFailed(err) + } + + return NewAccount(childExtendedKey.ToECDSA(), childExtendedKey), nil +} + +// DeriveChildrenFromAccount derives multiple child accounts from an account. +func DeriveChildrenFromAccount(acc *Account, pathStrings []string) (map[string]*Account, error) { + pathAccounts := make(map[string]*Account) + + for _, pathString := range pathStrings { + childAccount, err := DeriveChildFromAccount(acc, pathString) + if err != nil { + return pathAccounts, ErrChildAccountDerivationFailed(err) + } + + pathAccounts[pathString] = childAccount + } + + return pathAccounts, nil +} + +func CreateAndDeriveAccountsFromMnemonic(mnemonic string, paths []string, bip39Passphrase string) (*Account, map[string]*Account, error) { + account, err := CreateAccountFromMnemonic(mnemonic, bip39Passphrase) + if err != nil { + return nil, nil, err + } + + derivedAccounts, err := DeriveChildrenFromAccount(account, paths) + if err != nil { + return nil, nil, err + } + + return account, derivedAccounts, nil +} diff --git a/accounts-management/generator/generator_test.go b/accounts-management/generator/generator_test.go new file mode 100644 index 0000000000..185371d7f9 --- /dev/null +++ b/accounts-management/generator/generator_test.go @@ -0,0 +1,159 @@ +package generator + +import ( + "strings" + "testing" + + "github.com/status-im/extkeys" + + "github.com/stretchr/testify/assert" + + "github.com/status-im/status-go/accounts-management/types" +) + +type testAccount struct { + path string + privateKey string + publicKey string + address string + keyUID string +} + +var testData = struct { + mnemonic string + bip39Passphrase string + encriptionPassword string + extendedMasterKey string + + masterAccount testAccount + childAccount0 testAccount + childAccount1 testAccount +}{ + mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + bip39Passphrase: "TREZOR", + encriptionPassword: "TEST_PASSWORD", + extendedMasterKey: "xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF", + masterAccount: testAccount{ + path: "m", + privateKey: "0xcbedc75b0d6412c85c79bc13875112ef912fd1e756631b5a00330866f22ff184", + publicKey: "0x04f632717d78bf73e74aa8461e2e782532abae4eed5110241025afb59ebfd3d2fd55dcbc97ce588a492a152798460f89dfeacf266b3cb544bf216ec1e3e3c766e0", + address: "0xd7FDc6389223c747de571b22C2860B6b1CE9643a", + keyUID: "0x6b33d8b321bedcccd9bb3eeda0383c9ee49437fec19452e3b87f4efe36e57c70", + }, + childAccount0: testAccount{ + path: "m/44'/60'/0'/0/0", + privateKey: "0x62f1d86b246c81bdd8f6c166d56896a4a5e1eddbcaebe06480e5c0bc74c28224", + publicKey: "0x04986dee3b8afe24cb8ccb2ac23dac3f8c43d22850d14b809b26d6b8aa5a1f47784152cd2c7d9edd0ab20392a837464b5a750b2a7f3f06e6a5756b5211b6a6ed05", + address: "0x9c32F71D4DB8Fb9e1A58B0a80dF79935e7256FA6", + keyUID: "0x06d6639c5b0fb5465d80e97efe9288b0b046223fc33b054c1083946a21f49315", + }, + childAccount1: testAccount{ + path: "m/44'/60'/0'/0/1", + privateKey: "0x49ee230b1605382ac1c40079191bca937fc30e8c2fa845b7de27a96ffcc4ddbf", + publicKey: "0x04462e7b95dab24fe8a57ac897d9026545ec4327c9c5e4a772e5d14cc5422f94896d222a9e8880e41562c41e8290b842679d33c450bb5329caa3f078fbdf9e639d", + address: "0x7AF7283bd1462C3b957e8FAc28Dc19cBbF2FAdfe", + keyUID: "0x5bd1c31af7a92087f76fa0def8ded5277d4d69b0aa4f4a4352912f4026aa68c3", + }, +} + +func createKey(t *testing.T, seedPhrase string, bip39Passphrase string) *types.Key { + mnemonic := extkeys.NewMnemonic() + seed := mnemonic.MnemonicSeed(seedPhrase, bip39Passphrase) + + masterKey, err := extkeys.NewMaster(seed) + assert.NoError(t, err) + + return &types.Key{ + PrivateKey: masterKey.ToECDSA(), + ExtendedKey: masterKey, + } +} + +func TestGenerator_CreateAccountFromMnemonic(t *testing.T) { + acc, err := CreateAccountFromMnemonic(testData.mnemonic, testData.bip39Passphrase) + assert.NoError(t, err) + assert.Equal(t, testData.extendedMasterKey, acc.extendedKey.String()) + + info := acc.ToIdentifiedAccountInfo() + assert.Equal(t, testData.masterAccount.keyUID, info.KeyUID) + assert.Equal(t, testData.masterAccount.address, info.Address) + assert.Equal(t, testData.masterAccount.publicKey, info.PublicKey) + assert.Equal(t, testData.masterAccount.privateKey, info.PrivateKey) +} +func TestGenerator_CreateAccountFromPrivateKey(t *testing.T) { + acc, err := CreateAccountFromPrivateKey(testData.masterAccount.privateKey) + assert.NoError(t, err) + + info := acc.ToIdentifiedAccountInfo() + assert.Equal(t, testData.masterAccount.keyUID, info.KeyUID) + assert.Equal(t, testData.masterAccount.address, info.Address) + assert.Equal(t, testData.masterAccount.publicKey, info.PublicKey) + assert.Equal(t, testData.masterAccount.privateKey, info.PrivateKey) +} + +func TestGenerator_CreateAccountFromKey(t *testing.T) { + key := createKey(t, testData.mnemonic, testData.bip39Passphrase) + + acc, err := CreateAccountFromKey(key) + assert.NoError(t, err) + assert.Equal(t, key.ExtendedKey.String(), acc.extendedKey.String()) + + info := acc.ToIdentifiedAccountInfo() + assert.Equal(t, testData.masterAccount.keyUID, info.KeyUID) + assert.Equal(t, testData.masterAccount.address, info.Address) + assert.Equal(t, testData.masterAccount.publicKey, info.PublicKey) + assert.Equal(t, testData.masterAccount.privateKey, info.PrivateKey) +} + +func TestGenerator_CreateAccountsOfMnemonicLength(t *testing.T) { + accounts, mnemonicPhrases, err := CreateAccountsOfMnemonicLength(12, 5, "") + assert.NoError(t, err) + assert.Equal(t, 5, len(accounts)) + assert.Equal(t, len(accounts), len(mnemonicPhrases)) + + for i, acc := range accounts { + info := acc.ToGeneratedAccountInfo(mnemonicPhrases[i]) + words := strings.Split(info.Mnemonic, " ") + assert.Equal(t, 12, len(words)) + } +} + +func TestGenerator_DeriveChildFromAccount(t *testing.T) { + acc, err := CreateAccountFromMnemonic(testData.mnemonic, testData.bip39Passphrase) + assert.NoError(t, err) + + child, err := DeriveChildFromAccount(acc, testData.childAccount0.path) + assert.NoError(t, err) + + info := child.ToIdentifiedAccountInfo() + + assert.Equal(t, testData.childAccount0.keyUID, info.KeyUID) + assert.Equal(t, testData.childAccount0.address, info.Address) + assert.Equal(t, testData.childAccount0.publicKey, info.PublicKey) + assert.Equal(t, testData.childAccount0.privateKey, info.PrivateKey) +} + +func TestGenerator_DeriveChildrenFromAccount(t *testing.T) { + acc, err := CreateAccountFromMnemonic(testData.mnemonic, testData.bip39Passphrase) + assert.NoError(t, err) + + children, err := DeriveChildrenFromAccount(acc, []string{testData.masterAccount.path, testData.childAccount0.path, testData.childAccount1.path}) + assert.NoError(t, err) + + assert.Equal(t, 3, len(children)) + + assert.Equal(t, testData.masterAccount.keyUID, children[testData.masterAccount.path].ToIdentifiedAccountInfo().KeyUID) + assert.Equal(t, testData.masterAccount.address, children[testData.masterAccount.path].ToIdentifiedAccountInfo().Address) + assert.Equal(t, testData.masterAccount.publicKey, children[testData.masterAccount.path].ToIdentifiedAccountInfo().PublicKey) + assert.Equal(t, testData.masterAccount.privateKey, children[testData.masterAccount.path].ToIdentifiedAccountInfo().PrivateKey) + + assert.Equal(t, testData.childAccount0.keyUID, children[testData.childAccount0.path].ToIdentifiedAccountInfo().KeyUID) + assert.Equal(t, testData.childAccount0.address, children[testData.childAccount0.path].ToIdentifiedAccountInfo().Address) + assert.Equal(t, testData.childAccount0.publicKey, children[testData.childAccount0.path].ToIdentifiedAccountInfo().PublicKey) + assert.Equal(t, testData.childAccount0.privateKey, children[testData.childAccount0.path].ToIdentifiedAccountInfo().PrivateKey) + + assert.Equal(t, testData.childAccount1.keyUID, children[testData.childAccount1.path].ToIdentifiedAccountInfo().KeyUID) + assert.Equal(t, testData.childAccount1.address, children[testData.childAccount1.path].ToIdentifiedAccountInfo().Address) + assert.Equal(t, testData.childAccount1.publicKey, children[testData.childAccount1.path].ToIdentifiedAccountInfo().PublicKey) + assert.Equal(t, testData.childAccount1.privateKey, children[testData.childAccount1.path].ToIdentifiedAccountInfo().PrivateKey) +} diff --git a/accounts-management/generator/path_decoder.go b/accounts-management/generator/path_decoder.go new file mode 100644 index 0000000000..34f75c8cf2 --- /dev/null +++ b/accounts-management/generator/path_decoder.go @@ -0,0 +1,229 @@ +package generator + +import ( + "fmt" + "io" + "strconv" + "strings" +) + +type startingPoint int + +const ( + tokenMaster = 0x6D // char m + tokenSeparator = 0x2F // char / + tokenHardened = 0x27 // char ' + tokenDot = 0x2E // char . + + hardenedStart = 0x80000000 // 2^31 +) + +const ( + startingPointMaster startingPoint = iota + 1 + startingPointCurrent + startingPointParent +) + +type parseFunc = func() error + +type pathDecoder struct { + s string + r *strings.Reader + f parseFunc + pos int + path []uint32 + start startingPoint + currentToken string + currentTokenHardened bool +} + +func newPathDecoder(path string) (*pathDecoder, error) { + d := &pathDecoder{ + s: path, + r: strings.NewReader(path), + } + + if err := d.reset(); err != nil { + return nil, err + } + + return d, nil +} + +func (d *pathDecoder) reset() error { + _, err := d.r.Seek(0, io.SeekStart) + if err != nil { + return err + } + + d.pos = 0 + d.start = startingPointCurrent + d.f = d.parseStart + d.path = make([]uint32, 0) + d.resetCurrentToken() + + return nil +} + +func (d *pathDecoder) resetCurrentToken() { + d.currentToken = "" + d.currentTokenHardened = false +} + +func (d *pathDecoder) parse() (startingPoint, []uint32, error) { + for { + err := d.f() + if err != nil { + if err == io.EOF { + err = nil + } else { + err = ErrPathParsingFailed. + WithContext("path", d.s). + WithContext("position", d.pos). + WithContext("error", err.Error()) + } + + return d.start, d.path, err + } + } +} + +func (d *pathDecoder) readByte() (byte, error) { + b, err := d.r.ReadByte() + if err != nil { + return b, err + } + + d.pos++ + + return b, nil +} + +func (d *pathDecoder) unreadByte() error { + err := d.r.UnreadByte() + if err != nil { + return err + } + + d.pos-- + + return nil +} + +func (d *pathDecoder) parseStart() error { + b, err := d.readByte() + if err != nil { + return err + } + + if b == tokenMaster { + d.start = startingPointMaster + d.f = d.parseSeparator + return nil + } + + if b == tokenDot { + b2, err := d.readByte() + if err != nil { + return err + } + + if b2 == tokenDot { + d.f = d.parseSeparator + d.start = startingPointParent + return nil + } + + d.f = d.parseSeparator + d.start = startingPointCurrent + return d.unreadByte() + } + + d.f = d.parseSegment + + return d.unreadByte() +} + +func (d *pathDecoder) saveSegment() error { + if len(d.currentToken) > 0 { + i, err := strconv.ParseUint(d.currentToken, 10, 32) + if err != nil { + return err + } + + if i >= hardenedStart { + d.pos -= len(d.currentToken) - 1 + return ErrInvalidDerivationIndex.WithContext("index", i) + } + + if d.currentTokenHardened { + i += hardenedStart + } + + d.path = append(d.path, uint32(i)) + } + + d.f = d.parseSegment + d.resetCurrentToken() + + return nil +} + +func (d *pathDecoder) parseSeparator() error { + b, err := d.readByte() + if err != nil { + return err + } + + if b == tokenSeparator { + return d.saveSegment() + } + + return ErrUnexpectedToken.WithContext("expected", string(rune(tokenSeparator))).WithContext("got", string(rune(b))) +} + +func (d *pathDecoder) parseSegment() error { + b, err := d.readByte() + if err == io.EOF { + if len(d.currentToken) == 0 { + return ErrUnexpectedEOF + } + + if newErr := d.saveSegment(); newErr != nil { + return newErr + } + + return err + } + + if err != nil { + return err + } + + if len(d.currentToken) > 0 && b == tokenSeparator { + return d.saveSegment() + } + + if len(d.currentToken) > 0 && b == tokenHardened { + d.currentTokenHardened = true + d.f = d.parseSeparator + return nil + } + + if b < 0x30 || b > 0x39 { + return ErrUnexpectedToken.WithContext("expected", "number").WithContext("got", string(b)) + } + + d.currentToken = fmt.Sprintf("%s%s", d.currentToken, string(b)) + + return nil +} + +func decodePath(str string) (startingPoint, []uint32, error) { + d, err := newPathDecoder(str) + if err != nil { + return 0, nil, err + } + + return d.parse() +} diff --git a/accounts-management/generator/path_decoder_test.go b/accounts-management/generator/path_decoder_test.go new file mode 100644 index 0000000000..115ba7b1bc --- /dev/null +++ b/accounts-management/generator/path_decoder_test.go @@ -0,0 +1,106 @@ +package generator + +import ( + "errors" + "fmt" + "testing" + + customerrors "github.com/status-im/status-go/accounts-management/errors" + + "github.com/stretchr/testify/assert" +) + +func TestDecodePath(t *testing.T) { + scenarios := []struct { + path string + expectedPath []uint32 + expectedStartingPoint startingPoint + err error + }{ + { + path: "", + expectedPath: []uint32{}, + expectedStartingPoint: startingPointCurrent, + }, + { + path: "1", + expectedPath: []uint32{1}, + expectedStartingPoint: startingPointCurrent, + }, + { + path: "..", + expectedPath: []uint32{}, + expectedStartingPoint: startingPointParent, + }, + { + path: "m", + expectedPath: []uint32{}, + expectedStartingPoint: startingPointMaster, + }, + { + path: "m/1", + expectedPath: []uint32{1}, + expectedStartingPoint: startingPointMaster, + }, + { + path: "m/1/2", + expectedPath: []uint32{1, 2}, + expectedStartingPoint: startingPointMaster, + }, + { + path: "m/1/2'/3", + expectedPath: []uint32{1, 2147483650, 3}, + expectedStartingPoint: startingPointMaster, + }, + { + path: "m/", + err: fmt.Errorf("error parsing derivation path m/; at position 2, expected number, got EOF"), + }, + { + path: "m/1//2", + err: fmt.Errorf("error parsing derivation path m/1//2; at position 5, expected number, got /"), + }, + { + path: "m/1'2", + err: fmt.Errorf("error parsing derivation path m/1'2; at position 5, expected /, got 2"), + }, + { + path: "m/'/2", + err: fmt.Errorf("error parsing derivation path m/'/2; at position 3, expected number, got '"), + }, + { + path: "m/2147483648", + err: fmt.Errorf("error parsing derivation path m/2147483648; at position 3, index must be lower than 2^31, got 2147483648"), + }, + } + + for i, s := range scenarios { + t.Run(fmt.Sprintf("scenario %d", i), func(t *testing.T) { + startingP, path, err := decodePath(s.path) + if s.err == nil { + assert.NoError(t, err) + assert.Equal(t, s.expectedStartingPoint, startingP) + assert.Equal(t, s.expectedPath, path) + } else { + if !assert.Error(t, err) { + return + } + + var accountsErr *customerrors.AccountsError + if errors.As(err, &accountsErr) { + assert.Equal(t, ErrCodePathParsingFailed, accountsErr.Code) + assert.Equal(t, ErrorCategoryGenerator, accountsErr.Category) + + if path, ok := accountsErr.Context["path"]; ok { + assert.Equal(t, s.path, path) + } + if position, ok := accountsErr.Context["position"]; ok { + assert.IsType(t, 0, position) + } + } else { + assert.Equal(t, s.err, err) + } + } + }) + } +} diff --git a/accounts-management/generator/types.go b/accounts-management/generator/types.go new file mode 100644 index 0000000000..9abe6aa53c --- /dev/null +++ b/accounts-management/generator/types.go @@ -0,0 +1,214 @@ +package generator + +import ( + "bytes" + "crypto/ecdsa" + "crypto/sha256" + "encoding/json" + + "github.com/status-im/extkeys" + + "github.com/status-im/status-go/accounts-management/common" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" +) + +type Account struct { + privateKey *ecdsa.PrivateKey + extendedKey *extkeys.ExtendedKey +} + +func NewAccount(privateKey *ecdsa.PrivateKey, extKey *extkeys.ExtendedKey) *Account { + if privateKey == nil && extKey != nil { + privateKey = extKey.ToECDSA() + } + + return &Account{ + privateKey: privateKey, + extendedKey: extKey, + } +} + +func (a *Account) ExtendedKey() *extkeys.ExtendedKey { + return a.extendedKey +} + +func (a *Account) PrivateKey() *ecdsa.PrivateKey { + return a.privateKey +} + +func (a *Account) PrivateKeyHex() string { + return types.EncodeHex(crypto.FromECDSA(a.privateKey)) +} + +func (a *Account) PublicKey() *ecdsa.PublicKey { + return &a.privateKey.PublicKey +} + +func (a *Account) PublicKeyHex() string { + if a.privateKey == nil { + return "" + } + return types.EncodeHex(crypto.FromECDSAPub(&a.privateKey.PublicKey)) +} + +func (a *Account) Address() types.Address { + if a.privateKey == nil { + return types.Address{} + } + return crypto.PubkeyToAddress(a.privateKey.PublicKey) +} + +func (a *Account) HasExtendedKey() bool { + return a.extendedKey != nil && !a.extendedKey.IsZeroed() +} + +func (a *Account) KeyUID() string { + if a.privateKey == nil { + return "" + } + keyUID := sha256.Sum256(crypto.FromECDSAPub(&a.privateKey.PublicKey)) + return types.EncodeHex(keyUID[:]) +} + +func (a *Account) ToAccountInfo() AccountInfo { + if a.privateKey == nil { + return AccountInfo{} + } + privateKeyHex := types.EncodeHex(crypto.FromECDSA(a.privateKey)) + publicKeyHex := types.EncodeHex(crypto.FromECDSAPub(&a.privateKey.PublicKey)) + addressHex := crypto.PubkeyToAddress(a.privateKey.PublicKey).Hex() + + return AccountInfo{ + PrivateKey: privateKeyHex, + PublicKey: publicKeyHex, + Address: addressHex, + } +} + +func (a *Account) ToIdentifiedAccountInfo() IdentifiedAccountInfo { + if a.privateKey == nil { + return IdentifiedAccountInfo{} + } + info := a.ToAccountInfo() + keyUID := sha256.Sum256(crypto.FromECDSAPub(&a.privateKey.PublicKey)) + keyUIDHex := types.EncodeHex(keyUID[:]) + return IdentifiedAccountInfo{ + AccountInfo: info, + KeyUID: keyUIDHex, + } +} + +func (a *Account) ToGeneratedAccountInfo(mnemonic string) GeneratedAccountInfo { + idInfo := a.ToIdentifiedAccountInfo() + return GeneratedAccountInfo{ + IdentifiedAccountInfo: idInfo, + Mnemonic: mnemonic, + } +} + +// ValidateExtendedKey validates the keystore keys, checking that ExtendedKey is the extended key of PrivateKey +func (a *Account) ValidateExtendedKey() error { + if a.extendedKey == nil || a.extendedKey.IsZeroed() { + return nil + } + + privKey := crypto.FromECDSA(a.privateKey) + extKey := crypto.FromECDSA(a.extendedKey.ToECDSA()) + if !bytes.Equal(privKey, extKey) { + return ErrInvalidKeystoreExtendedKey + } + + return nil +} + +type AccountInfo struct { + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` + Address string `json:"address"` +} + +func (a AccountInfo) MarshalJSON() ([]byte, error) { + type Alias AccountInfo + ext, err := common.ExtendStructWithPubKeyData(a.PublicKey, Alias(a)) + if err != nil { + return nil, err + } + return json.Marshal(ext) +} + +type IdentifiedAccountInfo struct { + AccountInfo + KeyUID string `json:"keyUid"` +} + +func (a *IdentifiedAccountInfo) ToGeneratedAccountInfo(mnemonic string) GeneratedAccountInfo { + return GeneratedAccountInfo{ + IdentifiedAccountInfo: *a, + Mnemonic: mnemonic, + } +} + +func (i IdentifiedAccountInfo) MarshalJSON() ([]byte, error) { + accountInfoJSON, err := i.AccountInfo.MarshalJSON() + if err != nil { + return nil, err + } + type info struct { + KeyUID string `json:"keyUid"` + } + infoJSON, err := json.Marshal(info{ + KeyUID: i.KeyUID, + }) + if err != nil { + return nil, err + } + infoJSON[0] = ',' + return append(accountInfoJSON[:len(accountInfoJSON)-1], infoJSON...), nil +} + +type GeneratedAccountInfo struct { + IdentifiedAccountInfo + Mnemonic string `json:"mnemonic"` +} + +func (g GeneratedAccountInfo) MarshalJSON() ([]byte, error) { + accountInfoJSON, err := g.IdentifiedAccountInfo.MarshalJSON() + if err != nil { + return nil, err + } + type info struct { + Mnemonic string `json:"mnemonic"` + } + infoJSON, err := json.Marshal(info{ + Mnemonic: g.Mnemonic, + }) + if err != nil { + return nil, err + } + infoJSON[0] = ',' + return append(accountInfoJSON[:len(accountInfoJSON)-1], infoJSON...), nil +} + +type GeneratedAndDerivedAccountInfo struct { + GeneratedAccountInfo + Derived map[string]AccountInfo `json:"derived"` +} + +func (g GeneratedAndDerivedAccountInfo) MarshalJSON() ([]byte, error) { + accountInfoJSON, err := g.GeneratedAccountInfo.MarshalJSON() + if err != nil { + return nil, err + } + type info struct { + Derived map[string]AccountInfo `json:"derived"` + } + infoJSON, err := json.Marshal(info{ + Derived: g.Derived, + }) + if err != nil { + return nil, err + } + infoJSON[0] = ',' + return append(accountInfoJSON[:len(accountInfoJSON)-1], infoJSON...), nil +} diff --git a/accounts-management/generator/types_test.go b/accounts-management/generator/types_test.go new file mode 100644 index 0000000000..1c51c7b599 --- /dev/null +++ b/accounts-management/generator/types_test.go @@ -0,0 +1,68 @@ +package generator + +import ( + "testing" + + "github.com/status-im/extkeys" + "github.com/stretchr/testify/assert" + + "github.com/status-im/status-go/accounts-management/common" +) + +func generateTestKey(t *testing.T) *Account { + mnemonic, err := common.CreateRandomMnemonicWithDefaultLength() + assert.NoError(t, err) + + extendedKey, err := common.CreateExtendedKeyFromMnemonic(mnemonic, "") + assert.NoError(t, err) + + return NewAccount(extendedKey.ToECDSA(), extendedKey) +} + +func TestValidateExtendedKey(t *testing.T) { + acc1 := generateTestKey(t) + acc2 := generateTestKey(t) + + // Create a valid account + validAccount := NewAccount(acc1.PrivateKey(), acc1.ExtendedKey()) + + // Create an invalid account with different private key + invalidAccount := NewAccount(acc1.PrivateKey(), acc2.ExtendedKey()) + + // Create a zeroed account + zeroedAccount := NewAccount(acc1.PrivateKey(), &extkeys.ExtendedKey{}) + + tests := []struct { + name string + account *Account + expectError bool + }{ + { + name: "valid account", + account: validAccount, + expectError: false, + }, + { + name: "invalid account", + account: invalidAccount, + expectError: true, + }, + { + name: "zeroed account", + account: zeroedAccount, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.account.ValidateExtendedKey() + if tt.expectError { + assert.Error(t, err) + assert.Equal(t, ErrInvalidKeystoreExtendedKey, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/accounts-management/keystore/geth/adapter.go b/accounts-management/keystore/geth/adapter.go new file mode 100644 index 0000000000..ad743e0ec9 --- /dev/null +++ b/accounts-management/keystore/geth/adapter.go @@ -0,0 +1,191 @@ +package geth + +import ( + "crypto/ecdsa" + "errors" + "os" + + "github.com/status-im/extkeys" + + "github.com/ethereum/go-ethereum/accounts" + gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/status-im/status-go/accounts-management/keystore" + "github.com/status-im/status-go/accounts-management/keystore/types" + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +// Adapter implements the KeyStore interface using go-ethereum +type Adapter struct { + keystoreDir string + scryptN int + scryptP int + keystore *gethkeystore.KeyStore +} + +func NewGethKeystoreAdapter(keystoreDir string) (*Adapter, error) { + var ( + keydir = keystoreDir + err error + ) + if keydir == "" { + keydir, err = os.MkdirTemp("", "go-ethereum-keystore") + if err != nil { + return nil, err + } + } + + if err = os.MkdirAll(keydir, 0700); err != nil { + return nil, err + } + + adapter := &Adapter{ + keystoreDir: keydir, + scryptN: gethkeystore.LightScryptN, + scryptP: gethkeystore.LightScryptP, + } + + ks := gethkeystore.NewKeyStore(keydir, adapter.scryptN, adapter.scryptP) + adapter.keystore = ks + + return adapter, nil +} + +func mapToKeystoreError(err error) error { + if errors.Is(err, gethkeystore.ErrNoMatch) { + return keystore.ErrNoMatch + } + if errors.Is(err, gethkeystore.ErrDecrypt) { + return keystore.ErrDecrypt + } + return err +} + +// ImportECDSA imports an ECDSA private key +func (a *Adapter) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (account types.KeystoreAccount, err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + var gethAccount accounts.Account + gethAccount, err = a.keystore.ImportECDSA(priv, passphrase) + if err != nil { + return + } + + account = keystoreAccountFrom(gethAccount) + return +} + +// ImportSingleExtendedKey imports an extended key by converting it to ECDSA private key +func (a *Adapter) ImportSingleExtendedKey(extKey *extkeys.ExtendedKey, passphrase string) (account types.KeystoreAccount, err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + privateKey := extKey.ToECDSA() + address := crypto.PubkeyToAddress(privateKey.PublicKey) + account, err = a.Find(address) + if err == nil { + return + } + + account, err = a.updateKeystoreFile(privateKey, extKey, a.scryptN, a.scryptP, passphrase) + return +} + +// AccountDecryptedKey gets the decrypted key for an account using standard go-ethereum functions +func (a *Adapter) AccountDecryptedKey(address cryptotypes.Address, passphrase string) (account types.KeystoreAccount, privateKey *ecdsa.PrivateKey, extendedKey *extkeys.ExtendedKey, err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + var gethAccount accounts.Account + gethAccount, err = a.find(address) + if err != nil { + return + } + + ethKey, err := readKeystoreFileAndDecryptedKey(gethAccount.URL.Path, passphrase) + if err != nil { + return + } + + account = keystoreAccountFrom(gethAccount) + privateKey = ethKey.PrivateKey + extendedKey = ethKey.ExtendedKey + return +} + +func (a *Adapter) Delete(address cryptotypes.Address) (err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + var gethAccount accounts.Account + gethAccount, err = a.find(address) + if err != nil { + return + } + + // TODO: think about how to use `Delete` method from `keystore` package, not from our fork + // this is the only that depends on our fork for the account management part of the app. + err = a.keystore.Delete(gethAccount) + return +} + +func (a *Adapter) Accounts() []types.KeystoreAccount { + gethAccounts := a.keystore.Accounts() + accounts := make([]types.KeystoreAccount, len(gethAccounts)) + for i, acc := range gethAccounts { + accounts[i] = keystoreAccountFrom(acc) + } + return accounts +} + +func (a *Adapter) Find(address cryptotypes.Address) (account types.KeystoreAccount, err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + var gethAccount accounts.Account + gethAccount, err = a.find(address) + if err != nil { + return + } + + account = keystoreAccountFrom(gethAccount) + return +} + +func (a *Adapter) ReEncryptKeyStoreDir(oldPass, newPass string) (err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + err = reEncryptKeyStoreDir(a.keystoreDir, oldPass, newPass) + return +} + +func (a *Adapter) MigrateKeyStoreDir(newDir string) (err error) { + defer func() { + err = mapToKeystoreError(err) + }() + + addresses := a.Accounts() + addressesStr := make([]string, len(addresses)) + for i, address := range addresses { + addressesStr[i] = address.Address.Hex() + } + + err = migrateKeyStoreDir(a.keystoreDir, newDir, addressesStr) + if err != nil { + return err + } + a.keystoreDir = newDir + return nil +} + +func (a *Adapter) KeystorePath() string { + return a.keystoreDir +} diff --git a/accounts-management/keystore/geth/const.go b/accounts-management/keystore/geth/const.go new file mode 100644 index 0000000000..9b32f51670 --- /dev/null +++ b/accounts-management/keystore/geth/const.go @@ -0,0 +1,7 @@ +// Imported from github.com/ethereum/go-ethereum/accounts/keystore/keystore.go + +package geth + +const ( + version = 3 +) diff --git a/accounts-management/keystore/geth/decryption.go b/accounts-management/keystore/geth/decryption.go new file mode 100644 index 0000000000..2dbee3149d --- /dev/null +++ b/accounts-management/keystore/geth/decryption.go @@ -0,0 +1,367 @@ +// Imported from github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go +// and github.com/ethereum/go-ethereum/accounts/keystore/presale.go + +package geth + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + + "github.com/google/uuid" + "golang.org/x/crypto/pbkdf2" + "golang.org/x/crypto/scrypt" + + "github.com/status-im/extkeys" + + "github.com/status-im/status-go/accounts-management/keystore" + "github.com/status-im/status-go/accounts-management/types" + "github.com/status-im/status-go/crypto" +) + +const ( + keyHeaderKDF = "scrypt" + + scryptR = 8 + scryptDKLen = 32 +) + +type EncryptedKeyJSONV3 struct { + Address string `json:"address"` + Crypto CryptoJSON `json:"crypto"` + Id string `json:"id"` + Version int `json:"version"` + ExtendedKey CryptoJSON `json:"extendedkey"` + SubAccountIndex uint32 `json:"subaccountindex"` +} + +type encryptedKeyJSONV1 struct { + Address string `json:"address"` + Crypto CryptoJSON `json:"crypto"` + Id string `json:"id"` + Version string `json:"version"` +} + +type CryptoJSON struct { + Cipher string `json:"cipher"` + CipherText string `json:"ciphertext"` + CipherParams cipherparamsJSON `json:"cipherparams"` + KDF string `json:"kdf"` + KDFParams map[string]interface{} `json:"kdfparams"` + MAC string `json:"mac"` +} + +type encryptedKeyJSONV3 struct { + Address string `json:"address"` + Crypto CryptoJSON `json:"crypto"` + Id string `json:"id"` + Version int `json:"version"` + ExtendedKey CryptoJSON `json:"extendedkey"` + SubAccountIndex uint32 `json:"subaccountindex"` +} + +type cipherparamsJSON struct { + IV string `json:"iv"` +} + +// DecryptKey decrypts a key from a json blob, returning the private key itself. +func DecryptKey(keyjson []byte, auth string) (*types.Key, error) { + // Parse the json into a simple map to fetch the key version + m := make(map[string]interface{}) + if err := json.Unmarshal(keyjson, &m); err != nil { + return nil, err + } + // Depending on the version try to parse one way or another + var ( + keyBytes, keyId []byte + err error + extKeyBytes []byte + extKey *extkeys.ExtendedKey + ) + + subAccountIndex, ok := m["subaccountindex"].(float64) + if !ok { + subAccountIndex = 0 + } + + if version, ok := m["version"].(string); ok && version == "1" { + k := new(encryptedKeyJSONV1) + if err := json.Unmarshal(keyjson, k); err != nil { + return nil, err + } + keyBytes, keyId, err = decryptKeyV1(k, auth) + if err != nil { + return nil, err + } + + extKey, err = extkeys.NewKeyFromString(extkeys.EmptyExtendedKeyString) + } else { + k := new(EncryptedKeyJSONV3) + if err := json.Unmarshal(keyjson, k); err != nil { + return nil, err + } + keyBytes, keyId, err = decryptKeyV3(k, auth) + if err != nil { + return nil, err + } + + extKeyBytes, err = decryptExtendedKey(k, auth) + if err != nil { + return nil, err + } + extKey, err = extkeys.NewKeyFromString(string(extKeyBytes)) + } + // Handle any decryption errors and return the key + if err != nil { + return nil, err + } + key := crypto.ToECDSAUnsafe(keyBytes) + + id, err := uuid.FromBytes(keyId) + if err != nil { + return nil, err + } + + return &types.Key{ + ID: id, + Address: crypto.PubkeyToAddress(key.PublicKey), + PrivateKey: key, + ExtendedKey: extKey, + SubAccountIndex: uint32(subAccountIndex), + }, nil +} + +func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) { + if cryptoJson.Cipher != "aes-128-ctr" { + return nil, fmt.Errorf("Cipher not supported: %v", cryptoJson.Cipher) + } + mac, err := hex.DecodeString(cryptoJson.MAC) + if err != nil { + return nil, err + } + + iv, err := hex.DecodeString(cryptoJson.CipherParams.IV) + if err != nil { + return nil, err + } + + cipherText, err := hex.DecodeString(cryptoJson.CipherText) + if err != nil { + return nil, err + } + + derivedKey, err := getKDFKey(cryptoJson, auth) + if err != nil { + return nil, err + } + + calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) + if !bytes.Equal(calculatedMAC, mac) { + return nil, keystore.ErrDecrypt + } + + plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) + if err != nil { + return nil, err + } + return plainText, err +} + +func decryptKeyV3(keyProtected *EncryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { + if keyProtected.Version != version { + return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) + } + id, err := uuid.Parse(keyProtected.Id) + if err != nil { + return nil, nil, err + } + keyId = id[:] + plainText, err := DecryptDataV3(keyProtected.Crypto, auth) + if err != nil { + return nil, nil, err + } + return plainText, keyId, err +} + +func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { + id, err := uuid.Parse(keyProtected.Id) + if err != nil { + return nil, nil, err + } + keyId = id[:] + + mac, err := hex.DecodeString(keyProtected.Crypto.MAC) + if err != nil { + return nil, nil, err + } + + iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) + if err != nil { + return nil, nil, err + } + + cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) + if err != nil { + return nil, nil, err + } + + derivedKey, err := getKDFKey(keyProtected.Crypto, auth) + if err != nil { + return nil, nil, err + } + + calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) + if !bytes.Equal(calculatedMAC, mac) { + return nil, nil, keystore.ErrDecrypt + } + + plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) + if err != nil { + return nil, nil, err + } + return plainText, keyId, err +} + +func decryptExtendedKey(keyProtected *EncryptedKeyJSONV3, auth string) (plainText []byte, err error) { + if len(keyProtected.ExtendedKey.CipherText) == 0 { + return []byte(extkeys.EmptyExtendedKeyString), nil + } + + if keyProtected.Version != version { + return nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) + } + + if keyProtected.ExtendedKey.Cipher != "aes-128-ctr" { + return nil, fmt.Errorf("Cipher not supported: %v", keyProtected.ExtendedKey.Cipher) + } + + mac, err := hex.DecodeString(keyProtected.ExtendedKey.MAC) + if err != nil { + return nil, err + } + + iv, err := hex.DecodeString(keyProtected.ExtendedKey.CipherParams.IV) + if err != nil { + return nil, err + } + + cipherText, err := hex.DecodeString(keyProtected.ExtendedKey.CipherText) + if err != nil { + return nil, err + } + + derivedKey, err := getKDFKey(keyProtected.ExtendedKey, auth) + if err != nil { + return nil, err + } + + calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) + if !bytes.Equal(calculatedMAC, mac) { + return nil, keystore.ErrDecrypt + } + + plainText, err = aesCTRXOR(derivedKey[:16], cipherText, iv) + if err != nil { + return nil, err + } + return plainText, err +} + +func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) { + authArray := []byte(auth) + salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) + if err != nil { + return nil, err + } + dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) + + if cryptoJSON.KDF == keyHeaderKDF { + n := ensureInt(cryptoJSON.KDFParams["n"]) + r := ensureInt(cryptoJSON.KDFParams["r"]) + p := ensureInt(cryptoJSON.KDFParams["p"]) + return scrypt.Key(authArray, salt, n, r, p, dkLen) + + } else if cryptoJSON.KDF == "pbkdf2" { + c := ensureInt(cryptoJSON.KDFParams["c"]) + prf := cryptoJSON.KDFParams["prf"].(string) + if prf != "hmac-sha256" { + return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) + } + key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) + return key, nil + } + + return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) +} + +// TODO: can we do without this when unmarshalling dynamic JSON? +// why do integers in KDF params end up as float64 and not int after +// unmarshal? +func ensureInt(x interface{}) int { + res, ok := x.(int) + if !ok { + res = int(x.(float64)) + } + return res +} + +func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { + // AES-128 is selected due to size of encryptKey. + aesBlock, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + stream := cipher.NewCTR(aesBlock, iv) + outText := make([]byte, len(inText)) + stream.XORKeyStream(outText, inText) + return outText, err +} + +func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) { + aesBlock, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + decrypter := cipher.NewCBCDecrypter(aesBlock, iv) + paddedPlaintext := make([]byte, len(cipherText)) + decrypter.CryptBlocks(paddedPlaintext, cipherText) + plaintext := pkcs7Unpad(paddedPlaintext) + if plaintext == nil { + return nil, keystore.ErrDecrypt + } + return plaintext, err +} + +// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes +func pkcs7Unpad(in []byte) []byte { + if len(in) == 0 { + return nil + } + + padding := in[len(in)-1] + if int(padding) > len(in) || padding > aes.BlockSize { + return nil + } else if padding == 0 { + return nil + } + + for i := len(in) - 1; i > len(in)-int(padding)-1; i-- { + if in[i] != padding { + return nil + } + } + return in[:len(in)-int(padding)] +} + +func RawKeyToCryptoJSON(rawKeyFile []byte) (cj CryptoJSON, e error) { + var keyJSON EncryptedKeyJSONV3 + if e := json.Unmarshal(rawKeyFile, &keyJSON); e != nil { + return cj, fmt.Errorf("failed to read key file: %s", e) + } + + return keyJSON.Crypto, e +} diff --git a/accounts-management/keystore/geth/encryption.go b/accounts-management/keystore/geth/encryption.go new file mode 100644 index 0000000000..c30c458a5e --- /dev/null +++ b/accounts-management/keystore/geth/encryption.go @@ -0,0 +1,133 @@ +// Imported from github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go +// and github.com/ethereum/go-ethereum/accounts/keystore/presale.go + +package geth + +import ( + "crypto/aes" + "crypto/rand" + "encoding/hex" + "encoding/json" + "io" + + "golang.org/x/crypto/scrypt" + + "github.com/status-im/extkeys" + + "github.com/ethereum/go-ethereum/common/math" + "github.com/status-im/status-go/accounts-management/types" + "github.com/status-im/status-go/crypto" +) + +// Encryptdata encrypts the data given as 'data' with the password 'auth'. +func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) { + salt := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, salt); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + derivedKey, err := scrypt.Key(auth, salt, scryptN, scryptR, scryptP, scryptDKLen) + if err != nil { + return CryptoJSON{}, err + } + encryptKey := derivedKey[:16] + + iv := make([]byte, aes.BlockSize) // 16 + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + cipherText, err := aesCTRXOR(encryptKey, data, iv) + if err != nil { + return CryptoJSON{}, err + } + mac := crypto.Keccak256(derivedKey[16:32], cipherText) + + scryptParamsJSON := make(map[string]interface{}, 5) + scryptParamsJSON["n"] = scryptN + scryptParamsJSON["r"] = scryptR + scryptParamsJSON["p"] = scryptP + scryptParamsJSON["dklen"] = scryptDKLen + scryptParamsJSON["salt"] = hex.EncodeToString(salt) + cipherParamsJSON := cipherparamsJSON{ + IV: hex.EncodeToString(iv), + } + + cryptoStruct := CryptoJSON{ + Cipher: "aes-128-ctr", + CipherText: hex.EncodeToString(cipherText), + CipherParams: cipherParamsJSON, + KDF: keyHeaderKDF, + KDFParams: scryptParamsJSON, + MAC: hex.EncodeToString(mac), + } + return cryptoStruct, nil +} + +// EncryptKey encrypts a key using the specified scrypt parameters into a json +// blob that can be decrypted later on. +func EncryptKey(key *types.Key, auth string, scryptN, scryptP int) ([]byte, error) { + keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32) + cryptoStruct, err := EncryptDataV3(keyBytes, []byte(auth), scryptN, scryptP) + if err != nil { + return nil, err + } + encryptedExtendedKey, err := EncryptExtendedKey(key.ExtendedKey, auth, scryptN, scryptP) + if err != nil { + return nil, err + } + encryptedKeyJSONV3 := encryptedKeyJSONV3{ + hex.EncodeToString(key.Address[:]), + cryptoStruct, + key.ID.String(), + version, + encryptedExtendedKey, + key.SubAccountIndex, + } + return json.Marshal(encryptedKeyJSONV3) +} + +func EncryptExtendedKey(extKey *extkeys.ExtendedKey, auth string, scryptN, scryptP int) (CryptoJSON, error) { + if extKey == nil { + return CryptoJSON{}, nil + } + authArray := []byte(auth) + salt := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, salt); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) + if err != nil { + return CryptoJSON{}, err + } + encryptKey := derivedKey[:16] + keyBytes := []byte(extKey.String()) + + iv := make([]byte, aes.BlockSize) // 16 + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) + if err != nil { + return CryptoJSON{}, err + } + mac := crypto.Keccak256(derivedKey[16:32], cipherText) + + scryptParamsJSON := make(map[string]interface{}, 5) + scryptParamsJSON["n"] = scryptN + scryptParamsJSON["r"] = scryptR + scryptParamsJSON["p"] = scryptP + scryptParamsJSON["dklen"] = scryptDKLen + scryptParamsJSON["salt"] = hex.EncodeToString(salt) + + cipherParamsJSON := cipherparamsJSON{ + IV: hex.EncodeToString(iv), + } + + return CryptoJSON{ + Cipher: "aes-128-ctr", + CipherText: hex.EncodeToString(cipherText), + CipherParams: cipherParamsJSON, + KDF: "scrypt", + KDFParams: scryptParamsJSON, + MAC: hex.EncodeToString(mac), + }, nil +} diff --git a/accounts-management/keystore/geth/helper.go b/accounts-management/keystore/geth/helper.go new file mode 100644 index 0000000000..e23bc5f533 --- /dev/null +++ b/accounts-management/keystore/geth/helper.go @@ -0,0 +1,79 @@ +package geth + +import ( + "crypto/ecdsa" + "os" + + "github.com/status-im/extkeys" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + keystoretypes "github.com/status-im/status-go/accounts-management/keystore/types" + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +func (a *Adapter) find(address cryptotypes.Address) (accounts.Account, error) { + gethAccount, err := a.keystore.Find(accounts.Account{ + Address: common.Address(address), + }) + if err != nil { + return accounts.Account{}, err + } + return gethAccount, nil +} + +func keystoreAccountFrom(account accounts.Account) keystoretypes.KeystoreAccount { + return keystoretypes.KeystoreAccount{ + Address: cryptotypes.Address(account.Address), + URL: account.URL.String(), + } +} + +func readKeystoreFileAndDecryptedKey(path string, auth string) (*types.Key, error) { + keyjson, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + return DecryptKey(keyjson, auth) +} + +func encryptKeyAndStoreToKeystoreFile(ethKey *types.Key, path string, scryptN int, scryptP int, passphrase string) error { + key := &types.Key{ + ID: ethKey.ID, + Address: ethKey.Address, + PrivateKey: ethKey.PrivateKey, + ExtendedKey: ethKey.ExtendedKey, + SubAccountIndex: ethKey.SubAccountIndex, + } + + keyjson, err := EncryptKey(key, passphrase, scryptN, scryptP) + if err != nil { + return err + } + + return os.WriteFile(path, keyjson, 0600) +} + +func (a *Adapter) updateKeystoreFile(privateKey *ecdsa.PrivateKey, extKey *extkeys.ExtendedKey, scryptN int, scryptP int, + passphrase string) (keystoretypes.KeystoreAccount, error) { + gethAccount, err := a.keystore.ImportECDSA(privateKey, passphrase) + if err != nil { + return keystoretypes.KeystoreAccount{}, err + } + + ethKey, err := readKeystoreFileAndDecryptedKey(gethAccount.URL.Path, passphrase) + if err != nil { + return keystoretypes.KeystoreAccount{}, err + } + + ethKey.ExtendedKey = extKey + + err = encryptKeyAndStoreToKeystoreFile(ethKey, gethAccount.URL.Path, scryptN, scryptP, passphrase) + if err != nil { + return keystoretypes.KeystoreAccount{}, err + } + + return keystoreAccountFrom(gethAccount), nil +} diff --git a/accounts-management/keystore/geth/migration.go b/accounts-management/keystore/geth/migration.go new file mode 100644 index 0000000000..c04d74df3c --- /dev/null +++ b/accounts-management/keystore/geth/migration.go @@ -0,0 +1,69 @@ +// Imported from github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go +// and github.com/ethereum/go-ethereum/accounts/keystore/presale.go + +package geth + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/status-im/status-go/crypto/types" +) + +func migrateKeyStoreDir(oldDir, newDir string, addresses []string) error { + paths := []string{} + + addressesMap := map[string]struct{}{} + for _, address := range addresses { + addressesMap[address] = struct{}{} + } + + checkFile := func(path string, fileInfo os.FileInfo) error { + if fileInfo.IsDir() || filepath.Dir(path) != oldDir { + return nil + } + + rawKeyFile, err := ioutil.ReadFile(path) + if err != nil { + return fmt.Errorf("invalid account key file: %v", err) + } + + var accountKey struct { + Address string `json:"address"` + } + if err := json.Unmarshal(rawKeyFile, &accountKey); err != nil { + return fmt.Errorf("failed to read key file: %s", err) + } + + address := types.HexToAddress("0x" + accountKey.Address).Hex() + if _, ok := addressesMap[address]; ok { + paths = append(paths, path) + } + + return nil + } + + err := filepath.Walk(oldDir, func(path string, fileInfo os.FileInfo, err error) error { + if err != nil { + return err + } + return checkFile(path, fileInfo) + }) + if err != nil { + return fmt.Errorf("cannot traverse key store folder: %v", err) + } + + for _, path := range paths { + _, fileName := filepath.Split(path) + newPath := filepath.Join(newDir, fileName) + err := os.Rename(path, newPath) + if err != nil { + return err + } + } + + return nil +} diff --git a/accounts-management/keystore/geth/reencryption.go b/accounts-management/keystore/geth/reencryption.go new file mode 100644 index 0000000000..904d905818 --- /dev/null +++ b/accounts-management/keystore/geth/reencryption.go @@ -0,0 +1,127 @@ +// Imported from github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go +// and github.com/ethereum/go-ethereum/accounts/keystore/presale.go + +package geth + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/status-im/status-go/accounts-management/types" +) + +func reEncryptKey(rawKey []byte, pass string, newPass string) (reEncryptedKey []byte, e error) { + cryptoJSON, e := RawKeyToCryptoJSON(rawKey) + if e != nil { + return reEncryptedKey, fmt.Errorf("convert to crypto json error: %v", e) + } + + decryptedKey, e := DecryptKey(rawKey, pass) + if e != nil { + return reEncryptedKey, fmt.Errorf("decryption error: %v", e) + } + + if cryptoJSON.KDFParams["n"] == nil || cryptoJSON.KDFParams["p"] == nil { + return reEncryptedKey, fmt.Errorf("unable to determine `n` or `p`: %v", e) + } + n := int(cryptoJSON.KDFParams["n"].(float64)) + p := int(cryptoJSON.KDFParams["p"].(float64)) + + gethKey := &types.Key{ + ID: decryptedKey.ID, + Address: decryptedKey.Address, + PrivateKey: decryptedKey.PrivateKey, + ExtendedKey: decryptedKey.ExtendedKey, + SubAccountIndex: decryptedKey.SubAccountIndex, + } + + return EncryptKey(gethKey, newPass, n, p) +} + +func reEncryptKeyStoreDir(keyDirPath, oldPass, newPass string) error { + rencryptFileAtPath := func(tempKeyDirPath, path string, fileInfo os.FileInfo) error { + if fileInfo.IsDir() { + return nil + } + + rawKeyFile, e := ioutil.ReadFile(path) + if e != nil { + return fmt.Errorf("invalid account key file: %v", e) + } + + reEncryptedKey, e := reEncryptKey(rawKeyFile, oldPass, newPass) + if e != nil { + return fmt.Errorf("unable to re-encrypt key file: %v, path: %s, name: %s", e, path, fileInfo.Name()) + } + + tempWritePath := filepath.Join(tempKeyDirPath, fileInfo.Name()) + e = ioutil.WriteFile(tempWritePath, reEncryptedKey, fileInfo.Mode().Perm()) + if e != nil { + return fmt.Errorf("unable write key file: %v", e) + } + + return nil + } + + keyDirPath = strings.TrimSuffix(keyDirPath, "/") + keyDirPath = strings.TrimSuffix(keyDirPath, "\\") + keyParent, keyDirName := filepath.Split(keyDirPath) + + // backupKeyDirName used to store existing keys before final write + backupKeyDirName := keyDirName + "-backup" + // tempKeyDirName used to put re-encrypted keys + tempKeyDirName := keyDirName + "-re-encrypted" + backupKeyDirPath := filepath.Join(keyParent, backupKeyDirName) + tempKeyDirPath := filepath.Join(keyParent, tempKeyDirName) + + // create temp key dir + err := os.MkdirAll(tempKeyDirPath, os.ModePerm) + if err != nil { + return fmt.Errorf("mkdirall error: %v, tempKeyDirPath: %s", err, tempKeyDirPath) + } + + err = filepath.Walk(keyDirPath, func(path string, fileInfo os.FileInfo, err error) error { + if err != nil { + os.RemoveAll(tempKeyDirPath) + return fmt.Errorf("walk callback error: %v", err) + } + + return rencryptFileAtPath(tempKeyDirPath, path, fileInfo) + }) + if err != nil { + os.RemoveAll(tempKeyDirPath) + return fmt.Errorf("walk error: %v", err) + } + + // move existing keys + err = os.Rename(keyDirPath, backupKeyDirPath) + if err != nil { + os.RemoveAll(tempKeyDirPath) + return fmt.Errorf("unable to rename keyDirPath to backupKeyDirPath: %v", err) + } + + // move tempKeyDirPath to keyDirPath + err = os.Rename(tempKeyDirPath, keyDirPath) + if err != nil { + // if this happens, then the app is probably bricked, because the keystore won't exist anymore + // try to restore from backup + _ = os.Rename(backupKeyDirPath, keyDirPath) + return fmt.Errorf("unable to rename tempKeyDirPath to keyDirPath: %v", err) + } + + // remove temp and backup folders and their contents + err = os.RemoveAll(tempKeyDirPath) + if err != nil { + return fmt.Errorf("unable to delete tempKeyDirPath, manual cleanup required: %v", err) + } + + err = os.RemoveAll(backupKeyDirPath) + if err != nil { + return fmt.Errorf("unable to delete backupKeyDirPath, manual cleanup required: %v", err) + } + + return nil +} diff --git a/accounts-management/keystore/interface.go b/accounts-management/keystore/interface.go new file mode 100644 index 0000000000..08df3f8583 --- /dev/null +++ b/accounts-management/keystore/interface.go @@ -0,0 +1,41 @@ +package keystore + +import ( + "crypto/ecdsa" + "errors" + + "github.com/status-im/extkeys" + + "github.com/status-im/status-go/accounts-management/keystore/types" + cryptoypes "github.com/status-im/status-go/crypto/types" +) + +var ( + ErrNoMatch = errors.New("no key for given address or file") + ErrDecrypt = errors.New("could not decrypt key with given password") +) + +type KeyStore interface { + // ImportECDSA imports a private key into the keystore + ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (types.KeystoreAccount, error) + // ImportSingleExtendedKey imports an extended key setting it in both the PrivateKey and ExtendedKey fields + // of the Key struct. + // ImportExtendedKey is used in older version of Status where PrivateKey is set to be the BIP44 key at index 0, + // and ExtendedKey is the extended key of the BIP44 key at index 1. + ImportSingleExtendedKey(extKey *extkeys.ExtendedKey, passphrase string) (types.KeystoreAccount, error) + // AccountDecryptedKey returns decrypted key for account (provided that password is correct). + AccountDecryptedKey(address cryptoypes.Address, passphrase string) (types.KeystoreAccount, *ecdsa.PrivateKey, *extkeys.ExtendedKey, error) + // Delete deletes the key matched by account. + // If the account contains no filename, the address must match a unique key. + Delete(address cryptoypes.Address) error + // Find returns the account matched by address + Find(address cryptoypes.Address) (types.KeystoreAccount, error) + // Accounts returns all accounts in the keystore + Accounts() []types.KeystoreAccount + // ReEncryptKeyStoreDir re-encrypts all keys in the keystore directory. + ReEncryptKeyStoreDir(oldPass, newPass string) error + // MigrateKeyStoreDir migrates the keystore directory from one location to another. + MigrateKeyStoreDir(newDir string) error + // KeystorePath returns the path to the keystore directory + KeystorePath() string +} diff --git a/accounts-management/keystore/types/account.go b/accounts-management/keystore/types/account.go new file mode 100644 index 0000000000..544ec70136 --- /dev/null +++ b/accounts-management/keystore/types/account.go @@ -0,0 +1,24 @@ +package types + +import ( + "errors" + + "github.com/status-im/status-go/crypto/types" +) + +var ( + ErrInvalidAddress = errors.New("cannot parse address to valid account address") +) + +type KeystoreAccount struct { + Address types.Address `json:"address"` // Ethereum account address derived from the key + URL string `json:"url"` // Optional resource locator within a backend +} + +// AddressToAccount parses a hex encoded string and returns it as an account +func AddressToAccount(address string) (KeystoreAccount, error) { + if types.IsHexAddress(address) { + return KeystoreAccount{Address: types.HexToAddress(address)}, nil + } + return KeystoreAccount{}, ErrInvalidAddress +} diff --git a/accounts-management/keystore/types/account_test.go b/accounts-management/keystore/types/account_test.go new file mode 100644 index 0000000000..9efb83f7c5 --- /dev/null +++ b/accounts-management/keystore/types/account_test.go @@ -0,0 +1,48 @@ +package types + +import ( + "testing" + + "github.com/status-im/status-go/crypto/types" + + "github.com/stretchr/testify/assert" +) + +func TestAddressToAccount(t *testing.T) { + + tests := []struct { + name string + address string + expectError bool + }{ + { + name: "valid address", + address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + expectError: false, + }, + { + name: "invalid address", + address: "0xinvalid", + expectError: true, + }, + { + name: "empty address", + address: "", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + account, err := AddressToAccount(tt.address) + if tt.expectError { + assert.Error(t, err) + assert.Equal(t, ErrInvalidAddress, err) + assert.Equal(t, KeystoreAccount{}, account) + } else { + assert.NoError(t, err) + assert.Equal(t, types.HexToAddress(tt.address), account.Address) + } + }) + } +} diff --git a/accounts-management/persistence/interface.go b/accounts-management/persistence/interface.go new file mode 100644 index 0000000000..ee754bcb08 --- /dev/null +++ b/accounts-management/persistence/interface.go @@ -0,0 +1,43 @@ +package persistence + +//go:generate mockgen -package=mock_persistence -source=interface.go -destination=../mock/persistence.go + +import ( + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +type Persistence interface { + // AddressExists checks if the address exists in the persistence + AddressExists(address cryptotypes.Address) (bool, error) + // GetProfileKeypair returns the profile keypair + GetProfileKeypair() (*types.Keypair, error) + // GetWalletRootAddress returns the root address of the wallet + GetWalletRootAddress() (cryptotypes.Address, error) + // GetPath returns the derivation path of the address + GetPath(address cryptotypes.Address) (string, error) + // GetKeypairByKeyUID returns a keypair by its keyUID + GetKeypairByKeyUID(keyUID string) (*types.Keypair, error) + // GetActiveKeypairs returns all active keypairs + GetActiveKeypairs() ([]*types.Keypair, error) + // SaveOrUpdateKeypair saves or updates a keypair and its accounts + SaveOrUpdateKeypair(keypair *types.Keypair) error + // SaveOrUpdateAccounts saves or updates accounts + SaveOrUpdateAccounts(accounts []*types.Account, updateKeypairClock bool) error + // SaveOrUpdateKeycard saves or updates a keycard and its accounts + SaveOrUpdateKeycard(keycard *types.Keycard, clock uint64, updateKeypairClock bool) error + // MarkKeypairFullyOperable marks a keypair as fully operable + MarkKeypairFullyOperable(keyUID string, clock uint64, updateKeypairClock bool) (err error) + // MarkAccountFullyOperable marks an account as fully operable + MarkAccountFullyOperable(address cryptotypes.Address) (err error) + // DeleteAllKeycardsWithKeyUID deletes all keycards with a given keyUID + DeleteAllKeycardsWithKeyUID(keyUID string, clock uint64) (err error) + // GetPositionForNextNewAccount returns the position for the next new account + GetPositionForNextNewAccount() (int64, error) + // GetAccountByAddress returns an account by its address + GetAccountByAddress(address cryptotypes.Address) (*types.Account, error) + // RemoveAccount removes an account + RemoveAccount(address cryptotypes.Address, clock uint64) error + // RemoveKeypair removes a keypair + RemoveKeypair(keyUID string, clock uint64) error +} diff --git a/accounts-management/types/key.go b/accounts-management/types/key.go new file mode 100644 index 0000000000..66795b9d5d --- /dev/null +++ b/accounts-management/types/key.go @@ -0,0 +1,36 @@ +package types + +import ( + "crypto/ecdsa" + + "github.com/google/uuid" + + "github.com/status-im/extkeys" + + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +// Key represents a cryptographic key with both private key and extended key +type Key struct { + ID uuid.UUID // Version 4 "random" for unique id not derived from key data + // to simplify lookups we also store the address + Address cryptotypes.Address + // we only store privkey as pubkey/address can be derived from it + // privkey in this struct is always in plaintext + PrivateKey *ecdsa.PrivateKey + // ExtendedKey is the extended key of the PrivateKey itself, and it's used + // to derive child keys. + ExtendedKey *extkeys.ExtendedKey + // Deprecated: SubAccountIndex + // It was use in Status to keep track of the number of sub-account created + // before having multi-account support. + SubAccountIndex uint32 +} + +// NewKey creates a new Key instance +func NewKey(privateKey *ecdsa.PrivateKey, extendedKey *extkeys.ExtendedKey) *Key { + return &Key{ + PrivateKey: privateKey, + ExtendedKey: extendedKey, + } +} diff --git a/accounts-management/types/keypair.go b/accounts-management/types/keypair.go new file mode 100644 index 0000000000..6cdd6148e0 --- /dev/null +++ b/accounts-management/types/keypair.go @@ -0,0 +1,107 @@ +package types + +import ( + "errors" + + "github.com/status-im/status-go/crypto/types" +) + +var ( + ErrDbKeypairNotFound = errors.New("keypair is not found") +) + +type KeypairType string +type AccountType string +type AccountOperable string + +const ( + KeypairTypeProfile KeypairType = "profile" + KeypairTypeKey KeypairType = "key" + KeypairTypeSeed KeypairType = "seed" +) + +const ( + AccountTypeGenerated AccountType = "generated" + AccountTypeKey AccountType = "key" + AccountTypeSeed AccountType = "seed" + AccountTypeWatch AccountType = "watch" +) + +const ( + AccountNonOperable AccountOperable = "no" // an account is non operable it is not a keycard account and there is no keystore file for it and no keystore file for the address it is derived from + AccountPartiallyOperable AccountOperable = "partially" // an account is partially operable if it is not a keycard account and there is created keystore file for the address it is derived from + AccountFullyOperable AccountOperable = "fully" // an account is fully operable if it is not a keycard account and there is a keystore file for it + +) + +type Keypair struct { + KeyUID string `json:"key-uid"` + Name string `json:"name"` + Type KeypairType `json:"type"` + DerivedFrom string `json:"derived-from"` + LastUsedDerivationIndex uint64 `json:"last-used-derivation-index,omitempty"` + SyncedFrom string `json:"synced-from,omitempty"` // keeps an info which device this keypair is added from can be one of two values defined in constants or device name (custom) + Clock uint64 `json:"clock,omitempty"` + Accounts []*Account `json:"accounts,omitempty"` + Keycards []*Keycard `json:"keycards,omitempty"` + Removed bool `json:"removed,omitempty"` +} + +type AccountCreationDetails struct { + Path string `json:"path"` + Name string `json:"name"` + Emoji string `json:"emoji,omitempty"` + ColorID string `json:"colorId,omitempty"` +} + +type Account struct { + Address types.Address `json:"address"` + KeyUID string `json:"key-uid"` + Wallet bool `json:"wallet"` + AddressWasNotShown bool `json:"address-was-not-shown,omitempty"` + Chat bool `json:"chat"` + Type AccountType `json:"type,omitempty"` + Path string `json:"path,omitempty"` + PublicKey types.HexBytes `json:"public-key,omitempty"` + Name string `json:"name"` + Emoji string `json:"emoji"` + ColorID string `json:"colorId,omitempty"` + Hidden bool `json:"hidden"` + Clock uint64 `json:"clock,omitempty"` + Removed bool `json:"removed,omitempty"` + Operable AccountOperable `json:"operable"` // describes an account's operability (check AccountOperable type constants for details) + CreatedAt int64 `json:"createdAt"` + Position int64 `json:"position"` + ProdPreferredChainIDs string `json:"prodPreferredChainIds"` + TestPreferredChainIDs string `json:"testPreferredChainIds"` +} + +type Keycard struct { + KeycardUID string `json:"keycard-uid"` + KeycardName string `json:"keycard-name"` + KeycardLocked bool `json:"keycard-locked"` + AccountsAddresses []types.Address `json:"accounts-addresses"` + KeyUID string `json:"key-uid"` + Position uint64 +} + +func (a *Keypair) MigratedToKeycard() bool { + return len(a.Keycards) > 0 +} + +// Returns operability of a keypair: +// - if any of keypair's account is not operable, then a keyapir is considered as non operable +// - if any of keypair's account is partially operable, then a keyapir is considered as partially operable +// - if all accounts are fully operable, then a keyapir is considered as fully operable +func (a *Keypair) Operability() AccountOperable { + for _, acc := range a.Accounts { + if acc.Operable == AccountNonOperable { + return AccountNonOperable + } + if acc.Operable == AccountPartiallyOperable { + return AccountPartiallyOperable + } + } + + return AccountFullyOperable +} diff --git a/accounts-management/types/types.go b/accounts-management/types/types.go new file mode 100644 index 0000000000..9a5683e91f --- /dev/null +++ b/accounts-management/types/types.go @@ -0,0 +1,24 @@ +package types + +import cryptotypes "github.com/status-im/status-go/crypto/types" + +type PublicKeyData struct { + CompressedKey string `json:"compressedKey"` + EmojiHash []string `json:"emojiHash"` +} + +// SelectedExtKey is a container for the selected (logged in) external account. +type SelectedExtKey struct { + Address cryptotypes.Address + AccountKey *Key + SubAccounts []Account +} + +// Hex dumps address of a given extended key as hex string. +func (k *SelectedExtKey) Hex() string { + if k == nil { + return "0x0" + } + + return k.Address.Hex() +} diff --git a/accounts-management/types/types_test.go b/accounts-management/types/types_test.go new file mode 100644 index 0000000000..2ec517f00f --- /dev/null +++ b/accounts-management/types/types_test.go @@ -0,0 +1,29 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +func TestHex(t *testing.T) { + var addr *SelectedExtKey + cr, _ := crypto.GenerateKey() + var flagtests = []struct { + in *SelectedExtKey + out string + }{ + {&SelectedExtKey{ + Address: cryptotypes.HexToAddress("0x742d35Cc6634C0532925a3b844Bc454e4438f44e"), + AccountKey: &Key{PrivateKey: cr}, + }, "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"}, + {addr, "0x0"}, + } + + for _, tt := range flagtests { + assert.Equal(t, tt.in.Hex(), tt.out) + } +} diff --git a/appdatabase/migrations/sql/1752869164_drop_telemetry_server_url.up.sql b/appdatabase/migrations/sql/1752869164_drop_telemetry_server_url.up.sql new file mode 100644 index 0000000000..4e5473636f --- /dev/null +++ b/appdatabase/migrations/sql/1752869164_drop_telemetry_server_url.up.sql @@ -0,0 +1 @@ +ALTER TABLE settings DROP COLUMN telemetry_server_url; diff --git a/appdatabase/migrations/sql/1753221199_add_add_backup_path_setting.up.sql b/appdatabase/migrations/sql/1753221199_add_add_backup_path_setting.up.sql new file mode 100644 index 0000000000..258024ff2f --- /dev/null +++ b/appdatabase/migrations/sql/1753221199_add_add_backup_path_setting.up.sql @@ -0,0 +1 @@ +ALTER TABLE settings ADD COLUMN backup_path VARCHAR DEFAULT ''; diff --git a/appdatabase/migrations/sql/1754574769_drop_mailservers.up.sql b/appdatabase/migrations/sql/1754574769_drop_mailservers.up.sql new file mode 100644 index 0000000000..8b57e87c01 --- /dev/null +++ b/appdatabase/migrations/sql/1754574769_drop_mailservers.up.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS mailservers; +DROP TABLE IF EXISTS mailserver_request_gaps; +DROP TABLE IF EXISTS mailserver_chat_request_ranges; \ No newline at end of file diff --git a/appdatabase/migrations/sql/1754667909_drop_http_config.up.sql b/appdatabase/migrations/sql/1754667909_drop_http_config.up.sql new file mode 100644 index 0000000000..d92f6c23b8 --- /dev/null +++ b/appdatabase/migrations/sql/1754667909_drop_http_config.up.sql @@ -0,0 +1,4 @@ +DROP TABLE IF EXISTS http_config; +DROP TABLE IF EXISTS http_virtual_hosts; +DROP TABLE IF EXISTS http_cors; +DROP TABLE IF EXISTS ipc_config; \ No newline at end of file diff --git a/appdatabase/migrations/sql/1754670349_drop_ipc_config.up.sql b/appdatabase/migrations/sql/1754670349_drop_ipc_config.up.sql new file mode 100644 index 0000000000..4431e2842f --- /dev/null +++ b/appdatabase/migrations/sql/1754670349_drop_ipc_config.up.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS ipc_config; diff --git a/appdatabase/migrations/sql/1754670350_drop_cluster_nodes.up.sql b/appdatabase/migrations/sql/1754670350_drop_cluster_nodes.up.sql new file mode 100644 index 0000000000..ad6e51424d --- /dev/null +++ b/appdatabase/migrations/sql/1754670350_drop_cluster_nodes.up.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS cluster_nodes; \ No newline at end of file diff --git a/appdatabase/migrations/sql/1754670351_drop_wakuv2_custom_nodes.up.sql b/appdatabase/migrations/sql/1754670351_drop_wakuv2_custom_nodes.up.sql new file mode 100644 index 0000000000..5dd8d97f89 --- /dev/null +++ b/appdatabase/migrations/sql/1754670351_drop_wakuv2_custom_nodes.up.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS wakuv2_custom_nodes; \ No newline at end of file diff --git a/appdatabase/migrations/sql/1754670352_cleanup_wakuv2_config.up.sql b/appdatabase/migrations/sql/1754670352_cleanup_wakuv2_config.up.sql new file mode 100644 index 0000000000..4bca47b3c4 --- /dev/null +++ b/appdatabase/migrations/sql/1754670352_cleanup_wakuv2_config.up.sql @@ -0,0 +1,15 @@ +ALTER TABLE wakuv2_config DROP COLUMN enabled; +ALTER TABLE wakuv2_config DROP COLUMN host; +ALTER TABLE wakuv2_config DROP COLUMN port; +ALTER TABLE wakuv2_config DROP COLUMN full_node; +ALTER TABLE wakuv2_config DROP COLUMN enable_discv5; +ALTER TABLE wakuv2_config DROP COLUMN peer_exchange; +ALTER TABLE wakuv2_config DROP COLUMN discovery_limit; +ALTER TABLE wakuv2_config DROP COLUMN data_dir; +ALTER TABLE wakuv2_config DROP COLUMN max_message_size; +ALTER TABLE wakuv2_config DROP COLUMN enable_confirmations; +ALTER TABLE wakuv2_config DROP COLUMN udp_port; +ALTER TABLE wakuv2_config DROP COLUMN auto_update; +ALTER TABLE wakuv2_config DROP COLUMN enable_store; +ALTER TABLE wakuv2_config DROP COLUMN store_capacity; +ALTER TABLE wakuv2_config DROP COLUMN store_seconds; \ No newline at end of file diff --git a/appdatabase/migrations/sql/1754923284_cleanup_node_config.up.sql b/appdatabase/migrations/sql/1754923284_cleanup_node_config.up.sql new file mode 100644 index 0000000000..d5fcf1313e --- /dev/null +++ b/appdatabase/migrations/sql/1754923284_cleanup_node_config.up.sql @@ -0,0 +1,10 @@ +ALTER TABLE shhext_config DROP COLUMN enable_connection_manager; +ALTER TABLE shhext_config DROP COLUMN enable_last_used_monitor; +ALTER TABLE shhext_config DROP COLUMN connection_target; +ALTER TABLE shhext_config DROP COLUMN request_delay; +ALTER TABLE shhext_config DROP COLUMN max_server_failures; +ALTER TABLE shhext_config DROP COLUMN max_message_delivery_attempts; +ALTER TABLE shhext_config DROP COLUMN whisper_cache_dir; +ALTER TABLE shhext_config DROP COLUMN disable_generic_discovery_topic; +ALTER TABLE shhext_config DROP COLUMN send_v1_messages; +ALTER TABLE shhext_config DROP COLUMN data_sync_enabled; diff --git a/appdatabase/migrations/sql/1755017956_drop_app_metrics.up.sql b/appdatabase/migrations/sql/1755017956_drop_app_metrics.up.sql new file mode 100644 index 0000000000..56c41acc74 --- /dev/null +++ b/appdatabase/migrations/sql/1755017956_drop_app_metrics.up.sql @@ -0,0 +1,5 @@ +DROP TABLE IF EXISTS app_metrics; +ALTER TABLE settings DROP COLUMN anon_metrics_should_send; +ALTER TABLE shhext_config DROP COLUMN anon_metrics_server_enabled; +ALTER TABLE shhext_config DROP COLUMN anon_metrics_send_id; +ALTER TABLE shhext_config DROP COLUMN anon_metrics_server_postgres_uri; \ No newline at end of file diff --git a/appdatabase/migrations/sql/1755264069_cleanup_node_config.up.sql b/appdatabase/migrations/sql/1755264069_cleanup_node_config.up.sql new file mode 100644 index 0000000000..f3cc3dfc4c --- /dev/null +++ b/appdatabase/migrations/sql/1755264069_cleanup_node_config.up.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS shhext_default_push_notification_servers; diff --git a/cmd/generate-db/README.md b/cmd/generate-db/README.md new file mode 100644 index 0000000000..d769b9be73 --- /dev/null +++ b/cmd/generate-db/README.md @@ -0,0 +1,30 @@ +# generate-db + +A tiny utility to generate empty, up-to-date SQLite databases used by Status. + +It initializes the databases using the same initializers and migrations as the app, +so the resulting files match the current schema. This is handy for IDE SQL inspections, +schema exploration, or tooling that expects a real database file. + +## What it creates + +- `app.db` — initialized via `appdatabase.DbInitializer` +- `wallet.db` — initialized via `walletdatabase.DbInitializer` +- `accounts.db` — initialized via `multiaccounts.InitializeDB` + +By design, these databases are empty (no user data) but fully migrated to the latest schema. + +## Build and run + +```bash +make generate-db +``` +This builds the tool and generates databases under `build/db` by default. + +## Notes + +- Schemas are produced by the current codebase. + If you update migrations, rerun this tool to regenerate the files. +- The tool uses an empty password and 0 KDF iterations during initialization. + These files are strictly for local development, inspection, and tooling. +- Existing files at the target location are removed before re-creation. diff --git a/cmd/generate-db/main.go b/cmd/generate-db/main.go new file mode 100644 index 0000000000..0f06b10ab0 --- /dev/null +++ b/cmd/generate-db/main.go @@ -0,0 +1,96 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/multiaccounts" + "github.com/status-im/status-go/walletdatabase" +) + +const ( + password = "" + kdfIterationsNumber = 0 +) + +func main() { + outDir := flag.String("out-dir", "build", "Output directory for generated DB files") + flag.Parse() + + if err := os.MkdirAll(*outDir, 0o755); err != nil { + log.Fatalf("failed to create output directory %s: %v", *outDir, err) + } + + if err := generateAppDB(*outDir); err != nil { + log.Fatalf("failed to generate app DB: %v", err) + } + fmt.Println("Generated app DB") + + if err := generateWalletDB(*outDir); err != nil { + log.Fatalf("failed to generate wallet DB: %v", err) + } + fmt.Println("Generated wallet DB") + + if err := generateAccountsDB(*outDir); err != nil { + log.Fatalf("failed to generate accounts DB: %v", err) + } + fmt.Println("Generated accounts DB") + + fmt.Printf("All DBs are generated under %s\n", *outDir) +} + +func recreate(path string) error { + _ = os.Remove(path) + _ = os.Remove(path + "-wal") + _ = os.Remove(path + "-shm") + return nil +} + +func generateAppDB(outDir string) error { + path := filepath.Join(outDir, "app.db") + if err := recreate(path); err != nil { + return err + } + + // Use the same initializer the app uses + var init appdatabase.DbInitializer + _, err := init.Initialize(path, password, kdfIterationsNumber) + if err != nil { + return err + } + return nil +} + +func generateWalletDB(outDir string) error { + path := filepath.Join(outDir, "wallet.db") + if err := recreate(path); err != nil { + return err + } + + // Use the same initializer the app uses + var init walletdatabase.DbInitializer + _, err := init.Initialize(path, password, kdfIterationsNumber) + if err != nil { + return err + } + return nil +} + +func generateAccountsDB(outDir string) error { + path := filepath.Join(outDir, "accounts.db") + if err := recreate(path); err != nil { + return err + } + + // Accounts DB uses its own initializer returning a wrapper type + db, err := multiaccounts.InitializeDB(path) + if err != nil { + return err + } + defer db.Close() + return nil +} diff --git a/cmd/push-notification-server/main.go b/cmd/push-notification-server/main.go new file mode 100644 index 0000000000..19d8aa937d --- /dev/null +++ b/cmd/push-notification-server/main.go @@ -0,0 +1,284 @@ +package main + +import ( + "crypto/ecdsa" + "database/sql" + "flag" + "fmt" + "os" + "os/signal" + "path" + "time" + + "github.com/google/uuid" + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/common/dbsetup" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/logutils" + "github.com/status-im/status-go/messaging" + "github.com/status-im/status-go/params" + "github.com/status-im/status-go/pkg/sentry" + "github.com/status-im/status-go/pkg/version" + "github.com/status-im/status-go/protocol" + "github.com/status-im/status-go/protocol/pushnotificationserver" + "github.com/status-im/status-go/protocol/sqlite" + mailserversDB "github.com/status-im/status-go/services/mailservers" + "github.com/status-im/status-go/services/personal" + "github.com/status-im/status-go/timesource" + "github.com/status-im/status-go/walletdatabase" +) + +var ( + gorushURL = flag.String("gorush-url", pushnotificationserver.DefaultGorushURL, "gorush server URL") + dataDir = flag.String("data-dir", "", "data directory") + identity = flag.String("identity", "", "Hex-encoded private key to use. When empty, an ephemeral key will be used") + sentryEnabled = flag.Bool("sentry", false, "Enable sentry panic reporting") + logLevel = flag.String("log-level", "INFO", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG"`) + logNoColors = flag.Bool("log-no-color", false, "Disables log colors") + wakuFleet = flag.String("waku-fleet", "status.prod", "Waku fleet to use") + wakuFleetConfig = flag.String("waku-fleet-config", "", "path to Waku fleet config file") + Port = flag.Int("tcp-port", 30303, "Libp2p TCP port") + UDPPort = flag.Int("udp-port", 30303, "Libp2p UDP port") + // TODO: add pprof and metrics + + logger *zap.Logger +) + +const ( + exitCodeOK = iota + exitCodeInvalidWakuFleetConfig + exitCodeInvalidKey + exitCodeCreateWakuFailed + exitCodeStartMessagingFailed + exitCodeDBMigrationFailed + exitCodeCreateMessengerFailed + exitCodeCreateDatabaseFailed + exitCodeStartServerFailed + exitCodeStartMessengerFailed +) + +func init() { + flag.Parse() + logSettings := logutils.LogSettings{ + Enabled: true, + Level: *logLevel, + } + if err := logutils.OverrideRootLoggerWithConfig(logSettings); err != nil { + panic(err) + } + + logger = logutils.ZapLogger() +} + +func main() { + defer func() { + _ = logger.Sync() + }() + + if *sentryEnabled { + sentry.MustInit( + sentry.WithDefaultEnvironmentDSN(), + sentry.WithContext("push-notification-server", version.Version()), + ) + defer sentry.Recover() + } + + if *wakuFleetConfig != "" { + err := params.LoadWakuFleetsFromFile(*wakuFleetConfig) + if err != nil { + logger.Error("failed to load waku fleet config", zap.Error(err)) + os.Exit(exitCodeInvalidWakuFleetConfig) + } + } + + privateKey, installationID, err := parseNodeKey(*identity) + if err != nil { + logger.Error("failed to parse node key", zap.Error(err)) + os.Exit(exitCodeInvalidKey) + } + + dbPath := path.Join(*dataDir, installationID+"-app") + db, err := createAppDatabase(dbPath) + if err != nil { + logger.Error("failed to create database", zap.Error(err)) + os.Exit(exitCodeCreateDatabaseFailed) + } + + walletDBPath := path.Join(*dataDir, installationID) + walletDB, err := createWalletDatabase(walletDBPath) + if err != nil { + logger.Error("failed to create database", zap.Error(err)) + os.Exit(exitCodeCreateDatabaseFailed) + } + + err = sqlite.Migrate(db) + if err != nil { + logger.Error("failed to migrate database", zap.Error(err)) + os.Exit(exitCodeDBMigrationFailed) + } + + messaging, err := messaging.NewCore( + messaging.CoreParams{ + Identity: privateKey, + DB: db, + Persistence: protocol.NewMessagingPersistence(db), + NodeKey: nil, + WakuConfig: params.WakuV2Config{ + Enabled: true, + Host: "0.0.0.0", + Port: *Port, + UDPPort: *UDPPort, + LightClient: false, + DiscoveryLimit: 20, + AutoUpdate: true, + }, + ClusterConfig: params.ClusterConfig{ + WakuNodes: params.DefaultWakuNodes(*wakuFleet), + DiscV5BootstrapNodes: params.DefaultDiscV5Nodes(*wakuFleet), + ClusterID: 16, + }, + InstallationID: installationID, + TimeSource: timesource.Default(), + }, + messaging.WithLogger(logger.Named("messaging")), + ) + if err != nil { + os.Exit(exitCodeCreateMessengerFailed) + } + + err = messaging.API().Start() + if err != nil { + logger.Error("failed to start messaging", zap.Error(err)) + os.Exit(exitCodeStartMessagingFailed) + } + defer func() { + err := messaging.API().Stop() + if err != nil { + logger.Error("failed to stop messaging", zap.Error(err)) + } + }() + + // Set up the push notifications server + config := &pushnotificationserver.Config{ + Enabled: true, + Identity: privateKey, + GorushURL: *gorushURL, + Logger: logger, + } + server := pushnotificationserver.New(config) + + // Set up the messenger + options := []protocol.Option{ + protocol.WithDatabase(db), + protocol.WithWalletDatabase(walletDB), + protocol.WithMailserversDatabase(mailserversDB.NewDB(db)), + protocol.WithDatasync(), + protocol.WithMessageSigner(personal.New()), + protocol.WithPushNotificationServer(server), + } + messenger, err := protocol.NewMessenger(privateKey, messaging.API(), installationID, options...) + if err != nil { + logger.Error("failed to create messenger", zap.Error(err)) + os.Exit(exitCodeCreateMessengerFailed) + } + + // Start + serverPersistence := pushnotificationserver.NewSQLitePersistence(db) + err = server.Start(serverPersistence, messenger.Messaging()) + if err != nil { + logger.Error("failed to start push notifications server", zap.Error(err)) + os.Exit(exitCodeStartServerFailed) + } + + _, err = messenger.Start() + if err != nil { + fmt.Println("failed to start messenger", err) + logger.Error("failed to start messenger", zap.Error(err)) + os.Exit(exitCodeStartMessengerFailed) + } + + defer func() { + err := messenger.Shutdown() + if err != nil { + logger.Error("failed to shutdown messenger", zap.Error(err)) + } + }() + + cancelMessenger := make(chan struct{}) + messenger.StartRetrieveMessagesLoop(300*time.Millisecond, cancelMessenger) + + go func() { + select { + case <-cancelMessenger: + return + case <-time.After(10 * time.Second): + } + logger.Info("requesting history") + response, err := messenger.RequestAllHistoricMessages(false, false) + if err != nil { + logger.Error("failed to request history", zap.Error(err)) + return + } + + logger.Info("history fetched", + zap.Any("response", response), + ) + }() + + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt) + <-quit + close(cancelMessenger) + + logger.Info("push-notification-server finished") + os.Exit(exitCodeOK) +} + +func parseNodeKey(nodeKey string) (*ecdsa.PrivateKey, string, error) { + // Check for environment variable if CLI flag is empty + if nodeKey == "" { + nodeKey = os.Getenv("STATUS_GO_NODE_KEY") + } + + // If still empty, return error + if nodeKey == "" { + return nil, "", errors.New("Nodekey must be provided via -identity flag or STATUS_GO_NODE_KEY environment variable") + } + + // Parse private key + privateKey, err := crypto.HexToECDSA(nodeKey) + if err != nil { + return nil, "", errors.Wrap(err, "invalid node key") + } + + // Generate installationID from public key, so it's always the same + installationID, err := uuid.FromBytes(crypto.CompressPubkey(&privateKey.PublicKey)[:16]) + if err != nil { + return nil, "", errors.Wrap(err, "failed to generate installation id") + } + + return privateKey, installationID.String(), nil +} + +func createAppDatabase(path string) (*sql.DB, error) { + filename := path + ".db" + appDB, err := appdatabase.InitializeDB(filename, "", dbsetup.ReducedKDFIterationsNumber) + if err != nil { + return nil, errors.Wrap(err, "failed to initialize app database") + } + + return appDB, nil +} + +func createWalletDatabase(path string) (*sql.DB, error) { + filename := path + "-wallet.db" + walletDB, err := walletdatabase.InitializeDB(filename, "", dbsetup.ReducedKDFIterationsNumber) + if err != nil { + logger.Error("failed to initialize wallet db", zap.Error(err)) + return nil, err + } + return walletDB, nil +} diff --git a/cmd/status-backend/server/options.go b/cmd/status-backend/server/options.go new file mode 100644 index 0000000000..12125b5173 --- /dev/null +++ b/cmd/status-backend/server/options.go @@ -0,0 +1,19 @@ +package server + +type Config struct { + profilingEnabled bool +} + +func defaultConfig() *Config { + return &Config{ + profilingEnabled: false, + } +} + +type Option func(*Config) + +func WithProfiling(enabled bool) func(*Config) { + return func(c *Config) { + c.profilingEnabled = enabled + } +} diff --git a/common/errors.go b/common/errors.go new file mode 100644 index 0000000000..2ef36a788b --- /dev/null +++ b/common/errors.go @@ -0,0 +1,7 @@ +package common + +import "fmt" + +var ( + ErrBigIntSetFromString = func(val string) error { return fmt.Errorf("failed to set big.Int balance from string '%s'", val) } +) diff --git a/common/errors_test.go b/common/errors_test.go new file mode 100644 index 0000000000..b649494dfd --- /dev/null +++ b/common/errors_test.go @@ -0,0 +1,22 @@ +package common + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestErrBigIntSetFromString(t *testing.T) { + tcs := []struct { + Value string + Expected string + }{ + {"hello", "failed to set big.Int balance from string 'hello'"}, + {"123456.44abc", "failed to set big.Int balance from string '123456.44abc'"}, + {"13e1234234", "failed to set big.Int balance from string '13e1234234'"}, + } + + for _, tc := range tcs { + require.Equal(t, tc.Expected, ErrBigIntSetFromString(tc.Value).Error()) + } +} diff --git a/contracts/namewrapper/namewrapper.go b/contracts/namewrapper/namewrapper.go new file mode 100644 index 0000000000..977674dea7 --- /dev/null +++ b/contracts/namewrapper/namewrapper.go @@ -0,0 +1,2392 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package namewrapper + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// NamewrapperMetaData contains all meta data concerning the Namewrapper contract. +var NamewrapperMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"expiry\",\"type\":\"uint64\"}],\"name\":\"ExpiryExtended\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fuses\",\"type\":\"uint32\"}],\"name\":\"FusesSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"NameUnwrapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"name\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fuses\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"expiry\",\"type\":\"uint64\"}],\"name\":\"NameWrapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"fuseMask\",\"type\":\"uint32\"}],\"name\":\"allFusesBurned\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"canModifyName\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ens\",\"outputs\":[{\"internalType\":\"contractENS\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"labelhash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"expiry\",\"type\":\"uint64\"}],\"name\":\"extendExpiry\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getData\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"isWrapped\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"isWrapped\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"metadataService\",\"outputs\":[{\"internalType\":\"contractIMetadataService\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"names\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"label\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"wrappedOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"resolver\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"ownerControlledFuses\",\"type\":\"uint16\"}],\"name\":\"registerAndWrapETH2LD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"registrarExpiry\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractIBaseRegistrar\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"labelHash\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"renew\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expires\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"parentNode\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"labelhash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"fuses\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"expiry\",\"type\":\"uint64\"}],\"name\":\"setChildFuses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"uint16\",\"name\":\"ownerControlledFuses\",\"type\":\"uint16\"}],\"name\":\"setFuses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"newFuses\",\"type\":\"uint32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIMetadataService\",\"name\":\"_metadataService\",\"type\":\"address\"}],\"name\":\"setMetadataService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"resolver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setRecord\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"setResolver\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"label\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"fuses\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"expiry\",\"type\":\"uint64\"}],\"name\":\"setSubnodeOwner\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"label\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"resolver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"ttl\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"fuses\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"expiry\",\"type\":\"uint64\"}],\"name\":\"setSubnodeRecord\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setTTL\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractINameWrapperUpgrade\",\"name\":\"_upgradeAddress\",\"type\":\"address\"}],\"name\":\"setUpgradeContract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceID\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"node\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"label\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"unwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"label\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"newRegistrant\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"unwrapETH2LD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"name\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upgradeContract\",\"outputs\":[{\"internalType\":\"contractINameWrapperUpgrade\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"name\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrappedOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"wrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"label\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"wrappedOwner\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"ownerControlledFuses\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"wrapETH2LD\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"expires\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// NamewrapperABI is the input ABI used to generate the binding from. +// Deprecated: Use NamewrapperMetaData.ABI instead. +var NamewrapperABI = NamewrapperMetaData.ABI + +// Namewrapper is an auto generated Go binding around an Ethereum contract. +type Namewrapper struct { + NamewrapperCaller // Read-only binding to the contract + NamewrapperTransactor // Write-only binding to the contract + NamewrapperFilterer // Log filterer for contract events +} + +// NamewrapperCaller is an auto generated read-only Go binding around an Ethereum contract. +type NamewrapperCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NamewrapperTransactor is an auto generated write-only Go binding around an Ethereum contract. +type NamewrapperTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NamewrapperFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type NamewrapperFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NamewrapperSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type NamewrapperSession struct { + Contract *Namewrapper // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NamewrapperCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type NamewrapperCallerSession struct { + Contract *NamewrapperCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// NamewrapperTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type NamewrapperTransactorSession struct { + Contract *NamewrapperTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NamewrapperRaw is an auto generated low-level Go binding around an Ethereum contract. +type NamewrapperRaw struct { + Contract *Namewrapper // Generic contract binding to access the raw methods on +} + +// NamewrapperCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type NamewrapperCallerRaw struct { + Contract *NamewrapperCaller // Generic read-only contract binding to access the raw methods on +} + +// NamewrapperTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type NamewrapperTransactorRaw struct { + Contract *NamewrapperTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewNamewrapper creates a new instance of Namewrapper, bound to a specific deployed contract. +func NewNamewrapper(address common.Address, backend bind.ContractBackend) (*Namewrapper, error) { + contract, err := bindNamewrapper(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Namewrapper{NamewrapperCaller: NamewrapperCaller{contract: contract}, NamewrapperTransactor: NamewrapperTransactor{contract: contract}, NamewrapperFilterer: NamewrapperFilterer{contract: contract}}, nil +} + +// NewNamewrapperCaller creates a new read-only instance of Namewrapper, bound to a specific deployed contract. +func NewNamewrapperCaller(address common.Address, caller bind.ContractCaller) (*NamewrapperCaller, error) { + contract, err := bindNamewrapper(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &NamewrapperCaller{contract: contract}, nil +} + +// NewNamewrapperTransactor creates a new write-only instance of Namewrapper, bound to a specific deployed contract. +func NewNamewrapperTransactor(address common.Address, transactor bind.ContractTransactor) (*NamewrapperTransactor, error) { + contract, err := bindNamewrapper(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &NamewrapperTransactor{contract: contract}, nil +} + +// NewNamewrapperFilterer creates a new log filterer instance of Namewrapper, bound to a specific deployed contract. +func NewNamewrapperFilterer(address common.Address, filterer bind.ContractFilterer) (*NamewrapperFilterer, error) { + contract, err := bindNamewrapper(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &NamewrapperFilterer{contract: contract}, nil +} + +// bindNamewrapper binds a generic wrapper to an already deployed contract. +func bindNamewrapper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := NamewrapperMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Namewrapper *NamewrapperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Namewrapper.Contract.NamewrapperCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Namewrapper *NamewrapperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Namewrapper.Contract.NamewrapperTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Namewrapper *NamewrapperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Namewrapper.Contract.NamewrapperTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Namewrapper *NamewrapperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Namewrapper.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Namewrapper *NamewrapperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Namewrapper.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Namewrapper *NamewrapperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Namewrapper.Contract.contract.Transact(opts, method, params...) +} + +// AllFusesBurned is a free data retrieval call binding the contract method 0xadf4960a. +// +// Solidity: function allFusesBurned(bytes32 node, uint32 fuseMask) view returns(bool) +func (_Namewrapper *NamewrapperCaller) AllFusesBurned(opts *bind.CallOpts, node [32]byte, fuseMask uint32) (bool, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "allFusesBurned", node, fuseMask) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// AllFusesBurned is a free data retrieval call binding the contract method 0xadf4960a. +// +// Solidity: function allFusesBurned(bytes32 node, uint32 fuseMask) view returns(bool) +func (_Namewrapper *NamewrapperSession) AllFusesBurned(node [32]byte, fuseMask uint32) (bool, error) { + return _Namewrapper.Contract.AllFusesBurned(&_Namewrapper.CallOpts, node, fuseMask) +} + +// AllFusesBurned is a free data retrieval call binding the contract method 0xadf4960a. +// +// Solidity: function allFusesBurned(bytes32 node, uint32 fuseMask) view returns(bool) +func (_Namewrapper *NamewrapperCallerSession) AllFusesBurned(node [32]byte, fuseMask uint32) (bool, error) { + return _Namewrapper.Contract.AllFusesBurned(&_Namewrapper.CallOpts, node, fuseMask) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. +// +// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) +func (_Namewrapper *NamewrapperCaller) BalanceOf(opts *bind.CallOpts, account common.Address, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "balanceOf", account, id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. +// +// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) +func (_Namewrapper *NamewrapperSession) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) { + return _Namewrapper.Contract.BalanceOf(&_Namewrapper.CallOpts, account, id) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. +// +// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) +func (_Namewrapper *NamewrapperCallerSession) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) { + return _Namewrapper.Contract.BalanceOf(&_Namewrapper.CallOpts, account, id) +} + +// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. +// +// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) +func (_Namewrapper *NamewrapperCaller) BalanceOfBatch(opts *bind.CallOpts, accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "balanceOfBatch", accounts, ids) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. +// +// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) +func (_Namewrapper *NamewrapperSession) BalanceOfBatch(accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { + return _Namewrapper.Contract.BalanceOfBatch(&_Namewrapper.CallOpts, accounts, ids) +} + +// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. +// +// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) +func (_Namewrapper *NamewrapperCallerSession) BalanceOfBatch(accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { + return _Namewrapper.Contract.BalanceOfBatch(&_Namewrapper.CallOpts, accounts, ids) +} + +// CanModifyName is a free data retrieval call binding the contract method 0x41415eab. +// +// Solidity: function canModifyName(bytes32 node, address addr) view returns(bool) +func (_Namewrapper *NamewrapperCaller) CanModifyName(opts *bind.CallOpts, node [32]byte, addr common.Address) (bool, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "canModifyName", node, addr) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanModifyName is a free data retrieval call binding the contract method 0x41415eab. +// +// Solidity: function canModifyName(bytes32 node, address addr) view returns(bool) +func (_Namewrapper *NamewrapperSession) CanModifyName(node [32]byte, addr common.Address) (bool, error) { + return _Namewrapper.Contract.CanModifyName(&_Namewrapper.CallOpts, node, addr) +} + +// CanModifyName is a free data retrieval call binding the contract method 0x41415eab. +// +// Solidity: function canModifyName(bytes32 node, address addr) view returns(bool) +func (_Namewrapper *NamewrapperCallerSession) CanModifyName(node [32]byte, addr common.Address) (bool, error) { + return _Namewrapper.Contract.CanModifyName(&_Namewrapper.CallOpts, node, addr) +} + +// Ens is a free data retrieval call binding the contract method 0x3f15457f. +// +// Solidity: function ens() view returns(address) +func (_Namewrapper *NamewrapperCaller) Ens(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "ens") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Ens is a free data retrieval call binding the contract method 0x3f15457f. +// +// Solidity: function ens() view returns(address) +func (_Namewrapper *NamewrapperSession) Ens() (common.Address, error) { + return _Namewrapper.Contract.Ens(&_Namewrapper.CallOpts) +} + +// Ens is a free data retrieval call binding the contract method 0x3f15457f. +// +// Solidity: function ens() view returns(address) +func (_Namewrapper *NamewrapperCallerSession) Ens() (common.Address, error) { + return _Namewrapper.Contract.Ens(&_Namewrapper.CallOpts) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Namewrapper *NamewrapperCaller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "getApproved", tokenId) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Namewrapper *NamewrapperSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _Namewrapper.Contract.GetApproved(&_Namewrapper.CallOpts, tokenId) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Namewrapper *NamewrapperCallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _Namewrapper.Contract.GetApproved(&_Namewrapper.CallOpts, tokenId) +} + +// GetData is a free data retrieval call binding the contract method 0x0178fe3f. +// +// Solidity: function getData(uint256 id) view returns(address, uint32, uint64) +func (_Namewrapper *NamewrapperCaller) GetData(opts *bind.CallOpts, id *big.Int) (common.Address, uint32, uint64, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "getData", id) + + if err != nil { + return *new(common.Address), *new(uint32), *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out1 := *abi.ConvertType(out[1], new(uint32)).(*uint32) + out2 := *abi.ConvertType(out[2], new(uint64)).(*uint64) + + return out0, out1, out2, err + +} + +// GetData is a free data retrieval call binding the contract method 0x0178fe3f. +// +// Solidity: function getData(uint256 id) view returns(address, uint32, uint64) +func (_Namewrapper *NamewrapperSession) GetData(id *big.Int) (common.Address, uint32, uint64, error) { + return _Namewrapper.Contract.GetData(&_Namewrapper.CallOpts, id) +} + +// GetData is a free data retrieval call binding the contract method 0x0178fe3f. +// +// Solidity: function getData(uint256 id) view returns(address, uint32, uint64) +func (_Namewrapper *NamewrapperCallerSession) GetData(id *big.Int) (common.Address, uint32, uint64, error) { + return _Namewrapper.Contract.GetData(&_Namewrapper.CallOpts, id) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) +func (_Namewrapper *NamewrapperCaller) IsApprovedForAll(opts *bind.CallOpts, account common.Address, operator common.Address) (bool, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "isApprovedForAll", account, operator) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) +func (_Namewrapper *NamewrapperSession) IsApprovedForAll(account common.Address, operator common.Address) (bool, error) { + return _Namewrapper.Contract.IsApprovedForAll(&_Namewrapper.CallOpts, account, operator) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) +func (_Namewrapper *NamewrapperCallerSession) IsApprovedForAll(account common.Address, operator common.Address) (bool, error) { + return _Namewrapper.Contract.IsApprovedForAll(&_Namewrapper.CallOpts, account, operator) +} + +// IsWrapped is a free data retrieval call binding the contract method 0xd9a50c12. +// +// Solidity: function isWrapped(bytes32 , bytes32 ) view returns(bool) +func (_Namewrapper *NamewrapperCaller) IsWrapped(opts *bind.CallOpts, arg0 [32]byte, arg1 [32]byte) (bool, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "isWrapped", arg0, arg1) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsWrapped is a free data retrieval call binding the contract method 0xd9a50c12. +// +// Solidity: function isWrapped(bytes32 , bytes32 ) view returns(bool) +func (_Namewrapper *NamewrapperSession) IsWrapped(arg0 [32]byte, arg1 [32]byte) (bool, error) { + return _Namewrapper.Contract.IsWrapped(&_Namewrapper.CallOpts, arg0, arg1) +} + +// IsWrapped is a free data retrieval call binding the contract method 0xd9a50c12. +// +// Solidity: function isWrapped(bytes32 , bytes32 ) view returns(bool) +func (_Namewrapper *NamewrapperCallerSession) IsWrapped(arg0 [32]byte, arg1 [32]byte) (bool, error) { + return _Namewrapper.Contract.IsWrapped(&_Namewrapper.CallOpts, arg0, arg1) +} + +// IsWrapped0 is a free data retrieval call binding the contract method 0xfd0cd0d9. +// +// Solidity: function isWrapped(bytes32 ) view returns(bool) +func (_Namewrapper *NamewrapperCaller) IsWrapped0(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "isWrapped0", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsWrapped0 is a free data retrieval call binding the contract method 0xfd0cd0d9. +// +// Solidity: function isWrapped(bytes32 ) view returns(bool) +func (_Namewrapper *NamewrapperSession) IsWrapped0(arg0 [32]byte) (bool, error) { + return _Namewrapper.Contract.IsWrapped0(&_Namewrapper.CallOpts, arg0) +} + +// IsWrapped0 is a free data retrieval call binding the contract method 0xfd0cd0d9. +// +// Solidity: function isWrapped(bytes32 ) view returns(bool) +func (_Namewrapper *NamewrapperCallerSession) IsWrapped0(arg0 [32]byte) (bool, error) { + return _Namewrapper.Contract.IsWrapped0(&_Namewrapper.CallOpts, arg0) +} + +// MetadataService is a free data retrieval call binding the contract method 0x53095467. +// +// Solidity: function metadataService() view returns(address) +func (_Namewrapper *NamewrapperCaller) MetadataService(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "metadataService") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// MetadataService is a free data retrieval call binding the contract method 0x53095467. +// +// Solidity: function metadataService() view returns(address) +func (_Namewrapper *NamewrapperSession) MetadataService() (common.Address, error) { + return _Namewrapper.Contract.MetadataService(&_Namewrapper.CallOpts) +} + +// MetadataService is a free data retrieval call binding the contract method 0x53095467. +// +// Solidity: function metadataService() view returns(address) +func (_Namewrapper *NamewrapperCallerSession) MetadataService() (common.Address, error) { + return _Namewrapper.Contract.MetadataService(&_Namewrapper.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Namewrapper *NamewrapperCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Namewrapper *NamewrapperSession) Name() (string, error) { + return _Namewrapper.Contract.Name(&_Namewrapper.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Namewrapper *NamewrapperCallerSession) Name() (string, error) { + return _Namewrapper.Contract.Name(&_Namewrapper.CallOpts) +} + +// Names is a free data retrieval call binding the contract method 0x20c38e2b. +// +// Solidity: function names(bytes32 ) view returns(bytes) +func (_Namewrapper *NamewrapperCaller) Names(opts *bind.CallOpts, arg0 [32]byte) ([]byte, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "names", arg0) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +// Names is a free data retrieval call binding the contract method 0x20c38e2b. +// +// Solidity: function names(bytes32 ) view returns(bytes) +func (_Namewrapper *NamewrapperSession) Names(arg0 [32]byte) ([]byte, error) { + return _Namewrapper.Contract.Names(&_Namewrapper.CallOpts, arg0) +} + +// Names is a free data retrieval call binding the contract method 0x20c38e2b. +// +// Solidity: function names(bytes32 ) view returns(bytes) +func (_Namewrapper *NamewrapperCallerSession) Names(arg0 [32]byte) ([]byte, error) { + return _Namewrapper.Contract.Names(&_Namewrapper.CallOpts, arg0) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 id) view returns(address owner) +func (_Namewrapper *NamewrapperCaller) OwnerOf(opts *bind.CallOpts, id *big.Int) (common.Address, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "ownerOf", id) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 id) view returns(address owner) +func (_Namewrapper *NamewrapperSession) OwnerOf(id *big.Int) (common.Address, error) { + return _Namewrapper.Contract.OwnerOf(&_Namewrapper.CallOpts, id) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 id) view returns(address owner) +func (_Namewrapper *NamewrapperCallerSession) OwnerOf(id *big.Int) (common.Address, error) { + return _Namewrapper.Contract.OwnerOf(&_Namewrapper.CallOpts, id) +} + +// Registrar is a free data retrieval call binding the contract method 0x2b20e397. +// +// Solidity: function registrar() view returns(address) +func (_Namewrapper *NamewrapperCaller) Registrar(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "registrar") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Registrar is a free data retrieval call binding the contract method 0x2b20e397. +// +// Solidity: function registrar() view returns(address) +func (_Namewrapper *NamewrapperSession) Registrar() (common.Address, error) { + return _Namewrapper.Contract.Registrar(&_Namewrapper.CallOpts) +} + +// Registrar is a free data retrieval call binding the contract method 0x2b20e397. +// +// Solidity: function registrar() view returns(address) +func (_Namewrapper *NamewrapperCallerSession) Registrar() (common.Address, error) { + return _Namewrapper.Contract.Registrar(&_Namewrapper.CallOpts) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceID) view returns(bool) +func (_Namewrapper *NamewrapperCaller) SupportsInterface(opts *bind.CallOpts, interfaceID [4]byte) (bool, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "supportsInterface", interfaceID) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceID) view returns(bool) +func (_Namewrapper *NamewrapperSession) SupportsInterface(interfaceID [4]byte) (bool, error) { + return _Namewrapper.Contract.SupportsInterface(&_Namewrapper.CallOpts, interfaceID) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceID) view returns(bool) +func (_Namewrapper *NamewrapperCallerSession) SupportsInterface(interfaceID [4]byte) (bool, error) { + return _Namewrapper.Contract.SupportsInterface(&_Namewrapper.CallOpts, interfaceID) +} + +// UpgradeContract is a free data retrieval call binding the contract method 0x1f4e1504. +// +// Solidity: function upgradeContract() view returns(address) +func (_Namewrapper *NamewrapperCaller) UpgradeContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "upgradeContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// UpgradeContract is a free data retrieval call binding the contract method 0x1f4e1504. +// +// Solidity: function upgradeContract() view returns(address) +func (_Namewrapper *NamewrapperSession) UpgradeContract() (common.Address, error) { + return _Namewrapper.Contract.UpgradeContract(&_Namewrapper.CallOpts) +} + +// UpgradeContract is a free data retrieval call binding the contract method 0x1f4e1504. +// +// Solidity: function upgradeContract() view returns(address) +func (_Namewrapper *NamewrapperCallerSession) UpgradeContract() (common.Address, error) { + return _Namewrapper.Contract.UpgradeContract(&_Namewrapper.CallOpts) +} + +// Uri is a free data retrieval call binding the contract method 0x0e89341c. +// +// Solidity: function uri(uint256 tokenId) view returns(string) +func (_Namewrapper *NamewrapperCaller) Uri(opts *bind.CallOpts, tokenId *big.Int) (string, error) { + var out []interface{} + err := _Namewrapper.contract.Call(opts, &out, "uri", tokenId) + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Uri is a free data retrieval call binding the contract method 0x0e89341c. +// +// Solidity: function uri(uint256 tokenId) view returns(string) +func (_Namewrapper *NamewrapperSession) Uri(tokenId *big.Int) (string, error) { + return _Namewrapper.Contract.Uri(&_Namewrapper.CallOpts, tokenId) +} + +// Uri is a free data retrieval call binding the contract method 0x0e89341c. +// +// Solidity: function uri(uint256 tokenId) view returns(string) +func (_Namewrapper *NamewrapperCallerSession) Uri(tokenId *big.Int) (string, error) { + return _Namewrapper.Contract.Uri(&_Namewrapper.CallOpts, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address to, uint256 tokenId) returns() +func (_Namewrapper *NamewrapperTransactor) Approve(opts *bind.TransactOpts, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "approve", to, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address to, uint256 tokenId) returns() +func (_Namewrapper *NamewrapperSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Namewrapper.Contract.Approve(&_Namewrapper.TransactOpts, to, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address to, uint256 tokenId) returns() +func (_Namewrapper *NamewrapperTransactorSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Namewrapper.Contract.Approve(&_Namewrapper.TransactOpts, to, tokenId) +} + +// ExtendExpiry is a paid mutator transaction binding the contract method 0x6e5d6ad2. +// +// Solidity: function extendExpiry(bytes32 node, bytes32 labelhash, uint64 expiry) returns(uint64) +func (_Namewrapper *NamewrapperTransactor) ExtendExpiry(opts *bind.TransactOpts, node [32]byte, labelhash [32]byte, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "extendExpiry", node, labelhash, expiry) +} + +// ExtendExpiry is a paid mutator transaction binding the contract method 0x6e5d6ad2. +// +// Solidity: function extendExpiry(bytes32 node, bytes32 labelhash, uint64 expiry) returns(uint64) +func (_Namewrapper *NamewrapperSession) ExtendExpiry(node [32]byte, labelhash [32]byte, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.ExtendExpiry(&_Namewrapper.TransactOpts, node, labelhash, expiry) +} + +// ExtendExpiry is a paid mutator transaction binding the contract method 0x6e5d6ad2. +// +// Solidity: function extendExpiry(bytes32 node, bytes32 labelhash, uint64 expiry) returns(uint64) +func (_Namewrapper *NamewrapperTransactorSession) ExtendExpiry(node [32]byte, labelhash [32]byte, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.ExtendExpiry(&_Namewrapper.TransactOpts, node, labelhash, expiry) +} + +// RegisterAndWrapETH2LD is a paid mutator transaction binding the contract method 0xa4014982. +// +// Solidity: function registerAndWrapETH2LD(string label, address wrappedOwner, uint256 duration, address resolver, uint16 ownerControlledFuses) returns(uint256 registrarExpiry) +func (_Namewrapper *NamewrapperTransactor) RegisterAndWrapETH2LD(opts *bind.TransactOpts, label string, wrappedOwner common.Address, duration *big.Int, resolver common.Address, ownerControlledFuses uint16) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "registerAndWrapETH2LD", label, wrappedOwner, duration, resolver, ownerControlledFuses) +} + +// RegisterAndWrapETH2LD is a paid mutator transaction binding the contract method 0xa4014982. +// +// Solidity: function registerAndWrapETH2LD(string label, address wrappedOwner, uint256 duration, address resolver, uint16 ownerControlledFuses) returns(uint256 registrarExpiry) +func (_Namewrapper *NamewrapperSession) RegisterAndWrapETH2LD(label string, wrappedOwner common.Address, duration *big.Int, resolver common.Address, ownerControlledFuses uint16) (*types.Transaction, error) { + return _Namewrapper.Contract.RegisterAndWrapETH2LD(&_Namewrapper.TransactOpts, label, wrappedOwner, duration, resolver, ownerControlledFuses) +} + +// RegisterAndWrapETH2LD is a paid mutator transaction binding the contract method 0xa4014982. +// +// Solidity: function registerAndWrapETH2LD(string label, address wrappedOwner, uint256 duration, address resolver, uint16 ownerControlledFuses) returns(uint256 registrarExpiry) +func (_Namewrapper *NamewrapperTransactorSession) RegisterAndWrapETH2LD(label string, wrappedOwner common.Address, duration *big.Int, resolver common.Address, ownerControlledFuses uint16) (*types.Transaction, error) { + return _Namewrapper.Contract.RegisterAndWrapETH2LD(&_Namewrapper.TransactOpts, label, wrappedOwner, duration, resolver, ownerControlledFuses) +} + +// Renew is a paid mutator transaction binding the contract method 0xc475abff. +// +// Solidity: function renew(uint256 labelHash, uint256 duration) returns(uint256 expires) +func (_Namewrapper *NamewrapperTransactor) Renew(opts *bind.TransactOpts, labelHash *big.Int, duration *big.Int) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "renew", labelHash, duration) +} + +// Renew is a paid mutator transaction binding the contract method 0xc475abff. +// +// Solidity: function renew(uint256 labelHash, uint256 duration) returns(uint256 expires) +func (_Namewrapper *NamewrapperSession) Renew(labelHash *big.Int, duration *big.Int) (*types.Transaction, error) { + return _Namewrapper.Contract.Renew(&_Namewrapper.TransactOpts, labelHash, duration) +} + +// Renew is a paid mutator transaction binding the contract method 0xc475abff. +// +// Solidity: function renew(uint256 labelHash, uint256 duration) returns(uint256 expires) +func (_Namewrapper *NamewrapperTransactorSession) Renew(labelHash *big.Int, duration *big.Int) (*types.Transaction, error) { + return _Namewrapper.Contract.Renew(&_Namewrapper.TransactOpts, labelHash, duration) +} + +// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. +// +// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() +func (_Namewrapper *NamewrapperTransactor) SafeBatchTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "safeBatchTransferFrom", from, to, ids, amounts, data) +} + +// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. +// +// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() +func (_Namewrapper *NamewrapperSession) SafeBatchTransferFrom(from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _Namewrapper.Contract.SafeBatchTransferFrom(&_Namewrapper.TransactOpts, from, to, ids, amounts, data) +} + +// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. +// +// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() +func (_Namewrapper *NamewrapperTransactorSession) SafeBatchTransferFrom(from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _Namewrapper.Contract.SafeBatchTransferFrom(&_Namewrapper.TransactOpts, from, to, ids, amounts, data) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() +func (_Namewrapper *NamewrapperTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "safeTransferFrom", from, to, id, amount, data) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() +func (_Namewrapper *NamewrapperSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _Namewrapper.Contract.SafeTransferFrom(&_Namewrapper.TransactOpts, from, to, id, amount, data) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() +func (_Namewrapper *NamewrapperTransactorSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _Namewrapper.Contract.SafeTransferFrom(&_Namewrapper.TransactOpts, from, to, id, amount, data) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Namewrapper *NamewrapperTransactor) SetApprovalForAll(opts *bind.TransactOpts, operator common.Address, approved bool) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setApprovalForAll", operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Namewrapper *NamewrapperSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Namewrapper.Contract.SetApprovalForAll(&_Namewrapper.TransactOpts, operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Namewrapper.Contract.SetApprovalForAll(&_Namewrapper.TransactOpts, operator, approved) +} + +// SetChildFuses is a paid mutator transaction binding the contract method 0x33c69ea9. +// +// Solidity: function setChildFuses(bytes32 parentNode, bytes32 labelhash, uint32 fuses, uint64 expiry) returns() +func (_Namewrapper *NamewrapperTransactor) SetChildFuses(opts *bind.TransactOpts, parentNode [32]byte, labelhash [32]byte, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setChildFuses", parentNode, labelhash, fuses, expiry) +} + +// SetChildFuses is a paid mutator transaction binding the contract method 0x33c69ea9. +// +// Solidity: function setChildFuses(bytes32 parentNode, bytes32 labelhash, uint32 fuses, uint64 expiry) returns() +func (_Namewrapper *NamewrapperSession) SetChildFuses(parentNode [32]byte, labelhash [32]byte, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetChildFuses(&_Namewrapper.TransactOpts, parentNode, labelhash, fuses, expiry) +} + +// SetChildFuses is a paid mutator transaction binding the contract method 0x33c69ea9. +// +// Solidity: function setChildFuses(bytes32 parentNode, bytes32 labelhash, uint32 fuses, uint64 expiry) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetChildFuses(parentNode [32]byte, labelhash [32]byte, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetChildFuses(&_Namewrapper.TransactOpts, parentNode, labelhash, fuses, expiry) +} + +// SetFuses is a paid mutator transaction binding the contract method 0x402906fc. +// +// Solidity: function setFuses(bytes32 node, uint16 ownerControlledFuses) returns(uint32 newFuses) +func (_Namewrapper *NamewrapperTransactor) SetFuses(opts *bind.TransactOpts, node [32]byte, ownerControlledFuses uint16) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setFuses", node, ownerControlledFuses) +} + +// SetFuses is a paid mutator transaction binding the contract method 0x402906fc. +// +// Solidity: function setFuses(bytes32 node, uint16 ownerControlledFuses) returns(uint32 newFuses) +func (_Namewrapper *NamewrapperSession) SetFuses(node [32]byte, ownerControlledFuses uint16) (*types.Transaction, error) { + return _Namewrapper.Contract.SetFuses(&_Namewrapper.TransactOpts, node, ownerControlledFuses) +} + +// SetFuses is a paid mutator transaction binding the contract method 0x402906fc. +// +// Solidity: function setFuses(bytes32 node, uint16 ownerControlledFuses) returns(uint32 newFuses) +func (_Namewrapper *NamewrapperTransactorSession) SetFuses(node [32]byte, ownerControlledFuses uint16) (*types.Transaction, error) { + return _Namewrapper.Contract.SetFuses(&_Namewrapper.TransactOpts, node, ownerControlledFuses) +} + +// SetMetadataService is a paid mutator transaction binding the contract method 0x1534e177. +// +// Solidity: function setMetadataService(address _metadataService) returns() +func (_Namewrapper *NamewrapperTransactor) SetMetadataService(opts *bind.TransactOpts, _metadataService common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setMetadataService", _metadataService) +} + +// SetMetadataService is a paid mutator transaction binding the contract method 0x1534e177. +// +// Solidity: function setMetadataService(address _metadataService) returns() +func (_Namewrapper *NamewrapperSession) SetMetadataService(_metadataService common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.SetMetadataService(&_Namewrapper.TransactOpts, _metadataService) +} + +// SetMetadataService is a paid mutator transaction binding the contract method 0x1534e177. +// +// Solidity: function setMetadataService(address _metadataService) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetMetadataService(_metadataService common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.SetMetadataService(&_Namewrapper.TransactOpts, _metadataService) +} + +// SetRecord is a paid mutator transaction binding the contract method 0xcf408823. +// +// Solidity: function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) returns() +func (_Namewrapper *NamewrapperTransactor) SetRecord(opts *bind.TransactOpts, node [32]byte, owner common.Address, resolver common.Address, ttl uint64) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setRecord", node, owner, resolver, ttl) +} + +// SetRecord is a paid mutator transaction binding the contract method 0xcf408823. +// +// Solidity: function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) returns() +func (_Namewrapper *NamewrapperSession) SetRecord(node [32]byte, owner common.Address, resolver common.Address, ttl uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetRecord(&_Namewrapper.TransactOpts, node, owner, resolver, ttl) +} + +// SetRecord is a paid mutator transaction binding the contract method 0xcf408823. +// +// Solidity: function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetRecord(node [32]byte, owner common.Address, resolver common.Address, ttl uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetRecord(&_Namewrapper.TransactOpts, node, owner, resolver, ttl) +} + +// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. +// +// Solidity: function setResolver(bytes32 node, address resolver) returns() +func (_Namewrapper *NamewrapperTransactor) SetResolver(opts *bind.TransactOpts, node [32]byte, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setResolver", node, resolver) +} + +// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. +// +// Solidity: function setResolver(bytes32 node, address resolver) returns() +func (_Namewrapper *NamewrapperSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.SetResolver(&_Namewrapper.TransactOpts, node, resolver) +} + +// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. +// +// Solidity: function setResolver(bytes32 node, address resolver) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.SetResolver(&_Namewrapper.TransactOpts, node, resolver) +} + +// SetSubnodeOwner is a paid mutator transaction binding the contract method 0xc658e086. +// +// Solidity: function setSubnodeOwner(bytes32 node, string label, address newOwner, uint32 fuses, uint64 expiry) returns(bytes32) +func (_Namewrapper *NamewrapperTransactor) SetSubnodeOwner(opts *bind.TransactOpts, node [32]byte, label string, newOwner common.Address, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setSubnodeOwner", node, label, newOwner, fuses, expiry) +} + +// SetSubnodeOwner is a paid mutator transaction binding the contract method 0xc658e086. +// +// Solidity: function setSubnodeOwner(bytes32 node, string label, address newOwner, uint32 fuses, uint64 expiry) returns(bytes32) +func (_Namewrapper *NamewrapperSession) SetSubnodeOwner(node [32]byte, label string, newOwner common.Address, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetSubnodeOwner(&_Namewrapper.TransactOpts, node, label, newOwner, fuses, expiry) +} + +// SetSubnodeOwner is a paid mutator transaction binding the contract method 0xc658e086. +// +// Solidity: function setSubnodeOwner(bytes32 node, string label, address newOwner, uint32 fuses, uint64 expiry) returns(bytes32) +func (_Namewrapper *NamewrapperTransactorSession) SetSubnodeOwner(node [32]byte, label string, newOwner common.Address, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetSubnodeOwner(&_Namewrapper.TransactOpts, node, label, newOwner, fuses, expiry) +} + +// SetSubnodeRecord is a paid mutator transaction binding the contract method 0x24c1af44. +// +// Solidity: function setSubnodeRecord(bytes32 node, string label, address owner, address resolver, uint64 ttl, uint32 fuses, uint64 expiry) returns(bytes32) +func (_Namewrapper *NamewrapperTransactor) SetSubnodeRecord(opts *bind.TransactOpts, node [32]byte, label string, owner common.Address, resolver common.Address, ttl uint64, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setSubnodeRecord", node, label, owner, resolver, ttl, fuses, expiry) +} + +// SetSubnodeRecord is a paid mutator transaction binding the contract method 0x24c1af44. +// +// Solidity: function setSubnodeRecord(bytes32 node, string label, address owner, address resolver, uint64 ttl, uint32 fuses, uint64 expiry) returns(bytes32) +func (_Namewrapper *NamewrapperSession) SetSubnodeRecord(node [32]byte, label string, owner common.Address, resolver common.Address, ttl uint64, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetSubnodeRecord(&_Namewrapper.TransactOpts, node, label, owner, resolver, ttl, fuses, expiry) +} + +// SetSubnodeRecord is a paid mutator transaction binding the contract method 0x24c1af44. +// +// Solidity: function setSubnodeRecord(bytes32 node, string label, address owner, address resolver, uint64 ttl, uint32 fuses, uint64 expiry) returns(bytes32) +func (_Namewrapper *NamewrapperTransactorSession) SetSubnodeRecord(node [32]byte, label string, owner common.Address, resolver common.Address, ttl uint64, fuses uint32, expiry uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetSubnodeRecord(&_Namewrapper.TransactOpts, node, label, owner, resolver, ttl, fuses, expiry) +} + +// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. +// +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() +func (_Namewrapper *NamewrapperTransactor) SetTTL(opts *bind.TransactOpts, node [32]byte, ttl uint64) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setTTL", node, ttl) +} + +// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. +// +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() +func (_Namewrapper *NamewrapperSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetTTL(&_Namewrapper.TransactOpts, node, ttl) +} + +// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. +// +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { + return _Namewrapper.Contract.SetTTL(&_Namewrapper.TransactOpts, node, ttl) +} + +// SetUpgradeContract is a paid mutator transaction binding the contract method 0xb6bcad26. +// +// Solidity: function setUpgradeContract(address _upgradeAddress) returns() +func (_Namewrapper *NamewrapperTransactor) SetUpgradeContract(opts *bind.TransactOpts, _upgradeAddress common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "setUpgradeContract", _upgradeAddress) +} + +// SetUpgradeContract is a paid mutator transaction binding the contract method 0xb6bcad26. +// +// Solidity: function setUpgradeContract(address _upgradeAddress) returns() +func (_Namewrapper *NamewrapperSession) SetUpgradeContract(_upgradeAddress common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.SetUpgradeContract(&_Namewrapper.TransactOpts, _upgradeAddress) +} + +// SetUpgradeContract is a paid mutator transaction binding the contract method 0xb6bcad26. +// +// Solidity: function setUpgradeContract(address _upgradeAddress) returns() +func (_Namewrapper *NamewrapperTransactorSession) SetUpgradeContract(_upgradeAddress common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.SetUpgradeContract(&_Namewrapper.TransactOpts, _upgradeAddress) +} + +// Unwrap is a paid mutator transaction binding the contract method 0xd8c9921a. +// +// Solidity: function unwrap(bytes32 node, bytes32 label, address owner) returns() +func (_Namewrapper *NamewrapperTransactor) Unwrap(opts *bind.TransactOpts, node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "unwrap", node, label, owner) +} + +// Unwrap is a paid mutator transaction binding the contract method 0xd8c9921a. +// +// Solidity: function unwrap(bytes32 node, bytes32 label, address owner) returns() +func (_Namewrapper *NamewrapperSession) Unwrap(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.Unwrap(&_Namewrapper.TransactOpts, node, label, owner) +} + +// Unwrap is a paid mutator transaction binding the contract method 0xd8c9921a. +// +// Solidity: function unwrap(bytes32 node, bytes32 label, address owner) returns() +func (_Namewrapper *NamewrapperTransactorSession) Unwrap(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.Unwrap(&_Namewrapper.TransactOpts, node, label, owner) +} + +// UnwrapETH2LD is a paid mutator transaction binding the contract method 0x8b4dfa75. +// +// Solidity: function unwrapETH2LD(bytes32 label, address newRegistrant, address newController) returns() +func (_Namewrapper *NamewrapperTransactor) UnwrapETH2LD(opts *bind.TransactOpts, label [32]byte, newRegistrant common.Address, newController common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "unwrapETH2LD", label, newRegistrant, newController) +} + +// UnwrapETH2LD is a paid mutator transaction binding the contract method 0x8b4dfa75. +// +// Solidity: function unwrapETH2LD(bytes32 label, address newRegistrant, address newController) returns() +func (_Namewrapper *NamewrapperSession) UnwrapETH2LD(label [32]byte, newRegistrant common.Address, newController common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.UnwrapETH2LD(&_Namewrapper.TransactOpts, label, newRegistrant, newController) +} + +// UnwrapETH2LD is a paid mutator transaction binding the contract method 0x8b4dfa75. +// +// Solidity: function unwrapETH2LD(bytes32 label, address newRegistrant, address newController) returns() +func (_Namewrapper *NamewrapperTransactorSession) UnwrapETH2LD(label [32]byte, newRegistrant common.Address, newController common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.UnwrapETH2LD(&_Namewrapper.TransactOpts, label, newRegistrant, newController) +} + +// Upgrade is a paid mutator transaction binding the contract method 0xc93ab3fd. +// +// Solidity: function upgrade(bytes name, bytes extraData) returns() +func (_Namewrapper *NamewrapperTransactor) Upgrade(opts *bind.TransactOpts, name []byte, extraData []byte) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "upgrade", name, extraData) +} + +// Upgrade is a paid mutator transaction binding the contract method 0xc93ab3fd. +// +// Solidity: function upgrade(bytes name, bytes extraData) returns() +func (_Namewrapper *NamewrapperSession) Upgrade(name []byte, extraData []byte) (*types.Transaction, error) { + return _Namewrapper.Contract.Upgrade(&_Namewrapper.TransactOpts, name, extraData) +} + +// Upgrade is a paid mutator transaction binding the contract method 0xc93ab3fd. +// +// Solidity: function upgrade(bytes name, bytes extraData) returns() +func (_Namewrapper *NamewrapperTransactorSession) Upgrade(name []byte, extraData []byte) (*types.Transaction, error) { + return _Namewrapper.Contract.Upgrade(&_Namewrapper.TransactOpts, name, extraData) +} + +// Wrap is a paid mutator transaction binding the contract method 0xeb8ae530. +// +// Solidity: function wrap(bytes name, address wrappedOwner, address resolver) returns() +func (_Namewrapper *NamewrapperTransactor) Wrap(opts *bind.TransactOpts, name []byte, wrappedOwner common.Address, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "wrap", name, wrappedOwner, resolver) +} + +// Wrap is a paid mutator transaction binding the contract method 0xeb8ae530. +// +// Solidity: function wrap(bytes name, address wrappedOwner, address resolver) returns() +func (_Namewrapper *NamewrapperSession) Wrap(name []byte, wrappedOwner common.Address, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.Wrap(&_Namewrapper.TransactOpts, name, wrappedOwner, resolver) +} + +// Wrap is a paid mutator transaction binding the contract method 0xeb8ae530. +// +// Solidity: function wrap(bytes name, address wrappedOwner, address resolver) returns() +func (_Namewrapper *NamewrapperTransactorSession) Wrap(name []byte, wrappedOwner common.Address, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.Wrap(&_Namewrapper.TransactOpts, name, wrappedOwner, resolver) +} + +// WrapETH2LD is a paid mutator transaction binding the contract method 0x8cf8b41e. +// +// Solidity: function wrapETH2LD(string label, address wrappedOwner, uint16 ownerControlledFuses, address resolver) returns(uint64 expires) +func (_Namewrapper *NamewrapperTransactor) WrapETH2LD(opts *bind.TransactOpts, label string, wrappedOwner common.Address, ownerControlledFuses uint16, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.contract.Transact(opts, "wrapETH2LD", label, wrappedOwner, ownerControlledFuses, resolver) +} + +// WrapETH2LD is a paid mutator transaction binding the contract method 0x8cf8b41e. +// +// Solidity: function wrapETH2LD(string label, address wrappedOwner, uint16 ownerControlledFuses, address resolver) returns(uint64 expires) +func (_Namewrapper *NamewrapperSession) WrapETH2LD(label string, wrappedOwner common.Address, ownerControlledFuses uint16, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.WrapETH2LD(&_Namewrapper.TransactOpts, label, wrappedOwner, ownerControlledFuses, resolver) +} + +// WrapETH2LD is a paid mutator transaction binding the contract method 0x8cf8b41e. +// +// Solidity: function wrapETH2LD(string label, address wrappedOwner, uint16 ownerControlledFuses, address resolver) returns(uint64 expires) +func (_Namewrapper *NamewrapperTransactorSession) WrapETH2LD(label string, wrappedOwner common.Address, ownerControlledFuses uint16, resolver common.Address) (*types.Transaction, error) { + return _Namewrapper.Contract.WrapETH2LD(&_Namewrapper.TransactOpts, label, wrappedOwner, ownerControlledFuses, resolver) +} + +// NamewrapperApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the Namewrapper contract. +type NamewrapperApprovalForAllIterator struct { + Event *NamewrapperApprovalForAll // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperApprovalForAllIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperApprovalForAll) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperApprovalForAll) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperApprovalForAllIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperApprovalForAllIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperApprovalForAll represents a ApprovalForAll event raised by the Namewrapper contract. +type NamewrapperApprovalForAll struct { + Account common.Address + Operator common.Address + Approved bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) +func (_Namewrapper *NamewrapperFilterer) FilterApprovalForAll(opts *bind.FilterOpts, account []common.Address, operator []common.Address) (*NamewrapperApprovalForAllIterator, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "ApprovalForAll", accountRule, operatorRule) + if err != nil { + return nil, err + } + return &NamewrapperApprovalForAllIterator{contract: _Namewrapper.contract, event: "ApprovalForAll", logs: logs, sub: sub}, nil +} + +// WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) +func (_Namewrapper *NamewrapperFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *NamewrapperApprovalForAll, account []common.Address, operator []common.Address) (event.Subscription, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "ApprovalForAll", accountRule, operatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperApprovalForAll) + if err := _Namewrapper.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApprovalForAll is a log parse operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) +func (_Namewrapper *NamewrapperFilterer) ParseApprovalForAll(log types.Log) (*NamewrapperApprovalForAll, error) { + event := new(NamewrapperApprovalForAll) + if err := _Namewrapper.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperExpiryExtendedIterator is returned from FilterExpiryExtended and is used to iterate over the raw logs and unpacked data for ExpiryExtended events raised by the Namewrapper contract. +type NamewrapperExpiryExtendedIterator struct { + Event *NamewrapperExpiryExtended // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperExpiryExtendedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperExpiryExtended) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperExpiryExtended) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperExpiryExtendedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperExpiryExtendedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperExpiryExtended represents a ExpiryExtended event raised by the Namewrapper contract. +type NamewrapperExpiryExtended struct { + Node [32]byte + Expiry uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterExpiryExtended is a free log retrieval operation binding the contract event 0xf675815a0817338f93a7da433f6bd5f5542f1029b11b455191ac96c7f6a9b132. +// +// Solidity: event ExpiryExtended(bytes32 indexed node, uint64 expiry) +func (_Namewrapper *NamewrapperFilterer) FilterExpiryExtended(opts *bind.FilterOpts, node [][32]byte) (*NamewrapperExpiryExtendedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "ExpiryExtended", nodeRule) + if err != nil { + return nil, err + } + return &NamewrapperExpiryExtendedIterator{contract: _Namewrapper.contract, event: "ExpiryExtended", logs: logs, sub: sub}, nil +} + +// WatchExpiryExtended is a free log subscription operation binding the contract event 0xf675815a0817338f93a7da433f6bd5f5542f1029b11b455191ac96c7f6a9b132. +// +// Solidity: event ExpiryExtended(bytes32 indexed node, uint64 expiry) +func (_Namewrapper *NamewrapperFilterer) WatchExpiryExtended(opts *bind.WatchOpts, sink chan<- *NamewrapperExpiryExtended, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "ExpiryExtended", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperExpiryExtended) + if err := _Namewrapper.contract.UnpackLog(event, "ExpiryExtended", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseExpiryExtended is a log parse operation binding the contract event 0xf675815a0817338f93a7da433f6bd5f5542f1029b11b455191ac96c7f6a9b132. +// +// Solidity: event ExpiryExtended(bytes32 indexed node, uint64 expiry) +func (_Namewrapper *NamewrapperFilterer) ParseExpiryExtended(log types.Log) (*NamewrapperExpiryExtended, error) { + event := new(NamewrapperExpiryExtended) + if err := _Namewrapper.contract.UnpackLog(event, "ExpiryExtended", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperFusesSetIterator is returned from FilterFusesSet and is used to iterate over the raw logs and unpacked data for FusesSet events raised by the Namewrapper contract. +type NamewrapperFusesSetIterator struct { + Event *NamewrapperFusesSet // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperFusesSetIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperFusesSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperFusesSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperFusesSetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperFusesSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperFusesSet represents a FusesSet event raised by the Namewrapper contract. +type NamewrapperFusesSet struct { + Node [32]byte + Fuses uint32 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFusesSet is a free log retrieval operation binding the contract event 0x39873f00c80f4f94b7bd1594aebcf650f003545b74824d57ddf4939e3ff3a34b. +// +// Solidity: event FusesSet(bytes32 indexed node, uint32 fuses) +func (_Namewrapper *NamewrapperFilterer) FilterFusesSet(opts *bind.FilterOpts, node [][32]byte) (*NamewrapperFusesSetIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "FusesSet", nodeRule) + if err != nil { + return nil, err + } + return &NamewrapperFusesSetIterator{contract: _Namewrapper.contract, event: "FusesSet", logs: logs, sub: sub}, nil +} + +// WatchFusesSet is a free log subscription operation binding the contract event 0x39873f00c80f4f94b7bd1594aebcf650f003545b74824d57ddf4939e3ff3a34b. +// +// Solidity: event FusesSet(bytes32 indexed node, uint32 fuses) +func (_Namewrapper *NamewrapperFilterer) WatchFusesSet(opts *bind.WatchOpts, sink chan<- *NamewrapperFusesSet, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "FusesSet", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperFusesSet) + if err := _Namewrapper.contract.UnpackLog(event, "FusesSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFusesSet is a log parse operation binding the contract event 0x39873f00c80f4f94b7bd1594aebcf650f003545b74824d57ddf4939e3ff3a34b. +// +// Solidity: event FusesSet(bytes32 indexed node, uint32 fuses) +func (_Namewrapper *NamewrapperFilterer) ParseFusesSet(log types.Log) (*NamewrapperFusesSet, error) { + event := new(NamewrapperFusesSet) + if err := _Namewrapper.contract.UnpackLog(event, "FusesSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperNameUnwrappedIterator is returned from FilterNameUnwrapped and is used to iterate over the raw logs and unpacked data for NameUnwrapped events raised by the Namewrapper contract. +type NamewrapperNameUnwrappedIterator struct { + Event *NamewrapperNameUnwrapped // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperNameUnwrappedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperNameUnwrapped) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperNameUnwrapped) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperNameUnwrappedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperNameUnwrappedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperNameUnwrapped represents a NameUnwrapped event raised by the Namewrapper contract. +type NamewrapperNameUnwrapped struct { + Node [32]byte + Owner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNameUnwrapped is a free log retrieval operation binding the contract event 0xee2ba1195c65bcf218a83d874335c6bf9d9067b4c672f3c3bf16cf40de7586c4. +// +// Solidity: event NameUnwrapped(bytes32 indexed node, address owner) +func (_Namewrapper *NamewrapperFilterer) FilterNameUnwrapped(opts *bind.FilterOpts, node [][32]byte) (*NamewrapperNameUnwrappedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "NameUnwrapped", nodeRule) + if err != nil { + return nil, err + } + return &NamewrapperNameUnwrappedIterator{contract: _Namewrapper.contract, event: "NameUnwrapped", logs: logs, sub: sub}, nil +} + +// WatchNameUnwrapped is a free log subscription operation binding the contract event 0xee2ba1195c65bcf218a83d874335c6bf9d9067b4c672f3c3bf16cf40de7586c4. +// +// Solidity: event NameUnwrapped(bytes32 indexed node, address owner) +func (_Namewrapper *NamewrapperFilterer) WatchNameUnwrapped(opts *bind.WatchOpts, sink chan<- *NamewrapperNameUnwrapped, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "NameUnwrapped", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperNameUnwrapped) + if err := _Namewrapper.contract.UnpackLog(event, "NameUnwrapped", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseNameUnwrapped is a log parse operation binding the contract event 0xee2ba1195c65bcf218a83d874335c6bf9d9067b4c672f3c3bf16cf40de7586c4. +// +// Solidity: event NameUnwrapped(bytes32 indexed node, address owner) +func (_Namewrapper *NamewrapperFilterer) ParseNameUnwrapped(log types.Log) (*NamewrapperNameUnwrapped, error) { + event := new(NamewrapperNameUnwrapped) + if err := _Namewrapper.contract.UnpackLog(event, "NameUnwrapped", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperNameWrappedIterator is returned from FilterNameWrapped and is used to iterate over the raw logs and unpacked data for NameWrapped events raised by the Namewrapper contract. +type NamewrapperNameWrappedIterator struct { + Event *NamewrapperNameWrapped // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperNameWrappedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperNameWrapped) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperNameWrapped) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperNameWrappedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperNameWrappedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperNameWrapped represents a NameWrapped event raised by the Namewrapper contract. +type NamewrapperNameWrapped struct { + Node [32]byte + Name []byte + Owner common.Address + Fuses uint32 + Expiry uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNameWrapped is a free log retrieval operation binding the contract event 0x8ce7013e8abebc55c3890a68f5a27c67c3f7efa64e584de5fb22363c606fd340. +// +// Solidity: event NameWrapped(bytes32 indexed node, bytes name, address owner, uint32 fuses, uint64 expiry) +func (_Namewrapper *NamewrapperFilterer) FilterNameWrapped(opts *bind.FilterOpts, node [][32]byte) (*NamewrapperNameWrappedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "NameWrapped", nodeRule) + if err != nil { + return nil, err + } + return &NamewrapperNameWrappedIterator{contract: _Namewrapper.contract, event: "NameWrapped", logs: logs, sub: sub}, nil +} + +// WatchNameWrapped is a free log subscription operation binding the contract event 0x8ce7013e8abebc55c3890a68f5a27c67c3f7efa64e584de5fb22363c606fd340. +// +// Solidity: event NameWrapped(bytes32 indexed node, bytes name, address owner, uint32 fuses, uint64 expiry) +func (_Namewrapper *NamewrapperFilterer) WatchNameWrapped(opts *bind.WatchOpts, sink chan<- *NamewrapperNameWrapped, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "NameWrapped", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperNameWrapped) + if err := _Namewrapper.contract.UnpackLog(event, "NameWrapped", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseNameWrapped is a log parse operation binding the contract event 0x8ce7013e8abebc55c3890a68f5a27c67c3f7efa64e584de5fb22363c606fd340. +// +// Solidity: event NameWrapped(bytes32 indexed node, bytes name, address owner, uint32 fuses, uint64 expiry) +func (_Namewrapper *NamewrapperFilterer) ParseNameWrapped(log types.Log) (*NamewrapperNameWrapped, error) { + event := new(NamewrapperNameWrapped) + if err := _Namewrapper.contract.UnpackLog(event, "NameWrapped", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperTransferBatchIterator is returned from FilterTransferBatch and is used to iterate over the raw logs and unpacked data for TransferBatch events raised by the Namewrapper contract. +type NamewrapperTransferBatchIterator struct { + Event *NamewrapperTransferBatch // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperTransferBatchIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperTransferBatch) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperTransferBatch) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperTransferBatchIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperTransferBatchIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperTransferBatch represents a TransferBatch event raised by the Namewrapper contract. +type NamewrapperTransferBatch struct { + Operator common.Address + From common.Address + To common.Address + Ids []*big.Int + Values []*big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransferBatch is a free log retrieval operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. +// +// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) +func (_Namewrapper *NamewrapperFilterer) FilterTransferBatch(opts *bind.FilterOpts, operator []common.Address, from []common.Address, to []common.Address) (*NamewrapperTransferBatchIterator, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "TransferBatch", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &NamewrapperTransferBatchIterator{contract: _Namewrapper.contract, event: "TransferBatch", logs: logs, sub: sub}, nil +} + +// WatchTransferBatch is a free log subscription operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. +// +// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) +func (_Namewrapper *NamewrapperFilterer) WatchTransferBatch(opts *bind.WatchOpts, sink chan<- *NamewrapperTransferBatch, operator []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "TransferBatch", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperTransferBatch) + if err := _Namewrapper.contract.UnpackLog(event, "TransferBatch", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransferBatch is a log parse operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. +// +// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) +func (_Namewrapper *NamewrapperFilterer) ParseTransferBatch(log types.Log) (*NamewrapperTransferBatch, error) { + event := new(NamewrapperTransferBatch) + if err := _Namewrapper.contract.UnpackLog(event, "TransferBatch", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperTransferSingleIterator is returned from FilterTransferSingle and is used to iterate over the raw logs and unpacked data for TransferSingle events raised by the Namewrapper contract. +type NamewrapperTransferSingleIterator struct { + Event *NamewrapperTransferSingle // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperTransferSingleIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperTransferSingle) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperTransferSingle) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperTransferSingleIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperTransferSingleIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperTransferSingle represents a TransferSingle event raised by the Namewrapper contract. +type NamewrapperTransferSingle struct { + Operator common.Address + From common.Address + To common.Address + Id *big.Int + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransferSingle is a free log retrieval operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. +// +// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) +func (_Namewrapper *NamewrapperFilterer) FilterTransferSingle(opts *bind.FilterOpts, operator []common.Address, from []common.Address, to []common.Address) (*NamewrapperTransferSingleIterator, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "TransferSingle", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &NamewrapperTransferSingleIterator{contract: _Namewrapper.contract, event: "TransferSingle", logs: logs, sub: sub}, nil +} + +// WatchTransferSingle is a free log subscription operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. +// +// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) +func (_Namewrapper *NamewrapperFilterer) WatchTransferSingle(opts *bind.WatchOpts, sink chan<- *NamewrapperTransferSingle, operator []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "TransferSingle", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperTransferSingle) + if err := _Namewrapper.contract.UnpackLog(event, "TransferSingle", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransferSingle is a log parse operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. +// +// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) +func (_Namewrapper *NamewrapperFilterer) ParseTransferSingle(log types.Log) (*NamewrapperTransferSingle, error) { + event := new(NamewrapperTransferSingle) + if err := _Namewrapper.contract.UnpackLog(event, "TransferSingle", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NamewrapperURIIterator is returned from FilterURI and is used to iterate over the raw logs and unpacked data for URI events raised by the Namewrapper contract. +type NamewrapperURIIterator struct { + Event *NamewrapperURI // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NamewrapperURIIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NamewrapperURI) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NamewrapperURI) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NamewrapperURIIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NamewrapperURIIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NamewrapperURI represents a URI event raised by the Namewrapper contract. +type NamewrapperURI struct { + Value string + Id *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterURI is a free log retrieval operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. +// +// Solidity: event URI(string value, uint256 indexed id) +func (_Namewrapper *NamewrapperFilterer) FilterURI(opts *bind.FilterOpts, id []*big.Int) (*NamewrapperURIIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _Namewrapper.contract.FilterLogs(opts, "URI", idRule) + if err != nil { + return nil, err + } + return &NamewrapperURIIterator{contract: _Namewrapper.contract, event: "URI", logs: logs, sub: sub}, nil +} + +// WatchURI is a free log subscription operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. +// +// Solidity: event URI(string value, uint256 indexed id) +func (_Namewrapper *NamewrapperFilterer) WatchURI(opts *bind.WatchOpts, sink chan<- *NamewrapperURI, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _Namewrapper.contract.WatchLogs(opts, "URI", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NamewrapperURI) + if err := _Namewrapper.contract.UnpackLog(event, "URI", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseURI is a log parse operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. +// +// Solidity: event URI(string value, uint256 indexed id) +func (_Namewrapper *NamewrapperFilterer) ParseURI(log types.Log) (*NamewrapperURI, error) { + event := new(NamewrapperURI) + if err := _Namewrapper.contract.UnpackLog(event, "URI", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/crypto/README.md b/crypto/README.md new file mode 100644 index 0000000000..c188c2b96f --- /dev/null +++ b/crypto/README.md @@ -0,0 +1,300 @@ +# Crypto Package + +The crypto package provides a comprehensive set of cryptographic operations for the Status Go application. It offers a clean interface for cryptographic functions with support for multiple providers, primarily focused on Ethereum-compatible operations. + +## Overview + +This package provides: +- **Cryptographic primitives**: Key generation, signing, hashing, and address derivation +- **Provider abstraction**: Pluggable crypto providers for different implementations +- **Ethereum compatibility**: Full support for Ethereum cryptographic standards +- **Type safety**: Strongly typed cryptographic types (Address, Hash, etc.) + +## Package Structure + +``` +crypto/ +├── README.md # This file +├── crypto.go # Main crypto functions and provider management +├── interface.go # CryptoProvider interface definition +├── ethereum_crypto.go # Ethereum-specific crypto operations +├── types/ # Cryptographic type definitions +│ ├── address.go # Ethereum address type and operations +│ ├── hash.go # Hash type and operations +│ ├── hex.go # Hex encoding/decoding utilities +│ ├── utils.go # General crypto utilities +│ └── errors.go # Crypto-specific error types +└── geth/ # Geth crypto provider implementation + └── provider.go # Go-ethereum based crypto provider +``` + +## Quick Start + +### Basic Usage + +```go +import "github.com/status-im/status-go/crypto" + +// Generate a new private key +privateKey, err := crypto.GenerateKey() +if err != nil { + log.Fatal(err) +} + +// Derive address from public key +address := crypto.PubkeyToAddress(privateKey.PublicKey) + +// Compute Keccak256 hash +hash := crypto.Keccak256([]byte("Hello, World!")) + +// Sign data +signature, err := crypto.Sign(hash, privateKey) +if err != nil { + log.Fatal(err) +} +``` + +### Using Crypto Types + +```go +import ( + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +// Create address from hex string +addr := cryptotypes.Address("0x742d35Cc6634C0532925a3b8D4C9db96590c6d0b") + +// Create hash from hex string +hash := cryptotypes.Hash("0x1234567890abcdef...") + +// Convert to hex string +hexAddr := addr.Hex() +hexHash := hash.Hex() +``` + +## Core Functions + +### Key Management + +- `GenerateKey()` - Generate new ECDSA private key +- `HexToECDSA(hexkey)` - Convert hex string to private key +- `FromECDSA(prv)` - Convert private key to bytes +- `FromECDSAPub(pub)` - Convert public key to bytes + +### Address Operations + +- `PubkeyToAddress(pub)` - Derive Ethereum address from public key +- `CreateAddress(b, nonce)` - Create contract address from address and nonce + +### Hashing + +- `Keccak256(data...)` - Compute Keccak256 hash +- `Keccak256Hash(data...)` - Compute hash and return Hash type +- `TextHash(data)` - Hash text with Ethereum message prefix +- `TextAndHash(data)` - Hash text and return both hash and hex string + +### Signing + +- `Sign(digestHash, prv)` - Sign hash with private key +- `SignBytes(data, prv)` - Sign arbitrary data (hashes first) +- `SignBytesAsHex(data, prv)` - Sign data and return hex signature +- `SignStringAsHex(data, prv)` - Sign string and return hex signature +- `SigToPub(hash, sig)` - Recover public key from signature + +### Key Conversion + +- `ToECDSA(data)` - Convert bytes to private key +- `ToECDSAUnsafe(data)` - Convert bytes to private key without validation +- `DecompressPubkey(pubkey)` - Decompress compressed public key +- `CompressPubkey(pubkey)` - Compress public key to 33-byte format + +### Advanced Operations + +- `GenerateSharedKey(myKey, theirKey, sskLen)` - Generate shared secret key +- `S256()` - Get secp256k1 curve instance + +## Crypto Provider Interface + +The package uses a provider pattern to allow different cryptographic implementations: + +```go +type CryptoProvider interface { + S256() elliptic.Curve + GenerateKey() (*ecdsa.PrivateKey, error) + HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) + FromECDSA(prv *ecdsa.PrivateKey) []byte + FromECDSAPub(pub *ecdsa.PublicKey) []byte + PubkeyToAddress(p ecdsa.PublicKey) types.Address + Keccak256(data ...[]byte) []byte + ToECDSAUnsafe(data []byte) *ecdsa.PrivateKey + ToECDSA(d []byte) (*ecdsa.PrivateKey, error) + TextHash(data []byte) []byte + TextAndHash(data []byte) ([]byte, string) + Keccak256Hash(data ...[]byte) (h types.Hash) + Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) + SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) + UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) + CreateAddress(b types.Address, nonce uint64) types.Address + DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) + CompressPubkey(pubkey *ecdsa.PublicKey) []byte + GenerateSharedKey(myIdentityKey *ecdsa.PrivateKey, theirEphemeralKey *ecdsa.PublicKey, sskLen int) ([]byte, error) +} +``` + +### Setting Custom Provider + +```go +import "github.com/status-im/status-go/crypto" + +// Create custom provider +customProvider := &MyCryptoProvider{} + +// Set as default provider +crypto.SetProvider(customProvider) +``` + +## Types + +### Address + +Represents an Ethereum address (20 bytes): + +```go +type Address [20]byte + +// Methods: +func (a Address) Hex() string +func (a Address) String() string +func (a Address) Bytes() []byte +func (a Address) IsZero() bool +``` + +### Hash + +Represents a cryptographic hash (32 bytes): + +```go +type Hash [32]byte + +// Methods: +func (h Hash) Hex() string +func (h Hash) String() string +func (h Hash) Bytes() []byte +func (h Hash) IsZero() bool +``` + +## Error Handling + +The package provides structured error handling: + +```go +import "github.com/status-im/status-go/crypto/types" + +// Check for specific error types +if err != nil { + var cryptoErr *types.CryptoError + if errors.As(err, &cryptoErr) { + switch cryptoErr.Category { + case types.ErrorCategoryKey: + log.Printf("Key error: %s", cryptoErr.Message) + case types.ErrorCategoryHash: + log.Printf("Hash error: %s", cryptoErr.Message) + } + } +} +``` + +## Examples + +### Complete Key Generation and Address Derivation + +```go +package main + +import ( + "fmt" + "log" + + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +func main() { + // Generate new private key + privateKey, err := crypto.GenerateKey() + if err != nil { + log.Fatal("Failed to generate key:", err) + } + + // Derive address + address := crypto.PubkeyToAddress(privateKey.PublicKey) + + fmt.Printf("Generated address: %s\n", address.Hex()) + fmt.Printf("Private key (hex): %x\n", crypto.FromECDSA(privateKey)) +} +``` + +### Message Signing and Verification + +```go +package main + +import ( + "fmt" + "log" + + "github.com/status-im/status-go/crypto" +) + +func main() { + // Generate key + privateKey, err := crypto.GenerateKey() + if err != nil { + log.Fatal(err) + } + + // Message to sign + message := "Hello, Status!" + + // Sign message + signature, err := crypto.SignStringAsHex(message, privateKey) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Message: %s\n", message) + fmt.Printf("Signature: %s\n", signature) + + // Verify signature (recover public key) + hash := crypto.TextHash([]byte(message)) + sigBytes, _ := hex.DecodeString(signature) + recoveredPub, err := crypto.SigToPub(hash, sigBytes) + if err != nil { + log.Fatal("Signature verification failed:", err) + } + + fmt.Printf("Signature verified! Recovered public key: %x\n", crypto.FromECDSAPub(recoveredPub)) +} +``` + +## Dependencies + +- **Go** - For modern Go features +- **go-ethereum** - For Geth crypto provider implementation +- **crypto/ecdsa** - Standard Go ECDSA implementation +- **crypto/elliptic** - Standard Go elliptic curve operations + +## Contributing + +When contributing to this package: + +1. Follow Go best practices and conventions +2. Add tests for new functionality +3. Update this README for new features +4. Ensure compatibility with existing providers +5. Use the existing error types and patterns + +## License + +This package is part of the Status Go project and follows the same licensing terms. diff --git a/crypto/crypto.go b/crypto/crypto.go new file mode 100644 index 0000000000..4374deaede --- /dev/null +++ b/crypto/crypto.go @@ -0,0 +1,325 @@ +package crypto + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/hex" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/crypto" + + "github.com/status-im/status-go/crypto/geth" + "github.com/status-im/status-go/crypto/types" +) + +var defaultProvider CryptoProvider = geth.NewGethCryptoProvider() + +const ( + // Shared secret key length + sskLen = 16 + + aesNonceLength = 12 +) + +// SetProvider sets the default crypto provider +func SetProvider(provider CryptoProvider) { + defaultProvider = provider +} + +func S256() elliptic.Curve { + return defaultProvider.S256() +} + +func GenerateKey() (*ecdsa.PrivateKey, error) { + return defaultProvider.GenerateKey() +} + +func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) { + return defaultProvider.HexToECDSA(hexkey) +} + +func FromECDSA(prv *ecdsa.PrivateKey) []byte { + return defaultProvider.FromECDSA(prv) +} + +func FromECDSAPub(pub *ecdsa.PublicKey) []byte { + return defaultProvider.FromECDSAPub(pub) +} + +func PubkeyToAddress(p ecdsa.PublicKey) types.Address { + return defaultProvider.PubkeyToAddress(p) +} + +func Keccak256(data ...[]byte) []byte { + return defaultProvider.Keccak256(data...) +} + +func ToECDSAUnsafe(data []byte) *ecdsa.PrivateKey { + return defaultProvider.ToECDSAUnsafe(data) +} + +func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) { + return defaultProvider.ToECDSA(d) +} + +func TextHash(data []byte) []byte { + return defaultProvider.TextHash(data) +} + +func TextAndHash(data []byte) ([]byte, string) { + return defaultProvider.TextAndHash(data) +} + +func Keccak256Hash(data ...[]byte) (h types.Hash) { + return defaultProvider.Keccak256Hash(data...) +} + +func Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { + return defaultProvider.Sign(digestHash, prv) +} + +func SignBytes(data []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { + return Sign(Keccak256(data), prv) +} + +func SignBytesAsHex(data []byte, identity *ecdsa.PrivateKey) (string, error) { + signature, err := SignBytes(data, identity) + if err != nil { + return "", err + } + return hex.EncodeToString(signature), nil +} + +func SignStringAsHex(data string, identity *ecdsa.PrivateKey) (string, error) { + return SignBytesAsHex([]byte(data), identity) +} + +func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { + return defaultProvider.SigToPub(hash, sig) +} + +func CreateAddress(b types.Address, nonce uint64) types.Address { + return defaultProvider.CreateAddress(b, nonce) +} + +func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { + return defaultProvider.DecompressPubkey(pubkey) +} + +func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { + return defaultProvider.CompressPubkey(pubkey) +} + +func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { + return defaultProvider.UnmarshalPubkey(pub) +} + +func DecodePubkeyString(pubkey string) (*ecdsa.PublicKey, error) { + keyBytes, err := hex.DecodeString(pubkey) + if err != nil { + return nil, err + } + + key, err := crypto.UnmarshalPubkey(keyBytes) + if err != nil { + return nil, err + } + + return key, nil +} + +func MustDecodePubkeyString(pubkey string) *ecdsa.PublicKey { + pk, err := DecodePubkeyString(pubkey) + if err != nil { + panic(err) + } + return pk +} + +func VerifySignatures(signaturePairs [][3]string) error { + for _, signaturePair := range signaturePairs { + content := Keccak256([]byte(signaturePair[0])) + + signature, err := hex.DecodeString(signaturePair[1]) + if err != nil { + return err + } + + publicKeyBytes, err := hex.DecodeString(signaturePair[2]) + if err != nil { + return err + } + + publicKey, err := UnmarshalPubkey(publicKeyBytes) + if err != nil { + return err + } + + recoveredKey, err := SigToPub( + content, + signature, + ) + if err != nil { + return err + } + + if PubkeyToAddress(*recoveredKey) != PubkeyToAddress(*publicKey) { + return errors.New("identity key and signature mismatch") + } + } + + return nil +} + +func ExtractSignatures(signaturePairs [][2]string) ([]string, error) { + response := make([]string, len(signaturePairs)) + for i, signaturePair := range signaturePairs { + content := Keccak256([]byte(signaturePair[0])) + + signature, err := hex.DecodeString(signaturePair[1]) + if err != nil { + return nil, err + } + + recoveredKey, err := SigToPub( + content, + signature, + ) + if err != nil { + return nil, err + } + + response[i] = fmt.Sprintf("%x", FromECDSAPub(recoveredKey)) + } + + return response, nil +} + +// ExtractSignature returns a public key for a given data and signature. +func ExtractSignature(data, signature []byte) (*ecdsa.PublicKey, error) { + dataHash := Keccak256(data) + return SigToPub(dataHash, signature) +} + +func EcRecover(data types.HexBytes, sig types.HexBytes) (types.Address, error) { + // Returns the address for the Account that was used to create the signature. + // + // Note, this function is compatible with eth_sign and personal_sign. As such it recovers + // the address of: + // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // addr = ecrecover(hash, signature) + // + // Note, the signature must conform to the secp256k1 curve R, S and V values, where + // the V value must be be 27 or 28 for legacy reasons. + // + // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover + if len(sig) != 65 { + return types.Address{}, fmt.Errorf("signature must be 65 bytes long") + } + if sig[64] != 27 && sig[64] != 28 { + return types.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") + } + sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 + hash := TextHash(data) + rpk, err := SigToPub(hash, sig) + if err != nil { + return types.Address{}, err + } + return PubkeyToAddress(*rpk), nil +} + +func GenerateSharedKey(myIdentityKey *ecdsa.PrivateKey, theirEphemeralKey *ecdsa.PublicKey) ([]byte, error) { + return defaultProvider.GenerateSharedKey(myIdentityKey, theirEphemeralKey, sskLen) +} + +// DecryptWithDH decrypts message sent with a DH key exchange, and throws away the key after decryption +func DecryptWithDH(myIdentityKey *ecdsa.PrivateKey, theirEphemeralKey *ecdsa.PublicKey, payload []byte) ([]byte, error) { + key, err := GenerateSharedKey(myIdentityKey, theirEphemeralKey) + if err != nil { + return nil, err + } + + return DecryptSymmetric(key, payload) +} + +func DecryptSymmetric(key []byte, cyphertext []byte) ([]byte, error) { + // symmetric messages are expected to contain the 12-byte nonce at the end of the payload + if len(cyphertext) < aesNonceLength { + return nil, errors.New("missing salt or invalid payload in symmetric message") + } + salt := cyphertext[len(cyphertext)-aesNonceLength:] + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + decrypted, err := aesgcm.Open(nil, salt, cyphertext[:len(cyphertext)-aesNonceLength], nil) + if err != nil { + return nil, err + } + + return decrypted, nil +} + +func EncryptSymmetric(key, plaintext []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. + salt, err := generateSecureRandomData(aesNonceLength) + if err != nil { + return nil, err + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + encrypted := aesgcm.Seal(nil, salt, plaintext, nil) + return append(encrypted, salt...), nil +} + +func containsOnlyZeros(data []byte) bool { + for _, b := range data { + if b != 0 { + return false + } + } + return true +} + +func validateDataIntegrity(k []byte, expectedSize int) bool { + if len(k) != expectedSize { + return false + } + if containsOnlyZeros(k) { + return false + } + return true +} + +func generateSecureRandomData(length int) ([]byte, error) { + res := make([]byte, length) + + _, err := rand.Read(res) + if err != nil { + return nil, err + } + + if !validateDataIntegrity(res, length) { + return nil, errors.New("crypto/rand failed to generate secure random data") + } + + return res, nil +} diff --git a/crypto/ethereum_crypto.go b/crypto/ethereum_crypto.go new file mode 100644 index 0000000000..a47d13452d --- /dev/null +++ b/crypto/ethereum_crypto.go @@ -0,0 +1,188 @@ +package crypto + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "fmt" + "io" + + dr "github.com/status-im/doubleratchet" + "golang.org/x/crypto/hkdf" +) + +// EthereumCrypto is an implementation of Crypto with cryptographic primitives recommended +// by the Double Ratchet Algorithm specification. However, some details are different, +// see function comments for details. +type EthereumCrypto struct{} + +// See the Crypto interface. +func (c EthereumCrypto) GenerateDH() (dr.DHPair, error) { + keys, err := GenerateKey() + if err != nil { + return nil, err + } + + return DHPair{ + PubKey: CompressPubkey(&keys.PublicKey), + PrvKey: FromECDSA(keys), + }, nil + +} + +// See the Crypto interface. +func (c EthereumCrypto) DH(dhPair dr.DHPair, dhPub dr.Key) (dr.Key, error) { + tmpKey := dhPair.PrivateKey() + privateKey, err := ToECDSA(tmpKey) + if err != nil { + return nil, err + } + + publicKey, err := DecompressPubkey(dhPub) + if err != nil { + return nil, err + } + + key, err := GenerateSharedKey(privateKey, publicKey) + if err != nil { + return nil, err + } + + return key, nil +} + +// See the Crypto interface. +func (c EthereumCrypto) KdfRK(rk, dhOut dr.Key) (dr.Key, dr.Key, dr.Key) { + var ( + // We can use a non-secret constant as the last argument + r = hkdf.New(sha256.New, dhOut, rk, []byte("rsZUpEuXUqqwXBvSy3EcievAh4cMj6QL")) + buf = make([]byte, 96) + ) + + rootKey := make(dr.Key, 32) + chainKey := make(dr.Key, 32) + headerKey := make(dr.Key, 32) + + // The only error here is an entropy limit which won't be reached for such a short buffer. + _, _ = io.ReadFull(r, buf) + + copy(rootKey, buf[:32]) + copy(chainKey, buf[32:64]) + copy(headerKey, buf[64:96]) + return rootKey, chainKey, headerKey +} + +// See the Crypto interface. +func (c EthereumCrypto) KdfCK(ck dr.Key) (dr.Key, dr.Key) { + const ( + ckInput = 15 + mkInput = 16 + ) + + chainKey := make(dr.Key, 32) + msgKey := make(dr.Key, 32) + + h := hmac.New(sha256.New, ck) + + _, _ = h.Write([]byte{ckInput}) + copy(chainKey, h.Sum(nil)) + h.Reset() + + _, _ = h.Write([]byte{mkInput}) + copy(msgKey, h.Sum(nil)) + + return chainKey, msgKey +} + +// Encrypt uses a slightly different approach than in the algorithm specification: +// it uses AES-256-CTR instead of AES-256-CBC for security, ciphertext length and implementation +// complexity considerations. +func (c EthereumCrypto) Encrypt(mk dr.Key, plaintext, ad []byte) ([]byte, error) { + encKey, authKey, iv := c.deriveEncKeys(mk) + + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + copy(ciphertext, iv[:]) + + block, err := aes.NewCipher(encKey) + if err != nil { + return nil, err + } + + stream := cipher.NewCTR(block, iv[:]) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + + return append(ciphertext, c.computeSignature(authKey, ciphertext, ad)...), nil +} + +// See the Crypto interface. +func (c EthereumCrypto) Decrypt(mk dr.Key, authCiphertext, ad []byte) ([]byte, error) { + var ( + l = len(authCiphertext) + ciphertext = authCiphertext[:l-sha256.Size] + signature = authCiphertext[l-sha256.Size:] + ) + + // Check the signature. + encKey, authKey, _ := c.deriveEncKeys(mk) + + if s := c.computeSignature(authKey, ciphertext, ad); !bytes.Equal(s, signature) { + return nil, fmt.Errorf("invalid signature") + } + + // Decrypt. + block, err := aes.NewCipher(encKey) + if err != nil { + return nil, err + } + + stream := cipher.NewCTR(block, ciphertext[:aes.BlockSize]) + plaintext := make([]byte, len(ciphertext[aes.BlockSize:])) + + stream.XORKeyStream(plaintext, ciphertext[aes.BlockSize:]) + + return plaintext, nil +} + +// deriveEncKeys derive keys for message encryption and decryption. Returns (encKey, authKey, iv, err). +func (c EthereumCrypto) deriveEncKeys(mk dr.Key) (dr.Key, dr.Key, [16]byte) { + // First, derive encryption and authentication key out of mk. + salt := make([]byte, 32) + var ( + r = hkdf.New(sha256.New, mk, salt, []byte("pcwSByyx2CRdryCffXJwy7xgVZWtW5Sh")) + buf = make([]byte, 80) + ) + + encKey := make(dr.Key, 32) + authKey := make(dr.Key, 32) + var iv [16]byte + + // The only error here is an entropy limit which won't be reached for such a short buffer. + _, _ = io.ReadFull(r, buf) + + copy(encKey, buf[0:32]) + copy(authKey, buf[32:64]) + copy(iv[:], buf[64:80]) + return encKey, authKey, iv +} + +func (c EthereumCrypto) computeSignature(authKey, ciphertext, associatedData []byte) []byte { + h := hmac.New(sha256.New, authKey) + _, _ = h.Write(associatedData) + _, _ = h.Write(ciphertext) + return h.Sum(nil) +} + +type DHPair struct { + PrvKey dr.Key + PubKey dr.Key +} + +func (p DHPair) PrivateKey() dr.Key { + return p.PrvKey +} + +func (p DHPair) PublicKey() dr.Key { + return p.PubKey +} diff --git a/crypto/geth/provider.go b/crypto/geth/provider.go new file mode 100644 index 0000000000..05c51d40be --- /dev/null +++ b/crypto/geth/provider.go @@ -0,0 +1,106 @@ +package geth + +import ( + "crypto/ecdsa" + "crypto/elliptic" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/status-im/status-go/crypto/types" +) + +// GethCryptoProvider implements the CryptoProvider interface using go-ethereum +type GethCryptoProvider struct{} + +// NewGethCryptoProvider creates a new GethCryptoProvider instance +func NewGethCryptoProvider() *GethCryptoProvider { + return &GethCryptoProvider{} +} + +func (g *GethCryptoProvider) S256() elliptic.Curve { + return secp256k1.S256() +} + +func (g *GethCryptoProvider) GenerateKey() (*ecdsa.PrivateKey, error) { + return crypto.GenerateKey() +} + +func (g *GethCryptoProvider) HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) { + return crypto.HexToECDSA(hexkey) +} + +func (g *GethCryptoProvider) ToECDSA(d []byte) (*ecdsa.PrivateKey, error) { + return crypto.ToECDSA(d) +} + +func (g *GethCryptoProvider) FromECDSA(prv *ecdsa.PrivateKey) []byte { + return crypto.FromECDSA(prv) +} + +func (g *GethCryptoProvider) FromECDSAPub(pub *ecdsa.PublicKey) []byte { + return crypto.FromECDSAPub(pub) +} + +func (g *GethCryptoProvider) PubkeyToAddress(p ecdsa.PublicKey) types.Address { + address := crypto.PubkeyToAddress(p) + return types.Address(address) +} + +func (g *GethCryptoProvider) Keccak256(data ...[]byte) []byte { + return crypto.Keccak256(data...) +} + +func (g *GethCryptoProvider) ToECDSAUnsafe(data []byte) *ecdsa.PrivateKey { + return crypto.ToECDSAUnsafe(data) +} + +func (g *GethCryptoProvider) TextHash(data []byte) []byte { + return accounts.TextHash(data) +} + +func (g *GethCryptoProvider) TextAndHash(data []byte) ([]byte, string) { + return accounts.TextAndHash(data) +} + +func (g *GethCryptoProvider) Keccak256Hash(data ...[]byte) (h types.Hash) { + return types.Hash(crypto.Keccak256Hash(data...)) +} + +func (g *GethCryptoProvider) Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { + return crypto.Sign(digestHash, prv) +} + +func (g *GethCryptoProvider) SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { + return crypto.SigToPub(hash, sig) +} + +func (g *GethCryptoProvider) UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { + return crypto.UnmarshalPubkey(pub) +} + +func (g *GethCryptoProvider) CreateAddress(b types.Address, nonce uint64) types.Address { + return types.Address(crypto.CreateAddress(common.Address(b), nonce)) +} + +func (g *GethCryptoProvider) DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { + return crypto.DecompressPubkey(pubkey) +} + +func (g *GethCryptoProvider) CompressPubkey(pubkey *ecdsa.PublicKey) []byte { + return crypto.CompressPubkey(pubkey) +} + +// GenerateSharedKey generates a shared key given a private and a public key +func (g *GethCryptoProvider) GenerateSharedKey(myIdentityKey *ecdsa.PrivateKey, theirEphemeralKey *ecdsa.PublicKey, sskLen int) ([]byte, error) { + eciesPrivate := ecies.ImportECDSA(myIdentityKey) + eciesPublic := ecies.ImportECDSAPublic(theirEphemeralKey) + + return eciesPrivate.GenerateShared( + eciesPublic, + sskLen, + sskLen, + ) +} diff --git a/crypto/interface.go b/crypto/interface.go new file mode 100644 index 0000000000..443dd9856c --- /dev/null +++ b/crypto/interface.go @@ -0,0 +1,90 @@ +package crypto + +import ( + "crypto/ecdsa" + "crypto/elliptic" + + "github.com/status-im/status-go/crypto/types" +) + +const SignatureLength = 64 + 1 // 64 bytes ECDSA signature + 1 byte recovery id + +// CryptoProvider defines the interface for cryptographic operations +type CryptoProvider interface { + // S256 returns an instance of the secp256k1 curve. + S256() elliptic.Curve + + // GenerateKey generates a new ECDSA private key. + GenerateKey() (*ecdsa.PrivateKey, error) + + // HexToECDSA converts a hex string to an ECDSA private key + HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) + + // FromECDSA converts an ECDSA private key to bytes + FromECDSA(prv *ecdsa.PrivateKey) []byte + + // FromECDSAPub converts an ECDSA public key to bytes + FromECDSAPub(pub *ecdsa.PublicKey) []byte + + // PubkeyToAddress derives an Ethereum address from a public key + PubkeyToAddress(p ecdsa.PublicKey) types.Address + + // Keccak256 computes the Keccak256 hash of the concatenated data + Keccak256(data ...[]byte) []byte + + // ToECDSAUnsafe converts bytes to an ECDSA private key (unsafe - no validation) + ToECDSAUnsafe(data []byte) *ecdsa.PrivateKey + + // ToECDSA creates a private key with the given D value. + ToECDSA(d []byte) (*ecdsa.PrivateKey, error) + + // TextHash is a helper function that calculates a hash for the given message that can be safely used to calculate a signature from. + // + // The hash is calulcated as + // + // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). + // + // This gives context to the signed message and prevents signing of transactions. + TextHash(data []byte) []byte + + // TextAndHash is a helper function that calculates a hash for the given message that can be safely used to calculate a signature from. + // + // The hash is calulcated as + // + // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). + // + // This gives context to the signed message and prevents signing of transactions. + TextAndHash(data []byte) ([]byte, string) + + // Keccak256Hash calculates and returns the Keccak256 hash of the input data, + // converting it to an internal Hash data structure. + Keccak256Hash(data ...[]byte) (h types.Hash) + + // Sign calculates an ECDSA signature. + // + // This function is susceptible to chosen plaintext attacks that can leak + // information about the private key that is used for signing. Callers must + // be aware that the given digest cannot be chosen by an adversery. Common + // solution is to hash any input before calculating the signature. + // + // The produced signature is in the [R || S || V] format where V is 0 or 1. + Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) + + // SigToPub returns the public key that created the given signature. + SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) + + // UnmarshalPubkey converts bytes to a secp256k1 public key. + UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) + + // CreateAddress creates an ethereum address given the bytes and the nonce + CreateAddress(b types.Address, nonce uint64) types.Address + + // DecompressPubkey decompresses a public key from the 33-byte compressed format. + DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) + + // CompressPubkey encodes a public key to the 33-byte compressed format. + CompressPubkey(pubkey *ecdsa.PublicKey) []byte + + // GenerateSharedKey generates a shared key given a private and a public key + GenerateSharedKey(myIdentityKey *ecdsa.PrivateKey, theirEphemeralKey *ecdsa.PublicKey, sskLen int) ([]byte, error) +} diff --git a/crypto/types/address.go b/crypto/types/address.go new file mode 100644 index 0000000000..baf0c900d7 --- /dev/null +++ b/crypto/types/address.go @@ -0,0 +1,215 @@ +package types + +import ( + "database/sql/driver" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "reflect" + "strings" + + "golang.org/x/crypto/sha3" +) + +// AddressBytesLength is the expected length of the address in bytes +const AddressBytesLength = 20 + +// AddressHexLength is the expected length of the address in hex (with 0x prefix) +const AddressHexLength = 2*AddressBytesLength + 2 + +func ZeroAddress() Address { + return Address{} +} + +var ( + addressT = reflect.TypeOf(Address{}) +) + +// Address represents the 20 byte address of an Ethereum account. +type Address [AddressBytesLength]byte + +// BytesToAddress returns Address with value b. +// If b is larger than len(h), b will be cropped from the left. +func BytesToAddress(b []byte) Address { + var a Address + a.SetBytes(b) + return a +} + +// BigToAddress returns Address with byte values of b. +// If b is larger than len(h), b will be cropped from the left. +func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } + +// HexToAddress returns Address with byte values of s. +// If s is larger than len(h), s will be cropped from the left. +func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } + +// Bytes gets the string representation of the underlying address. +func (a Address) Bytes() []byte { return a[:] } + +// Hash converts an address to a hash by left-padding it with zeros. +func (a Address) Hash() Hash { return BytesToHash(a[:]) } + +// Hex returns an EIP55-compliant hex string representation of the address. +func (a Address) Hex() string { + unchecksummed := hex.EncodeToString(a[:]) + sha := sha3.NewLegacyKeccak256() + _, _ = sha.Write([]byte(unchecksummed)) + hash := sha.Sum(nil) + + result := []byte(unchecksummed) + for i := 0; i < len(result); i++ { + hashByte := hash[i/2] + if i%2 == 0 { + hashByte = hashByte >> 4 + } else { + hashByte &= 0xf + } + if result[i] > '9' && hashByte > 7 { + result[i] -= 32 + } + } + return "0x" + string(result) +} + +// String implements fmt.Stringer. +func (a Address) String() string { + return a.Hex() +} + +// Format implements fmt.Formatter, forcing the byte slice to be formatted as is, +// without going through the stringer interface used for logging. +func (a Address) Format(s fmt.State, c rune) { + fmt.Fprintf(s, "%"+string(c), a[:]) +} + +// SetBytes sets the address to the value of b. +// If b is larger than len(a) it will panic. +func (a *Address) SetBytes(b []byte) { + if len(b) > len(a) { + b = b[len(b)-AddressBytesLength:] + } + copy(a[AddressBytesLength-len(b):], b) +} + +// MarshalText returns the hex representation of a. +func (a Address) MarshalText() ([]byte, error) { + return HexBytes(a[:]).MarshalText() +} + +// UnmarshalText parses a hash in hex syntax. +func (a *Address) UnmarshalText(input []byte) error { + return UnmarshalFixedText("Address", input, a[:]) +} + +// UnmarshalJSON parses a hash in hex syntax. +func (a *Address) UnmarshalJSON(input []byte) error { + return UnmarshalFixedJSON(addressT, input, a[:]) +} + +// Scan implements Scanner for database/sql. +func (a *Address) Scan(src interface{}) error { + srcB, ok := src.([]byte) + if !ok { + return fmt.Errorf("can't scan %T into Address", src) + } + if len(srcB) != AddressBytesLength { + return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), AddressBytesLength) + } + copy(a[:], srcB) + return nil +} + +// Value implements valuer for database/sql. +func (a Address) Value() (driver.Value, error) { + return a[:], nil +} + +// ImplementsGraphQLType returns true if Hash implements the specified GraphQL type. +func (a Address) ImplementsGraphQLType(name string) bool { return name == "Address" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (a *Address) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + err = a.UnmarshalText([]byte(input)) + default: + err = fmt.Errorf("Unexpected type for Address: %v", input) + } + return err +} + +// UnprefixedAddress allows marshaling an Address without 0x prefix. +type UnprefixedAddress Address + +// UnmarshalText decodes the address from hex. The 0x prefix is optional. +func (a *UnprefixedAddress) UnmarshalText(input []byte) error { + return UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:]) +} + +// MarshalText encodes the address as hex. +func (a UnprefixedAddress) MarshalText() ([]byte, error) { + return []byte(hex.EncodeToString(a[:])), nil +} + +// MixedcaseAddress retains the original string, which may or may not be +// correctly checksummed +type MixedcaseAddress struct { + addr Address + original string +} + +// NewMixedcaseAddress constructor (mainly for testing) +func NewMixedcaseAddress(addr Address) MixedcaseAddress { + return MixedcaseAddress{addr: addr, original: addr.Hex()} +} + +// NewMixedcaseAddressFromString is mainly meant for unit-testing +func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) { + if !IsHexAddress(hexaddr) { + return nil, fmt.Errorf("Invalid address") + } + a := FromHex(hexaddr) + return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil +} + +// UnmarshalJSON parses MixedcaseAddress +func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error { + if err := UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil { + return err + } + return json.Unmarshal(input, &ma.original) +} + +// MarshalJSON marshals the original value +func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { + if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { + return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) + } + return json.Marshal(fmt.Sprintf("0x%s", ma.original)) +} + +// Address returns the address +func (ma *MixedcaseAddress) Address() Address { + return ma.addr +} + +// String implements fmt.Stringer +func (ma *MixedcaseAddress) String() string { + if ma.ValidChecksum() { + return fmt.Sprintf("%s [chksum ok]", ma.original) + } + return fmt.Sprintf("%s [chksum INVALID]", ma.original) +} + +// ValidChecksum returns true if the address has valid checksum +func (ma *MixedcaseAddress) ValidChecksum() bool { + return ma.original == ma.addr.Hex() +} + +// Original returns the mixed-case input string +func (ma *MixedcaseAddress) Original() string { + return ma.original +} diff --git a/crypto/types/errors.go b/crypto/types/errors.go new file mode 100644 index 0000000000..0e29caba7f --- /dev/null +++ b/crypto/types/errors.go @@ -0,0 +1,61 @@ +// Code extracted from vendor/github.com/ethereum/go-ethereum/common/hexutil/hexutil.go + +package types + +import ( + "encoding/hex" + "fmt" + "strconv" +) + +const ( + badNibble = ^uint64(0) + uintBits = 32 << (uint64(^uint(0)) >> 63) +) + +type decError struct{ msg string } + +func (err decError) Error() string { return err.msg } + +var ( + ErrEmptyString = &decError{"empty hex string"} + ErrSyntax = &decError{"invalid hex string"} + ErrMissingPrefix = &decError{"hex string without 0x prefix"} + ErrOddLength = &decError{"hex string of odd length"} + ErrEmptyNumber = &decError{"hex string \"0x\""} + ErrLeadingZero = &decError{"hex number with leading zero digits"} + ErrUint64Range = &decError{"hex number > 64 bits"} + ErrUintRange = &decError{fmt.Sprintf("hex number > %d bits", uintBits)} + ErrBig256Range = &decError{"hex number > 256 bits"} +) + +func mapError(err error) error { + if err, ok := err.(*strconv.NumError); ok { + switch err.Err { + case strconv.ErrRange: + return ErrUint64Range + case strconv.ErrSyntax: + return ErrSyntax + } + } + if _, ok := err.(hex.InvalidByteError); ok { + return ErrSyntax + } + if err == hex.ErrLength { + return ErrOddLength + } + return err +} + +func decodeNibble(in byte) uint64 { + switch { + case in >= '0' && in <= '9': + return uint64(in - '0') + case in >= 'A' && in <= 'F': + return uint64(in - 'A' + 10) + case in >= 'a' && in <= 'f': + return uint64(in - 'a' + 10) + default: + return badNibble + } +} diff --git a/crypto/types/hash.go b/crypto/types/hash.go new file mode 100644 index 0000000000..5c9d7c0e88 --- /dev/null +++ b/crypto/types/hash.go @@ -0,0 +1,119 @@ +// Code extracted from vendor/github.com/ethereum/go-ethereum/common/types.go + +package types + +import ( + "encoding/hex" + "fmt" + "reflect" +) + +const ( + // HashLength is the expected length of the hash + HashLength = 32 +) + +// Hash represents the 32 byte Keccak256 hash of arbitrary data. +type Hash [HashLength]byte + +var hashT = reflect.TypeOf(Hash{}) + +// Encode encodes b as a hex string with 0x prefix. +func encode(b []byte) string { + enc := make([]byte, len(b)*2+2) + copy(enc, "0x") + hex.Encode(enc[2:], b) + return string(enc) +} + +// FromHex returns the bytes represented by the hexadecimal string s. +// s may be prefixed with "0x". +func FromHex(s string) []byte { + if has0xPrefix(s) { + s = s[2:] + } + if len(s)%2 == 1 { + s = "0" + s + } + return Hex2Bytes(s) +} + +// HexToHash sets byte representation of s to hash. +// If b is larger than len(h), b will be cropped from the left. +func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } + +// Hex converts a hash to a hex string. +func (h *Hash) Hex() string { return encode(h[:]) } + +// Bytes gets the byte representation of the underlying hash. +func (h Hash) Bytes() []byte { return h[:] } + +// String implements the stringer interface and is used also by the logger when +// doing full logging into a file. +func (h Hash) String() string { + return h.Hex() +} + +// SetBytes sets the hash to the value of b. +// If b is larger than len(h), b will be cropped from the left. +func (h *Hash) SetBytes(b []byte) { + if len(b) > len(h) { + b = b[len(b)-HashLength:] + } + + copy(h[HashLength-len(b):], b) +} + +// UnmarshalText parses a hash in hex syntax. +func (h *Hash) UnmarshalText(input []byte) error { + return UnmarshalFixedText("Hash", input, h[:]) +} + +// UnmarshalJSON parses a hash in hex syntax. +func (h *Hash) UnmarshalJSON(input []byte) error { + return UnmarshalFixedJSON(hashT, input, h[:]) +} + +// MarshalText returns the hex representation of h. +func (h Hash) MarshalText() ([]byte, error) { + return HexBytes(h[:]).MarshalText() +} + +// BytesToHash sets b to hash. +// If b is larger than len(h), b will be cropped from the left. +func BytesToHash(b []byte) Hash { + var h Hash + h.SetBytes(b) + return h +} + +// UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length of out +// determines the required input length. This function is commonly used to implement the +// UnmarshalJSON method for fixed-size types. +func UnmarshalFixedJSON(typ reflect.Type, input, out []byte) error { + if !isString(input) { + return errNonString(typ) + } + return wrapTypeError(UnmarshalFixedText(typ.String(), input[1:len(input)-1], out), typ) +} + +// UnmarshalFixedText decodes the input as a string with 0x prefix. The length of out +// determines the required input length. This function is commonly used to implement the +// UnmarshalText method for fixed-size types. +func UnmarshalFixedText(typname string, input, out []byte) error { + raw, err := checkText(input, true) + if err != nil { + return err + } + if len(raw)/2 != len(out) { + return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname) + } + // Pre-verify syntax before modifying out. + for _, b := range raw { + if decodeNibble(b) == badNibble { + return ErrSyntax + } + } + _, err = hex.Decode(out, raw) + return err +} diff --git a/crypto/types/hex.go b/crypto/types/hex.go new file mode 100644 index 0000000000..f7e6b1da05 --- /dev/null +++ b/crypto/types/hex.go @@ -0,0 +1,78 @@ +// Code extracted from vendor/github.com/ethereum/go-ethereum/common/hexutil/hexutil.go + +package types + +import ( + "encoding/hex" + "fmt" + "reflect" +) + +var ( + bytesT = reflect.TypeOf(HexBytes(nil)) +) + +// HexBytes marshals/unmarshals as a JSON string with 0x prefix. +// The empty slice marshals as "0x". +type HexBytes []byte + +func (b HexBytes) Bytes() []byte { + result := make([]byte, len(b)*2+2) + copy(result, `0x`) + hex.Encode(result[2:], b) + return result +} + +// String returns the hex encoding of b. +func (b HexBytes) String() string { + return EncodeHex(b) +} + +// MarshalText implements encoding.TextMarshaler +func (b HexBytes) MarshalText() ([]byte, error) { + return b.Bytes(), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (b *HexBytes) UnmarshalJSON(input []byte) error { + if !isString(input) { + return errNonString(bytesT) + } + return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bytesT) +} + +// UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The +// length of out determines the required input length. This function is commonly used to +// implement the UnmarshalText method for fixed-size types. +func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error { + raw, err := checkText(input, false) + if err != nil { + return err + } + if len(raw)/2 != len(out) { + return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname) + } + // Pre-verify syntax before modifying out. + for _, b := range raw { + if decodeNibble(b) == badNibble { + return ErrSyntax + } + } + _, err = hex.Decode(out, raw) + return err +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (b *HexBytes) UnmarshalText(input []byte) error { + raw, err := checkText(input, true) + if err != nil { + return err + } + dec := make([]byte, len(raw)/2) + if _, err = hex.Decode(dec, raw); err != nil { + err = mapError(err) + } else { + *b = dec + } + return err +} diff --git a/crypto/types/utils.go b/crypto/types/utils.go new file mode 100644 index 0000000000..c937cf2ea6 --- /dev/null +++ b/crypto/types/utils.go @@ -0,0 +1,123 @@ +package types + +import ( + "encoding/hex" + "encoding/json" + "reflect" +) + +func isString(input []byte) bool { + return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' +} + +func errNonString(typ reflect.Type) error { + return &json.UnmarshalTypeError{Value: "non-string", Type: typ} +} + +func wrapTypeError(err error, typ reflect.Type) error { + if _, ok := err.(*decError); ok { + return &json.UnmarshalTypeError{Value: err.Error(), Type: typ} + } + return err +} + +// has0xPrefix validates str begins with '0x' or '0X'. +func has0xPrefix(str string) bool { + return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') +} + +func IsHexAddress(s string) bool { + if has0xPrefix(s) { + s = s[2:] + } + return len(s) == 2*AddressBytesLength && isHex(s) +} + +// isHexCharacter returns bool of c being a valid hexadecimal. +func isHexCharacter(c byte) bool { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') +} + +// isHex validates whether each byte is valid hexadecimal string. +func isHex(str string) bool { + if len(str)%2 != 0 { + return false + } + for _, c := range []byte(str) { + if !isHexCharacter(c) { + return false + } + } + return true +} + +// Hex2Bytes returns the bytes represented by the hexadecimal string str. +func Hex2Bytes(str string) []byte { + if has0xPrefix(str) { + str = str[2:] + } + + h, _ := hex.DecodeString(str) + return h +} + +// Bytes2Hex returns the hexadecimal encoding of d. +func Bytes2Hex(d []byte) string { + return hex.EncodeToString(d) +} + +// ToHex returns the hex string representation of bytes with 0x prefix. +func ToHex(bytes []byte) string { + return "0x" + Bytes2Hex(bytes) +} + +// EncodeHex encodes b as a hex string with 0x prefix. +func EncodeHex(b []byte) string { + enc := make([]byte, len(b)*2+2) + copy(enc, "0x") + hex.Encode(enc[2:], b) + return string(enc) +} + +// EncodeHex encodes bs as a hex strings with 0x prefix. +func EncodeHexes(bs [][]byte) []string { + result := make([]string, len(bs)) + for i, b := range bs { + result[i] = EncodeHex(b) + } + return result +} + +// DecodeHex decodes a hex string with 0x prefix. +func DecodeHex(input string) ([]byte, error) { + if len(input) == 0 { + return nil, ErrEmptyString + } + if !has0xPrefix(input) { + return nil, ErrMissingPrefix + } + b, err := hex.DecodeString(input[2:]) + if err != nil { + err = mapError(err) + } + return b, err +} + +func bytesHave0xPrefix(input []byte) bool { + return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') +} + +func checkText(input []byte, wantPrefix bool) ([]byte, error) { + if len(input) == 0 { + return nil, nil // empty strings are allowed + } + if bytesHave0xPrefix(input) { + input = input[2:] + } else if wantPrefix { + return nil, ErrMissingPrefix + } + if len(input)%2 != 0 { + return nil, ErrOddLength + } + return input, nil +} diff --git a/crypto/types/utils_test.go b/crypto/types/utils_test.go new file mode 100644 index 0000000000..177fe38d0a --- /dev/null +++ b/crypto/types/utils_test.go @@ -0,0 +1,81 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIsHexCharacter(t *testing.T) { + tests := []struct { + character string + want bool + }{ + {"0", true}, + {"1", true}, + {"2", true}, + {"3", true}, + {"4", true}, + {"5", true}, + {"6", true}, + {"7", true}, + {"8", true}, + {"9", true}, + {"a", true}, + {"b", true}, + {"c", true}, + {"d", true}, + {"e", true}, + {"f", true}, + {"A", true}, + {"B", true}, + {"C", true}, + {"D", true}, + {"E", true}, + {"F", true}, + {"-", false}, + {".", false}, + {"_", false}, + {" ", false}, + {"x", false}, + {"X", false}, + {"h", false}, + {"H", false}, + } + + for _, test := range tests { + t.Run(test.character, func(t *testing.T) { + got := isHexCharacter([]byte(test.character)[0]) + require.Equal(t, test.want, got) + }) + } +} + +func TestIsHexAddress(t *testing.T) { + tests := []struct { + address string + has0x bool + isHex bool + isHexAddress bool + }{ + {"0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa", true, false, true}, + {"aAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa", false, true, true}, + {"0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaA", true, false, false}, + {"aAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaA", false, false, false}, + {"0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaa", true, false, false}, + {"aAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaa", false, true, false}, + } + + for _, test := range tests { + t.Run(test.address, func(t *testing.T) { + gotHas0x := has0xPrefix(test.address) + require.Equal(t, test.has0x, gotHas0x) + + gotIsHex := isHex(test.address) + require.Equal(t, test.isHex, gotIsHex) + + gotIsHexAddress := IsHexAddress(test.address) + require.Equal(t, test.isHexAddress, gotIsHexAddress) + }) + } +} diff --git a/internal/enr/enr.go b/internal/enr/enr.go new file mode 100644 index 0000000000..fcb0f7f70a --- /dev/null +++ b/internal/enr/enr.go @@ -0,0 +1,13 @@ +package enr + +import ( + "github.com/ethereum/go-ethereum/p2p/enode" +) + +func MustDecode(enrStr string) *enode.Node { + node, err := enode.Parse(enode.ValidSchemes, enrStr) + if err != nil || node == nil { + panic("could not decode enr: " + enrStr) + } + return node +} diff --git a/internal/multiaddr/multiaddr.go b/internal/multiaddr/multiaddr.go new file mode 100644 index 0000000000..1d6135da63 --- /dev/null +++ b/internal/multiaddr/multiaddr.go @@ -0,0 +1,11 @@ +package multiaddr + +import "github.com/multiformats/go-multiaddr" + +func MustDecode(multiaddrsStr string) *multiaddr.Multiaddr { + maddr, err := multiaddr.NewMultiaddr(multiaddrsStr) + if err != nil || maddr == nil { + panic("could not decode multiaddr: " + multiaddrsStr) + } + return &maddr +} diff --git a/internal/timesource/timesource.go b/internal/timesource/timesource.go new file mode 100644 index 0000000000..5ea83fd029 --- /dev/null +++ b/internal/timesource/timesource.go @@ -0,0 +1,7 @@ +package timesource + +import "time" + +type TimeSource interface { + Now() time.Time +} diff --git a/messaging/adapters/encryption_subscriptions.go b/messaging/adapters/encryption_subscriptions.go new file mode 100644 index 0000000000..08496f9762 --- /dev/null +++ b/messaging/adapters/encryption_subscriptions.go @@ -0,0 +1,19 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/layers/encryption" + "github.com/status-im/status-go/messaging/types" + "github.com/status-im/status-go/messaging/utils" +) + +func FromEncryptionSubscriptions(s *encryption.Subscriptions) *types.EncryptionSubscriptions { + if s == nil { + return nil + } + return &types.EncryptionSubscriptions{ + SharedSecrets: FromEncryptionSharedSecrets(s.SharedSecrets), + SendContactCode: s.SendContactCode, + NewHashRatchetKeys: utils.BridgeChannelsSlice(s.NewHashRatchetKeys, FromEncryptionHashRatchet), + Quit: s.Quit, + } +} diff --git a/messaging/adapters/hash_ratchet.go b/messaging/adapters/hash_ratchet.go new file mode 100644 index 0000000000..d6eb902df3 --- /dev/null +++ b/messaging/adapters/hash_ratchet.go @@ -0,0 +1,27 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/layers/encryption" + "github.com/status-im/status-go/messaging/types" +) + +func FromEncryptionHashRatchet(s *encryption.HashRatchetInfo) *types.HashRatchetInfo { + if s == nil { + return nil + } + return &types.HashRatchetInfo{ + GroupID: s.GroupID, + KeyID: s.KeyID, + } +} + +func FromEncryptionHashRatchets(s []*encryption.HashRatchetInfo) []*types.HashRatchetInfo { + if s == nil { + return nil + } + ratchets := make([]*types.HashRatchetInfo, 0, len(s)) + for _, item := range s { + ratchets = append(ratchets, FromEncryptionHashRatchet(item)) + } + return ratchets +} diff --git a/messaging/adapters/installation.go b/messaging/adapters/installation.go new file mode 100644 index 0000000000..578f285e4f --- /dev/null +++ b/messaging/adapters/installation.go @@ -0,0 +1,84 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/layers/encryption/multidevice" + "github.com/status-im/status-go/messaging/types" +) + +func FromEncryptionInstallation(installation *multidevice.Installation) *types.Installation { + if installation == nil { + return nil + } + + return &types.Installation{ + Identity: installation.Identity, + ID: installation.ID, + Version: installation.Version, + Enabled: installation.Enabled, + Timestamp: installation.Timestamp, + InstallationMetadata: FromEncryptionInstallationMetadata(installation.InstallationMetadata), + } +} + +func FromEncryptionInstallationMetadata(metadata *multidevice.InstallationMetadata) *types.InstallationMetadata { + if metadata == nil { + return nil + } + + return &types.InstallationMetadata{ + Name: metadata.Name, + DeviceType: metadata.DeviceType, + } +} + +func FromEncryptionInstallations(installations []*multidevice.Installation) []*types.Installation { + if installations == nil { + return nil + } + + result := make([]*types.Installation, 0, len(installations)) + for _, installation := range installations { + result = append(result, FromEncryptionInstallation(installation)) + } + + return result +} + +func ToEncryptionInstallation(installation *types.Installation) *multidevice.Installation { + if installation == nil { + return nil + } + + return &multidevice.Installation{ + Identity: installation.Identity, + ID: installation.ID, + Version: installation.Version, + Enabled: installation.Enabled, + Timestamp: installation.Timestamp, + InstallationMetadata: ToEncryptionInstallationMetadata(installation.InstallationMetadata), + } +} + +func ToEncryptionInstallations(installations []*types.Installation) []*multidevice.Installation { + if installations == nil { + return nil + } + + result := make([]*multidevice.Installation, 0, len(installations)) + for _, installation := range installations { + result = append(result, ToEncryptionInstallation(installation)) + } + + return result +} + +func ToEncryptionInstallationMetadata(metadata *types.InstallationMetadata) *multidevice.InstallationMetadata { + if metadata == nil { + return nil + } + + return &multidevice.InstallationMetadata{ + Name: metadata.Name, + DeviceType: metadata.DeviceType, + } +} diff --git a/messaging/adapters/peers.go b/messaging/adapters/peers.go new file mode 100644 index 0000000000..77fdfba266 --- /dev/null +++ b/messaging/adapters/peers.go @@ -0,0 +1,17 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/types" + wakutypes "github.com/status-im/status-go/messaging/waku/types" +) + +func FromWakuPeerStats(wakuPeers wakutypes.PeerStats) types.PeerStats { + peerStats := make(types.PeerStats) + for id, peer := range wakuPeers { + peerStats[id] = types.Peer{ + Protocols: peer.Protocols, + Addresses: peer.Addresses, + } + } + return peerStats +} diff --git a/messaging/adapters/received_messages.go b/messaging/adapters/received_messages.go new file mode 100644 index 0000000000..d62ac9f909 --- /dev/null +++ b/messaging/adapters/received_messages.go @@ -0,0 +1,14 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/types" + "github.com/status-im/status-go/messaging/wakumetrics" +) + +func ToWakumetricsReceivedMessages(receivedMessages types.ReceivedMessages) wakumetrics.ReceivedMessages { + return wakumetrics.ReceivedMessages{ + Filter: receivedMessages.Filter, + SHHMessage: receivedMessages.SHHMessage, + Messages: receivedMessages.Messages, + } +} diff --git a/messaging/adapters/shard.go b/messaging/adapters/shard.go new file mode 100644 index 0000000000..236d8d7dec --- /dev/null +++ b/messaging/adapters/shard.go @@ -0,0 +1,16 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/types" + wakuv2 "github.com/status-im/status-go/messaging/waku" +) + +func ToWakuShard(s *types.Shard) *wakuv2.Shard { + if s == nil { + return nil + } + return &wakuv2.Shard{ + Cluster: s.Cluster, + Index: s.Index, + } +} diff --git a/messaging/adapters/shared_secret.go b/messaging/adapters/shared_secret.go new file mode 100644 index 0000000000..9035911b22 --- /dev/null +++ b/messaging/adapters/shared_secret.go @@ -0,0 +1,27 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/layers/encryption/sharedsecret" + "github.com/status-im/status-go/messaging/types" +) + +func FromEncryptionSharedSecret(s *sharedsecret.Secret) *types.SharedSecret { + if s == nil { + return nil + } + return &types.SharedSecret{ + Identity: s.Identity, + Key: s.Key, + } +} + +func FromEncryptionSharedSecrets(s []*sharedsecret.Secret) []*types.SharedSecret { + if s == nil { + return nil + } + result := make([]*types.SharedSecret, 0, len(s)) + for _, secret := range s { + result = append(result, FromEncryptionSharedSecret(secret)) + } + return result +} diff --git a/messaging/adapters/transport_stats.go b/messaging/adapters/transport_stats.go new file mode 100644 index 0000000000..fbd429df3e --- /dev/null +++ b/messaging/adapters/transport_stats.go @@ -0,0 +1,13 @@ +package adapters + +import ( + "github.com/status-im/status-go/messaging/types" + wakutypes "github.com/status-im/status-go/messaging/waku/types" +) + +func FromWakuTransportStats(wakuStats wakutypes.StatsSummary) types.TransportStats { + return types.TransportStats{ + UploadRate: wakuStats.UploadRate, + DownloadRate: wakuStats.DownloadRate, + } +} diff --git a/messaging/common/message_segmentation.go b/messaging/common/message_segmentation.go new file mode 100644 index 0000000000..fa265c42c3 --- /dev/null +++ b/messaging/common/message_segmentation.go @@ -0,0 +1,285 @@ +package common + +import ( + "bytes" + "math" + "time" + + "github.com/golang/protobuf/proto" + "github.com/jinzhu/copier" + "github.com/klauspost/reedsolomon" + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/messaging/types" + wakutypes "github.com/status-im/status-go/messaging/waku/types" + "github.com/status-im/status-go/protocol/protobuf" +) + +var ErrMessageSegmentsIncomplete = errors.New("message segments incomplete") +var ErrMessageSegmentsAlreadyCompleted = errors.New("message segments already completed") +var ErrMessageSegmentsInvalidPayload = errors.New("invalid segment payload") +var ErrMessageSegmentsHashMismatch = errors.New("hash of entire payload does not match") +var ErrMessageSegmentsInvalidParity = errors.New("invalid parity segments") + +const ( + segmentsParityRate = 0.125 + segmentsReedsolomonMaxCount = 256 +) + +func (s *MessageSender) segmentMessage(newMessage *wakutypes.NewMessage) ([]*wakutypes.NewMessage, error) { + // We set the max message size to 3/4 of the allowed message size, to leave + // room for segment message metadata. + newMessages, err := segmentMessage(newMessage, int(s.transport.MaxMessageSize()/4*3)) + s.logger.Debug("message segmented", zap.Int("segments", len(newMessages))) + return newMessages, err +} + +func replicateMessageWithNewPayload(message *wakutypes.NewMessage, payload []byte) (*wakutypes.NewMessage, error) { + copy := &wakutypes.NewMessage{} + err := copier.Copy(copy, message) + if err != nil { + return nil, err + } + + copy.Payload = payload + return copy, nil +} + +// Segments message into smaller chunks if the size exceeds segmentSize. +func segmentMessage(newMessage *wakutypes.NewMessage, segmentSize int) ([]*wakutypes.NewMessage, error) { + if len(newMessage.Payload) <= segmentSize { + return []*wakutypes.NewMessage{newMessage}, nil + } + + entireMessageHash := crypto.Keccak256(newMessage.Payload) + entirePayloadSize := len(newMessage.Payload) + + segmentsCount := int(math.Ceil(float64(entirePayloadSize) / float64(segmentSize))) + paritySegmentsCount := int(math.Floor(float64(segmentsCount) * segmentsParityRate)) + + segmentPayloads := make([][]byte, segmentsCount+paritySegmentsCount) + segmentMessages := make([]*wakutypes.NewMessage, segmentsCount) + + for start, index := 0, 0; start < entirePayloadSize; start += segmentSize { + end := start + segmentSize + if end > entirePayloadSize { + end = entirePayloadSize + } + + segmentPayload := newMessage.Payload[start:end] + segmentWithMetadata := &protobuf.SegmentMessage{ + EntireMessageHash: entireMessageHash, + Index: uint32(index), + SegmentsCount: uint32(segmentsCount), + Payload: segmentPayload, + } + marshaledSegmentWithMetadata, err := proto.Marshal(segmentWithMetadata) + if err != nil { + return nil, err + } + segmentMessage, err := replicateMessageWithNewPayload(newMessage, marshaledSegmentWithMetadata) + if err != nil { + return nil, err + } + + segmentPayloads[index] = segmentPayload + segmentMessages[index] = segmentMessage + index++ + } + + // Skip reedsolomon if the combined total of data and parity segments exceeds the predefined limit of segmentsReedsolomonMaxCount. + // Exceeding this limit necessitates shard sizes to be multiples of 64, which are incompatible with clients that do not support forward error correction. + if paritySegmentsCount == 0 || segmentsCount+paritySegmentsCount > segmentsReedsolomonMaxCount { + return segmentMessages, nil + } + + enc, err := reedsolomon.New(segmentsCount, paritySegmentsCount) + if err != nil { + return nil, err + } + + // Align the size of the last segment payload. + lastSegmentPayload := segmentPayloads[segmentsCount-1] + segmentPayloads[segmentsCount-1] = make([]byte, segmentSize) + copy(segmentPayloads[segmentsCount-1], lastSegmentPayload) + + // Make space for parity data. + for i := segmentsCount; i < segmentsCount+paritySegmentsCount; i++ { + segmentPayloads[i] = make([]byte, segmentSize) + } + + err = enc.Encode(segmentPayloads) + if err != nil { + return nil, err + } + + // Create parity messages. + for i, index := segmentsCount, 0; i < segmentsCount+paritySegmentsCount; i++ { + segmentWithMetadata := &protobuf.SegmentMessage{ + EntireMessageHash: entireMessageHash, + SegmentsCount: 0, // indicates parity message + ParitySegmentIndex: uint32(index), + ParitySegmentsCount: uint32(paritySegmentsCount), + Payload: segmentPayloads[i], + } + marshaledSegmentWithMetadata, err := proto.Marshal(segmentWithMetadata) + if err != nil { + return nil, err + } + segmentMessage, err := replicateMessageWithNewPayload(newMessage, marshaledSegmentWithMetadata) + if err != nil { + return nil, err + } + + segmentMessages = append(segmentMessages, segmentMessage) + index++ + } + + return segmentMessages, nil +} + +// handleSegmentationLayer is capable of reconstructing the message from both complete and partial sets of data segments. +// It has capability to perform forward error correction. +func (s *MessageSender) handleSegmentationLayer(message *types.Message) error { + logger := s.logger.Named("handleSegmentationLayer").With(zap.String("hash", cryptotypes.HexBytes(message.TransportLayer.Hash).String())) + + segmentMessage := &types.SegmentMessage{ + SegmentMessage: &protobuf.SegmentMessage{}, + } + err := proto.Unmarshal(message.TransportLayer.Payload, segmentMessage.SegmentMessage) + if err != nil { + return errors.Wrap(err, "failed to unmarshal SegmentMessage") + } + + if !segmentMessage.IsValid() { + return ErrMessageSegmentsInvalidPayload + } + + logger.Debug("handling message segment", + zap.String("EntireMessageHash", cryptotypes.HexBytes(segmentMessage.EntireMessageHash).String()), + zap.Uint32("Index", segmentMessage.Index), + zap.Uint32("SegmentsCount", segmentMessage.SegmentsCount), + zap.Uint32("ParitySegmentIndex", segmentMessage.ParitySegmentIndex), + zap.Uint32("ParitySegmentsCount", segmentMessage.ParitySegmentsCount)) + + alreadyCompleted, err := s.persistence.IsMessageAlreadyCompleted(segmentMessage.EntireMessageHash) + if err != nil { + return err + } + if alreadyCompleted { + return ErrMessageSegmentsAlreadyCompleted + } + + err = s.persistence.SaveMessageSegment(segmentMessage, message.TransportLayer.SigPubKey, time.Now().Unix()) + if err != nil { + return err + } + + segments, err := s.persistence.GetMessageSegments(segmentMessage.EntireMessageHash, message.TransportLayer.SigPubKey) + if err != nil { + return err + } + + if len(segments) == 0 { + return errors.New("unexpected state: no segments found after save operation") // This should theoretically never occur. + } + + firstSegmentMessage := segments[0] + lastSegmentMessage := segments[len(segments)-1] + + // First segment message must not be a parity message. + if firstSegmentMessage.IsParityMessage() || len(segments) != int(firstSegmentMessage.SegmentsCount) { + return ErrMessageSegmentsIncomplete + } + + payloads := make([][]byte, firstSegmentMessage.SegmentsCount+lastSegmentMessage.ParitySegmentsCount) + payloadSize := len(firstSegmentMessage.Payload) + + restoreUsingParityData := lastSegmentMessage.IsParityMessage() + if !restoreUsingParityData { + for i, segment := range segments { + payloads[i] = segment.Payload + } + } else { + enc, err := reedsolomon.New(int(firstSegmentMessage.SegmentsCount), int(lastSegmentMessage.ParitySegmentsCount)) + if err != nil { + return err + } + + var lastNonParitySegmentPayload []byte + for _, segment := range segments { + if !segment.IsParityMessage() { + if segment.Index == firstSegmentMessage.SegmentsCount-1 { + // Ensure last segment is aligned to payload size, as it is required by reedsolomon. + payloads[segment.Index] = make([]byte, payloadSize) + copy(payloads[segment.Index], segment.Payload) + lastNonParitySegmentPayload = segment.Payload + } else { + payloads[segment.Index] = segment.Payload + } + } else { + payloads[firstSegmentMessage.SegmentsCount+segment.ParitySegmentIndex] = segment.Payload + } + } + + err = enc.Reconstruct(payloads) + if err != nil { + return err + } + + ok, err := enc.Verify(payloads) + if err != nil { + return err + } + if !ok { + return ErrMessageSegmentsInvalidParity + } + + if lastNonParitySegmentPayload != nil { + payloads[firstSegmentMessage.SegmentsCount-1] = lastNonParitySegmentPayload // Bring back last segment with original length. + } + } + + // Combine payload. + var entirePayload bytes.Buffer + for i := 0; i < int(firstSegmentMessage.SegmentsCount); i++ { + _, err := entirePayload.Write(payloads[i]) + if err != nil { + return errors.Wrap(err, "failed to write segment payload") + } + } + + // Sanity check. + entirePayloadHash := crypto.Keccak256(entirePayload.Bytes()) + if !bytes.Equal(entirePayloadHash, segmentMessage.EntireMessageHash) { + return ErrMessageSegmentsHashMismatch + } + + err = s.persistence.CompleteMessageSegments(segmentMessage.EntireMessageHash, message.TransportLayer.SigPubKey, time.Now().Unix()) + if err != nil { + return err + } + + message.TransportLayer.Payload = entirePayload.Bytes() + + return nil +} + +func (s *MessageSender) CleanupSegments() error { + monthAgo := time.Now().AddDate(0, -1, 0).Unix() + + err := s.persistence.RemoveMessageSegmentsOlderThan(monthAgo) + if err != nil { + return err + } + + err = s.persistence.RemoveMessageSegmentsCompletedOlderThan(monthAgo) + if err != nil { + return err + } + + return nil +} diff --git a/messaging/common/message_segmentation_test.go b/messaging/common/message_segmentation_test.go new file mode 100644 index 0000000000..094b23fe91 --- /dev/null +++ b/messaging/common/message_segmentation_test.go @@ -0,0 +1,203 @@ +package common + +import ( + _ "embed" + "math" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/messaging/types" + wakutypes "github.com/status-im/status-go/messaging/waku/types" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/sqlite" + "github.com/status-im/status-go/t/helpers" +) + +func TestMessageSegmentationSuite(t *testing.T) { + suite.Run(t, new(MessageSegmentationSuite)) +} + +type MessageSegmentationSuite struct { + suite.Suite + + sender *MessageSender + testPayload []byte + logger *zap.Logger +} + +func (s *MessageSegmentationSuite) SetupSuite() { + s.testPayload = make([]byte, 1000) + for i := 0; i < 1000; i++ { + s.testPayload[i] = byte(i) + } +} + +func (s *MessageSegmentationSuite) SetupTest() { + identity, err := crypto.GenerateKey() + s.Require().NoError(err) + + database, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(database) + s.Require().NoError(err) + + s.logger, err = zap.NewDevelopment() + s.Require().NoError(err) + + s.sender, err = NewMessageSender( + identity, + database, + NewStubPersistence(), + nil, + nil, + s.logger, + ) + s.Require().NoError(err) +} + +func (s *MessageSegmentationSuite) SetupSubTest() { + s.SetupTest() +} + +func (s *MessageSegmentationSuite) TestHandleSegmentationLayer() { + testCases := []struct { + name string + segmentsCount int + expectedParitySegmentsCount int + retrievedSegments []int + retrievedParitySegments []int + shouldSucceed bool + }{ + { + name: "all segments retrieved", + segmentsCount: 2, + expectedParitySegmentsCount: 0, + retrievedSegments: []int{0, 1}, + retrievedParitySegments: []int{}, + shouldSucceed: true, + }, + { + name: "all segments retrieved out of order", + segmentsCount: 2, + expectedParitySegmentsCount: 0, + retrievedSegments: []int{1, 0}, + retrievedParitySegments: []int{}, + shouldSucceed: true, + }, + { + name: "all segments&parity retrieved", + segmentsCount: 8, + expectedParitySegmentsCount: 1, + retrievedSegments: []int{0, 1, 2, 3, 4, 5, 6, 7, 8}, + retrievedParitySegments: []int{8}, + shouldSucceed: true, + }, + { + name: "all segments&parity retrieved out of order", + segmentsCount: 8, + expectedParitySegmentsCount: 1, + retrievedSegments: []int{8, 0, 7, 1, 6, 2, 5, 3, 4}, + retrievedParitySegments: []int{8}, + shouldSucceed: true, + }, + { + name: "no segments retrieved", + segmentsCount: 2, + expectedParitySegmentsCount: 0, + retrievedSegments: []int{}, + retrievedParitySegments: []int{}, + shouldSucceed: false, + }, + { + name: "not all needed segments&parity retrieved", + segmentsCount: 8, + expectedParitySegmentsCount: 1, + retrievedSegments: []int{1, 2, 8}, + retrievedParitySegments: []int{8}, + shouldSucceed: false, + }, + { + name: "segments&parity retrieved", + segmentsCount: 8, + expectedParitySegmentsCount: 1, + retrievedSegments: []int{1, 2, 3, 4, 5, 6, 7, 8}, + retrievedParitySegments: []int{8}, + shouldSucceed: true, // succeed even though one segment is missing, thank you reedsolomon + }, + { + name: "segments&parity retrieved out of order", + segmentsCount: 16, + expectedParitySegmentsCount: 2, + retrievedSegments: []int{17, 0, 16, 1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7}, + retrievedParitySegments: []int{16, 17}, + shouldSucceed: true, // succeed even though two segments are missing, thank you reedsolomon + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + segmentedMessages, err := segmentMessage(&wakutypes.NewMessage{Payload: s.testPayload}, int(math.Ceil(float64(len(s.testPayload))/float64(tc.segmentsCount)))) + s.Require().NoError(err) + s.Require().Len(segmentedMessages, tc.segmentsCount+tc.expectedParitySegmentsCount) + + message := &types.Message{TransportLayer: types.TransportLayer{ + SigPubKey: &s.sender.identity.PublicKey, + }} + + messageRecreated := false + handledSegments := []int{} + + for i, segmentIndex := range tc.retrievedSegments { + s.T().Log("i=", i, "segmentIndex=", segmentIndex) + + message.TransportLayer.Payload = segmentedMessages[segmentIndex].Payload + + err = s.sender.handleSegmentationLayer(message) + + handledSegments = append(handledSegments, segmentIndex) + + if len(handledSegments) < tc.segmentsCount { + s.Require().ErrorIs(err, ErrMessageSegmentsIncomplete) + } else if len(handledSegments) == tc.segmentsCount { + s.Require().NoError(err) + s.Require().ElementsMatch(s.testPayload, message.TransportLayer.Payload) + messageRecreated = true + } else { + s.Require().ErrorIs(err, ErrMessageSegmentsAlreadyCompleted) + } + } + + s.Require().Equal(tc.shouldSucceed, messageRecreated) + }) + } +} + +//go:embed testdata/segmentationProtobufMissDecoding.bin +var protobufMissDecodingPayload []byte // Represents a payload that is intentionally not encoded as protobuf.SegmentMessage to test unmarshalling behavior. + +func (s *MessageSegmentationSuite) TestProtobufMissDecoding() { + // This test demonstrates how protobuf unmarshalling behaves when given a payload + // that is not encoded as a protobuf.SegmentMessage. Protobuf attempts to decode + // any byte sequence, and if the structure coincidentally matches valid encoding + // patterns (e.g., varint or byte fields), it produces seemingly valid but incorrect results. + + segmentedMessage := types.SegmentMessage{ + SegmentMessage: &protobuf.SegmentMessage{}, + } + + // Attempt to unmarshal the invalid payload into a protobuf.SegmentMessage. + err := proto.Unmarshal(protobufMissDecodingPayload, segmentedMessage.SegmentMessage) + s.Require().NoError(err) // Surprisingly, no error is returned. + + // Validate the unmarshalled data. The SegmentsCount field contains a value, + // but it is incorrect because the payload was not properly encoded. + s.Require().Equal(segmentedMessage.SegmentsCount, uint32(25)) // Incorrect but "valid" value. + + // Ensure that the sanity check for the segmented message fails, as expected. + s.Require().False(segmentedMessage.IsValid()) +} diff --git a/messaging/common/message_sender.go b/messaging/common/message_sender.go new file mode 100644 index 0000000000..8a735f7e60 --- /dev/null +++ b/messaging/common/message_sender.go @@ -0,0 +1,1388 @@ +package common + +import ( + "context" + "crypto/ecdsa" + "database/sql" + "math/rand" + "sync" + "time" + + "github.com/golang/protobuf/proto" + "github.com/pkg/errors" + datasyncnode "github.com/status-im/mvds/node" + datasyncproto "github.com/status-im/mvds/protobuf" + "github.com/status-im/mvds/state" + "go.uber.org/zap" + + "github.com/ethereum/go-ethereum/common/hexutil" + utils "github.com/status-im/status-go/common" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/messaging/adapters" + "github.com/status-im/status-go/messaging/datasync" + datasyncpeer "github.com/status-im/status-go/messaging/datasync/peer" + messagingevents "github.com/status-im/status-go/messaging/events" + "github.com/status-im/status-go/messaging/layers/encryption" + "github.com/status-im/status-go/messaging/layers/encryption/sharedsecret" + "github.com/status-im/status-go/messaging/layers/transport" + messagingtypes "github.com/status-im/status-go/messaging/types" + wakutypes "github.com/status-im/status-go/messaging/waku/types" + "github.com/status-im/status-go/pkg/pubsub" + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/protobuf" + v1protocol "github.com/status-im/status-go/protocol/v1" +) + +// Whisper message properties. +const ( + // largeSizeInBytes is when should we be using a lower POW. + // Roughly this is 50KB + largeSizeInBytes = 50000 + maxMessageSenderEphemeralKeys = 3 +) + +// RekeyCompatibility indicates whether we should be sending +// keys in 1-to-1 messages as well as in the newer format +var RekeyCompatibility = true + +type MessageSender struct { + identity *ecdsa.PrivateKey + datasync *datasync.DataSync + database *sql.DB + transport *transport.Transport + protocol *encryption.Protocol + logger *zap.Logger + persistence messagingtypes.Persistence + publisher *pubsub.Publisher + + datasyncEnabled bool + + // ephemeralKeys is a map that contains the ephemeral keys of the client, used + // to decrypt messages + ephemeralKeys map[string]*ecdsa.PrivateKey + ephemeralKeysMutex sync.Mutex + + // handleSharedSecrets is a callback that is called every time a new shared secret is negotiated + handleSharedSecrets func([]*sharedsecret.Secret) error +} + +func NewMessageSender( + identity *ecdsa.PrivateKey, + database *sql.DB, // FIXME + persistence messagingtypes.Persistence, + transport *transport.Transport, + enc *encryption.Protocol, + logger *zap.Logger, +) (*MessageSender, error) { + p := &MessageSender{ + identity: identity, + database: database, + datasyncEnabled: true, // FIXME + protocol: enc, + persistence: persistence, + publisher: pubsub.NewPublisher(), + transport: transport, + logger: logger, + ephemeralKeys: make(map[string]*ecdsa.PrivateKey), + } + + return p, nil +} + +func (s *MessageSender) Stop() { + s.publisher.Close() + s.StopDatasync() +} + +func (s *MessageSender) SetHandleSharedSecrets(handler func([]*sharedsecret.Secret) error) { + s.handleSharedSecrets = handler +} + +func (s *MessageSender) StartDatasync(statusChangeEvent chan datasyncnode.PeerStatusChangeEvent, handler func(peer state.PeerID, payload *datasyncproto.Payload) error) error { + if !s.datasyncEnabled { + return nil + } + + dataSyncTransport := datasync.NewNodeTransport() + dataSyncNode, err := datasyncnode.NewPersistentNode( + s.database, + dataSyncTransport, + datasyncpeer.PublicKeyToPeerID(s.identity.PublicKey), + datasyncnode.BATCH, + datasync.CalculateSendTime, + statusChangeEvent, + s.logger, + ) + if err != nil { + return err + } + + s.datasync = datasync.New(dataSyncNode, dataSyncTransport, true, s.logger) + + s.datasync.Init(handler, s.logger) + s.datasync.Start(datasync.DatasyncTicker) + + return nil +} + +// SendPrivate takes encoded data, encrypts it and sends through the wire. +func (s *MessageSender) SendPrivate( + ctx context.Context, + recipient *ecdsa.PublicKey, + rawMessage *messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug( + "sending a private message", + zap.String("public-key", types.EncodeHex(crypto.FromECDSAPub(recipient))), + zap.String("site", "SendPrivate"), + ) + // Currently we don't support sending through datasync and setting custom waku fields, + // as the datasync interface is not rich enough to propagate that information, so we + // would have to add some complexity to handle this. + if rawMessage.ResendType == messagingtypes.ResendTypeDataSync && (rawMessage.Sender != nil || rawMessage.SkipEncryptionLayer || rawMessage.SendOnPersonalTopic) { + return nil, errors.New("setting identity, skip-encryption or personal topic and datasync not supported") + } + + // Set sender identity if not specified + if rawMessage.Sender == nil { + rawMessage.Sender = s.identity + } + + return s.sendPrivate(ctx, recipient, rawMessage) +} + +// SendCommunityMessage takes encoded data, encrypts it and sends through the wire +// using the community topic and their key +func (s *MessageSender) SendCommunityMessage( + ctx context.Context, + rawMessage *messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug( + "sending a community message", + zap.String("communityId", types.EncodeHex(rawMessage.CommunityID)), + zap.String("site", "SendCommunityMessage"), + ) + rawMessage.Sender = s.identity + + return s.sendCommunity(ctx, rawMessage) +} + +// SendPubsubTopicKey sends the protected topic key for a community to a list of recipients +func (s *MessageSender) SendPubsubTopicKey( + ctx context.Context, + rawMessage *messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug( + "sending the protected topic key for a community", + zap.String("communityId", types.EncodeHex(rawMessage.CommunityID)), + zap.String("site", "SendPubsubTopicKey"), + ) + rawMessage.Sender = s.identity + messageID, err := s.getMessageID(rawMessage) + if err != nil { + return nil, err + } + + if err = s.setMessageID(messageID, rawMessage); err != nil { + return nil, err + } + + // Notify before dispatching, otherwise the dispatch subscription might happen + // earlier than the scheduled + s.notifyOnScheduledMessage(nil, rawMessage) + + // Send to each recipients + for _, recipient := range rawMessage.Recipients { + _, err = s.sendPrivate(ctx, recipient, rawMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to send message") + } + } + return messageID, nil + +} + +// SendGroup takes encoded data, encrypts it and sends through the wire, +// always return the messageID +func (s *MessageSender) SendGroup( + ctx context.Context, + recipients []*ecdsa.PublicKey, + rawMessage messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug( + "sending a private group message", + zap.String("site", "SendGroup"), + ) + // Set sender if not specified + if rawMessage.Sender == nil { + rawMessage.Sender = s.identity + } + + // Calculate messageID first and set on raw message + messageID, err := s.getMessageID(&rawMessage) + if err != nil { + return nil, err + } + + if err = s.setMessageID(messageID, &rawMessage); err != nil { + return nil, err + } + + // We call it only once, and we nil the function after so it doesn't get called again + if rawMessage.BeforeDispatch != nil { + if err := rawMessage.BeforeDispatch(&rawMessage); err != nil { + return nil, err + } + } + + // Send to each recipients + for _, recipient := range recipients { + _, err = s.sendPrivate(ctx, recipient, &rawMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to send message") + } + } + return messageID, nil +} + +func (s *MessageSender) getMessageID(rawMessage *messagingtypes.RawMessage) (types.HexBytes, error) { + wrappedMessage, err := s.wrapMessageV1(rawMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to wrap message") + } + + messageID := v1protocol.MessageID(&rawMessage.Sender.PublicKey, wrappedMessage) + return messageID, nil +} + +func (s *MessageSender) ValidateRawMessage(rawMessage *messagingtypes.RawMessage) error { + id, err := s.getMessageID(rawMessage) + if err != nil { + return err + } + messageID := types.EncodeHex(id) + + return s.validateMessageID(messageID, rawMessage) + +} + +func (s *MessageSender) validateMessageID(messageID string, rawMessage *messagingtypes.RawMessage) error { + if len(rawMessage.ID) > 0 && rawMessage.ID != messageID { + s.logger.Error("failed to validate message ID, RawMessage content was modified", + zap.String("prevID", rawMessage.ID), + zap.String("newID", messageID), + zap.Any("contentType", rawMessage.MessageType)) + return messagingtypes.ErrModifiedRawMessage + } + return nil +} + +func (s *MessageSender) setMessageID(messageID types.HexBytes, rawMessage *messagingtypes.RawMessage) error { + msgID := types.EncodeHex(messageID) + + if err := s.validateMessageID(msgID, rawMessage); err != nil { + return err + } + + rawMessage.ID = msgID + return nil +} + +func ShouldCommunityMessageBeEncrypted(msgType protobuf.ApplicationMetadataMessage_Type) bool { + return msgType == protobuf.ApplicationMetadataMessage_CHAT_MESSAGE || + msgType == protobuf.ApplicationMetadataMessage_EDIT_MESSAGE || + msgType == protobuf.ApplicationMetadataMessage_DELETE_MESSAGE || + msgType == protobuf.ApplicationMetadataMessage_PIN_MESSAGE || + msgType == protobuf.ApplicationMetadataMessage_EMOJI_REACTION +} + +// sendCommunity sends a message that's to be sent in a community +// If it's a chat message, it will go to the respective topic derived by the +// chat id, if it's not a chat message, it will go to the community topic. +func (s *MessageSender) sendCommunity( + ctx context.Context, + rawMessage *messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug("sending community message", zap.String("recipient", types.EncodeHex(crypto.FromECDSAPub(&rawMessage.Sender.PublicKey)))) + + // Set sender + if rawMessage.Sender == nil { + rawMessage.Sender = s.identity + } + + messageID, err := s.getMessageID(rawMessage) + if err != nil { + return nil, err + } + + if err = s.setMessageID(messageID, rawMessage); err != nil { + return nil, err + } + + if rawMessage.BeforeDispatch != nil { + if err := rawMessage.BeforeDispatch(rawMessage); err != nil { + return nil, err + } + } + // Notify before dispatching, otherwise the dispatch subscription might happen + // earlier than the scheduled + s.notifyOnScheduledMessage(nil, rawMessage) + + var hashes [][]byte + var newMessages []*wakutypes.NewMessage + + forceRekey := rawMessage.CommunityKeyExMsgType == messagingtypes.KeyExMsgRekey + + // Check if it's a key exchange message. In this case we send it + // to all the recipients + if rawMessage.CommunityKeyExMsgType != messagingtypes.KeyExMsgNone { + // If rekeycompatibility is on, we always + // want to execute below, otherwise we execute + // only when we want to fill up old keys to a given user + if RekeyCompatibility || !forceRekey { + keyExMessageSpecs, err := s.protocol.GetKeyExMessageSpecs(rawMessage.HashRatchetGroupID, s.identity, rawMessage.Recipients, forceRekey) + if err != nil { + return nil, err + } + + for i, spec := range keyExMessageSpecs { + recipient := rawMessage.Recipients[i] + _, _, err = s.sendMessageSpec(ctx, recipient, spec, [][]byte{messageID}) + if err != nil { + return nil, err + } + } + } + } + + wrappedMessage, err := s.wrapMessageV1(rawMessage) + if err != nil { + return nil, err + } + + // If it's a chat message, we send it on the community chat topic + if ShouldCommunityMessageBeEncrypted(rawMessage.MessageType) { + messageSpec, err := s.protocol.BuildHashRatchetMessage(rawMessage.HashRatchetGroupID, wrappedMessage) + if err != nil { + return nil, err + } + + payload, err := proto.Marshal(messageSpec.Message) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal") + } + hashes, newMessages, err = s.dispatchCommunityChatMessage(ctx, rawMessage, payload, forceRekey) + if err != nil { + return nil, err + } + + sentMessage := &messagingevents.SentMessage{ + Spec: messageSpec, + MessageIDs: [][]byte{messageID}, + } + + s.notifyOnSentMessage(sentMessage) + + } else { + + pubkey, err := crypto.DecompressPubkey(rawMessage.CommunityID) + if err != nil { + return nil, errors.Wrap(err, "failed to decompress pubkey") + } + hashes, newMessages, err = s.dispatchCommunityMessage(ctx, pubkey, wrappedMessage, rawMessage.PubsubTopic, forceRekey, rawMessage) + if err != nil { + s.logger.Error("failed to send a community message", zap.Error(err)) + return nil, errors.Wrap(err, "failed to send a message spec") + } + } + + s.logger.Debug("sent-message: community ", + zap.Strings("recipient", common.PubkeysToHex(rawMessage.Recipients)), + zap.String("messageID", messageID.String()), + zap.String("messageType", "community"), + zap.Any("contentType", rawMessage.MessageType), + zap.Strings("hashes", types.EncodeHexes(hashes))) + s.transport.Track(messageID, hashes, newMessages) + s.notifyOnSentRawMessage(rawMessage) + + return messageID, nil +} + +// sendPrivate sends data to the recipient identifying with a given public key. +func (s *MessageSender) sendPrivate( + ctx context.Context, + recipient *ecdsa.PublicKey, + rawMessage *messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug("sending private message", zap.String("recipient", types.EncodeHex(crypto.FromECDSAPub(recipient)))) + + var wrappedMessage []byte + var err error + if rawMessage.SkipApplicationWrap { + wrappedMessage = rawMessage.Payload + } else { + wrappedMessage, err = s.wrapMessageV1(rawMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to wrap message") + } + } + + messageID := v1protocol.MessageID(&rawMessage.Sender.PublicKey, wrappedMessage) + + if err = s.setMessageID(messageID, rawMessage); err != nil { + return nil, err + } + + if rawMessage.BeforeDispatch != nil { + if err := rawMessage.BeforeDispatch(rawMessage); err != nil { + return nil, err + } + } + + // Notify before dispatching, otherwise the dispatch subscription might happen + // earlier than the scheduled + s.notifyOnScheduledMessage(recipient, rawMessage) + + if s.datasync != nil && s.datasyncEnabled && rawMessage.ResendType == messagingtypes.ResendTypeDataSync { + // No need to call transport tracking. + // It is done in a data sync dispatch step. + datasyncID, err := s.addToDataSync(recipient, wrappedMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to send message with datasync") + } + // We don't need to receive confirmations from our own devices + if !common.IsPubKeyEqual(recipient, &s.identity.PublicKey) { + confirmation := &messagingtypes.RawMessageConfirmation{ + DataSyncID: datasyncID, + MessageID: messageID, + PublicKey: crypto.CompressPubkey(recipient), + } + + err = s.persistence.InsertPendingConfirmation(confirmation) + if err != nil { + return nil, err + } + } + } else if rawMessage.SkipEncryptionLayer { + + messageBytes := wrappedMessage + if rawMessage.CommunityKeyExMsgType == messagingtypes.KeyExMsgReuse { + groupID := rawMessage.HashRatchetGroupID + + ratchets, err := s.protocol.GetKeysForGroup(groupID) + if err != nil { + return nil, err + } + + message, err := s.protocol.BuildHashRatchetKeyExchangeMessageWithPayload(s.identity, recipient, groupID, ratchets, wrappedMessage) + if err != nil { + return nil, err + } + + messageBytes, err = proto.Marshal(message.Message) + if err != nil { + return nil, err + } + } + + // When SkipProtocolLayer is set we don't pass the message to the encryption layer + hashes, newMessages, err := s.sendPrivateRawMessage(ctx, rawMessage, recipient, messageBytes) + if err != nil { + s.logger.Error("failed to send a private message", zap.Error(err)) + return nil, errors.Wrap(err, "failed to send a message spec") + } + + s.logger.Debug("sent-message: private skipProtocolLayer", + zap.String("recipient", common.PubkeyToHex(recipient)), + zap.String("messageID", messageID.String()), + zap.String("messageType", "private"), + zap.Any("contentType", rawMessage.MessageType), + zap.Strings("hashes", types.EncodeHexes(hashes))) + s.transport.Track(messageID, hashes, newMessages) + + } else { + messageSpec, err := s.protocol.BuildEncryptedMessage(rawMessage.Sender, recipient, wrappedMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to encrypt message") + } + + hashes, newMessages, err := s.sendMessageSpec(ctx, recipient, messageSpec, [][]byte{messageID}) + if err != nil { + s.logger.Error("failed to send a private message", zap.Error(err)) + return nil, errors.Wrap(err, "failed to send a message spec") + } + + s.logger.Debug("sent-message: private without datasync", + zap.String("recipient", common.PubkeyToHex(recipient)), + zap.String("messageID", messageID.String()), + zap.Any("contentType", rawMessage.MessageType), + zap.String("messageType", "private"), + zap.Strings("hashes", types.EncodeHexes(hashes))) + s.transport.Track(messageID, hashes, newMessages) + } + + s.notifyOnSentRawMessage(rawMessage) + + return messageID, nil +} + +// sendPairInstallation sends data to the recipients, using DH +func (s *MessageSender) SendPairInstallation( + ctx context.Context, + recipient *ecdsa.PublicKey, + rawMessage messagingtypes.RawMessage, +) ([]byte, error) { + s.logger.Debug("sending private message", zap.String("recipient", types.EncodeHex(crypto.FromECDSAPub(recipient)))) + + wrappedMessage, err := s.wrapMessageV1(&rawMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to wrap message") + } + + messageSpec, err := s.protocol.BuildDHMessage(s.identity, recipient, wrappedMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to encrypt message") + } + + messageID := v1protocol.MessageID(&s.identity.PublicKey, wrappedMessage) + + hashes, newMessages, err := s.sendMessageSpec(ctx, recipient, messageSpec, [][]byte{messageID}) + if err != nil { + return nil, errors.Wrap(err, "failed to send a message spec") + } + + s.transport.Track(messageID, hashes, newMessages) + s.notifyOnSentRawMessage(&rawMessage) + + return messageID, nil +} + +func (s *MessageSender) encodeMembershipUpdate( + message v1protocol.MembershipUpdateMessage, + chatEntity messagingtypes.ChatEntity, +) ([]byte, error) { + + if chatEntity != nil { + chatEntityProtobuf := chatEntity.GetProtobuf() + switch chatEntityProtobuf := chatEntityProtobuf.(type) { + case *protobuf.ChatMessage: + message.Message = chatEntityProtobuf + case *protobuf.EmojiReaction: + message.EmojiReaction = chatEntityProtobuf + + } + } + + encodedMessage, err := v1protocol.EncodeMembershipUpdateMessage(message) + if err != nil { + return nil, errors.Wrap(err, "failed to encode membership update message") + } + + return encodedMessage, nil +} + +// EncodeMembershipUpdate takes a group and an optional chat message and returns the protobuf representation to be sent on the wire. +// All the events in a group are encoded and added to the payload +func (s *MessageSender) EncodeMembershipUpdate( + group *v1protocol.Group, + chatEntity messagingtypes.ChatEntity, +) ([]byte, error) { + message := v1protocol.MembershipUpdateMessage{ + ChatID: group.ChatID(), + Events: group.Events(), + } + + return s.encodeMembershipUpdate(message, chatEntity) +} + +// EncodeAbridgedMembershipUpdate takes a group and an optional chat message and returns the protobuf representation to be sent on the wire. +// Only the events relevant to the current group are encoded +func (s *MessageSender) EncodeAbridgedMembershipUpdate( + group *v1protocol.Group, + chatEntity messagingtypes.ChatEntity, +) ([]byte, error) { + message := v1protocol.MembershipUpdateMessage{ + ChatID: group.ChatID(), + Events: group.AbridgedEvents(), + } + return s.encodeMembershipUpdate(message, chatEntity) +} + +func (s *MessageSender) dispatchCommunityChatMessage(ctx context.Context, rawMessage *messagingtypes.RawMessage, wrappedMessage []byte, rekey bool) ([][]byte, []*wakutypes.NewMessage, error) { + payload := wrappedMessage + var err error + if rekey && len(rawMessage.HashRatchetGroupID) != 0 { + + var ratchet *encryption.HashRatchetKeyCompatibility + // We have just rekeyed, pull the latest + if RekeyCompatibility { + ratchet, err = s.protocol.GetCurrentKeyForGroup(rawMessage.HashRatchetGroupID) + if err != nil { + return nil, nil, err + } + + } + // We send the message over the community topic + spec, err := s.protocol.BuildHashRatchetReKeyGroupMessage(s.identity, rawMessage.Recipients, rawMessage.HashRatchetGroupID, wrappedMessage, ratchet) + if err != nil { + return nil, nil, err + } + payload, err = proto.Marshal(spec.Message) + if err != nil { + return nil, nil, err + } + } + + newMessage := &wakutypes.NewMessage{ + Payload: payload, + PubsubTopic: rawMessage.PubsubTopic, + } + + if rawMessage.BeforeDispatch != nil { + if err := rawMessage.BeforeDispatch(rawMessage); err != nil { + return nil, nil, err + } + } + + // notify before dispatching + s.notifyOnScheduledMessage(nil, rawMessage) + + newMessages, err := s.segmentMessage(newMessage) + if err != nil { + return nil, nil, err + } + + hashes := make([][]byte, 0, len(newMessages)) + for _, newMessage := range newMessages { + hash, err := s.transport.SendPublic(ctx, newMessage, rawMessage.ContentTopic) + if err != nil { + return nil, nil, err + } + hashes = append(hashes, hash) + } + + return hashes, newMessages, nil +} + +// SendPublic takes encoded data, encrypts it and sends through the wire. +func (s *MessageSender) SendPublic( + ctx context.Context, + chatName string, + rawMessage messagingtypes.RawMessage, +) ([]byte, error) { + // Set sender + if rawMessage.Sender == nil { + rawMessage.Sender = s.identity + } + + var wrappedMessage []byte + var err error + if rawMessage.SkipApplicationWrap { + wrappedMessage = rawMessage.Payload + } else { + wrappedMessage, err = s.wrapMessageV1(&rawMessage) + if err != nil { + return nil, errors.Wrap(err, "failed to wrap message") + } + } + + var newMessage *wakutypes.NewMessage + + messageSpec, err := s.protocol.BuildPublicMessage(s.identity, wrappedMessage) + if err != nil { + s.logger.Error("failed to send a public message", zap.Error(err)) + return nil, errors.Wrap(err, "failed to wrap a public message in the encryption layer") + } + + if len(rawMessage.HashRatchetGroupID) != 0 { + + var ratchet *encryption.HashRatchetKeyCompatibility + var err error + // We have just rekeyed, pull the latest + ratchet, err = s.protocol.GetCurrentKeyForGroup(rawMessage.HashRatchetGroupID) + if err != nil { + return nil, err + } + + keyID, err := ratchet.GetKeyID() + if err != nil { + return nil, err + } + s.logger.Debug("adding key id to message", zap.String("keyid", types.Bytes2Hex(keyID))) + // We send the message over the community topic + spec, err := s.protocol.BuildHashRatchetReKeyGroupMessage(s.identity, rawMessage.Recipients, rawMessage.HashRatchetGroupID, wrappedMessage, ratchet) + if err != nil { + return nil, err + } + newMessage, err = MessageSpecToWhisper(spec) + if err != nil { + return nil, err + } + + } else if !rawMessage.SkipEncryptionLayer { + newMessage, err = MessageSpecToWhisper(messageSpec) + if err != nil { + return nil, err + } + } else { + newMessage = &wakutypes.NewMessage{ + Payload: wrappedMessage, + } + } + + newMessage.Ephemeral = rawMessage.Ephemeral + newMessage.PubsubTopic = rawMessage.PubsubTopic + newMessage.Priority = rawMessage.Priority + + messageID := v1protocol.MessageID(&rawMessage.Sender.PublicKey, wrappedMessage) + + if err = s.setMessageID(messageID, &rawMessage); err != nil { + return nil, err + } + + if rawMessage.BeforeDispatch != nil { + if err := rawMessage.BeforeDispatch(&rawMessage); err != nil { + return nil, err + } + } + + // notify before dispatching + s.notifyOnScheduledMessage(nil, &rawMessage) + + newMessages, err := s.segmentMessage(newMessage) + if err != nil { + return nil, err + } + + hashes := make([][]byte, 0, len(newMessages)) + for _, newMessage := range newMessages { + hash, err := s.transport.SendPublic(ctx, newMessage, chatName) + if err != nil { + return nil, err + } + hashes = append(hashes, hash) + } + + sentMessage := &messagingevents.SentMessage{ + Spec: messageSpec, + MessageIDs: [][]byte{messageID}, + } + + s.notifyOnSentMessage(sentMessage) + + s.logger.Debug("sent-message: public message", + zap.Strings("recipient", common.PubkeysToHex(rawMessage.Recipients)), + zap.String("messageID", messageID.String()), + zap.Any("contentType", rawMessage.MessageType), + zap.String("messageType", "public"), + zap.Strings("hashes", types.EncodeHexes(hashes))) + s.transport.Track(messageID, hashes, newMessages) + s.notifyOnSentRawMessage(&rawMessage) + + return messageID, nil +} + +// unwrapDatasyncMessage tries to unwrap message as datasync one and in case of success +// returns cloned messages with replaced payloads +func (s *MessageSender) unwrapDatasyncMessage(m *messagingtypes.Message, response *handleMessageResponse) error { + + datasyncMessage, err := s.datasync.Unwrap( + m.SigPubKey(), + m.EncryptionLayer.Payload, + ) + if err != nil { + return err + } + + response.DatasyncSender = m.SigPubKey() + response.DatasyncAcks = append(response.DatasyncAcks, datasyncMessage.Acks...) + response.DatasyncRequests = append(response.DatasyncRequests, datasyncMessage.Requests...) + for _, o := range datasyncMessage.GroupOffers { + for _, mID := range o.MessageIds { + response.DatasyncOffers = append(response.DatasyncOffers, messagingtypes.DatasyncOffer{GroupID: o.GroupId, MessageID: mID}) + } + } + + for _, ds := range datasyncMessage.Messages { + message, err := m.Clone() + if err != nil { + return err + } + message.EncryptionLayer.Payload = ds.Body + response.DatasyncMessages = append(response.DatasyncMessages, message) + + } + return nil +} + +// HandleMessages expects a whisper message as input, and it will go through +// a series of transformations until the message is parsed into an application +// layer message, or in case of Raw methods, the processing stops at the layer +// before. +// It returns an error only if the processing of required steps failed. +func (s *MessageSender) HandleMessages(msg *messagingtypes.ReceivedMessage) (*messagingtypes.HandleMessageResponse, error) { + logger := s.logger.With(zap.String("site", "HandleMessages")) + hlogger := logger.With(zap.String("hash", types.HexBytes(msg.Hash).String())) + + response, err := s.handleMessage(msg) + if err != nil { + // Hash ratchet with a group id not found yet, save the message for future processing + if err == encryption.ErrHashRatchetGroupIDNotFound && len(response.Message.EncryptionLayer.HashRatchetInfo) == 1 { + info := response.Message.EncryptionLayer.HashRatchetInfo[0] + return nil, s.persistence.SaveHashRatchetMessage(info.GroupID, info.KeyID, msg) + } + + // The current message segment has been successfully retrieved. + // However, the collection of segments is not yet complete. + if err == ErrMessageSegmentsIncomplete { + return nil, nil + } + + return nil, err + } + + // Process queued hash ratchet messages + for _, hashRatchetInfo := range response.Message.EncryptionLayer.HashRatchetInfo { + messages, err := s.persistence.GetHashRatchetMessages(hashRatchetInfo.KeyID) + if err != nil { + return nil, err + } + + var processedIds [][]byte + for _, message := range messages { + hlogger.Info("handling out of order encrypted messages", zap.String("hash", types.Bytes2Hex(message.Hash))) + r, err := s.handleMessage(message) + if err != nil { + hlogger.Debug("failed to handle hash ratchet message", zap.Error(err)) + continue + } + response.DatasyncMessages = append(response.toPublicResponse().StatusMessages, r.Messages()...) + response.DatasyncAcks = append(response.DatasyncAcks, r.DatasyncAcks...) + + processedIds = append(processedIds, message.Hash) + } + + err = s.persistence.DeleteHashRatchetMessages(processedIds) + if err != nil { + s.logger.Warn("failed to delete hash ratchet messages", zap.Error(err)) + return nil, err + } + } + + return response.toPublicResponse(), nil +} + +func (h *handleMessageResponse) toPublicResponse() *messagingtypes.HandleMessageResponse { + return &messagingtypes.HandleMessageResponse{ + Hash: h.Hash, + StatusMessages: h.Messages(), + DatasyncSender: h.DatasyncSender, + DatasyncAcks: h.DatasyncAcks, + DatasyncOffers: h.DatasyncOffers, + DatasyncRequests: h.DatasyncRequests, + } +} + +type handleMessageResponse struct { + Hash []byte + Message *messagingtypes.Message + DatasyncMessages []*messagingtypes.Message + DatasyncSender *ecdsa.PublicKey + DatasyncAcks [][]byte + DatasyncOffers []messagingtypes.DatasyncOffer + DatasyncRequests [][]byte +} + +func (h *handleMessageResponse) Messages() []*messagingtypes.Message { + if len(h.DatasyncMessages) > 0 { + return h.DatasyncMessages + } + return []*messagingtypes.Message{h.Message} +} + +func (s *MessageSender) handleMessage(receivedMsg *messagingtypes.ReceivedMessage) (*handleMessageResponse, error) { + logger := s.logger.With(zap.String("site", "handleMessage")) + hlogger := logger.With(zap.String("hash", types.EncodeHex(receivedMsg.Hash))) + + message := &messagingtypes.Message{} + + response := &handleMessageResponse{ + Hash: receivedMsg.Hash, + Message: message, + DatasyncMessages: []*messagingtypes.Message{}, + DatasyncAcks: [][]byte{}, + } + + err := populateMessageTransportLayer(message, receivedMsg) + if err != nil { + hlogger.Error("failed to handle transport layer message", zap.Error(err)) + return nil, err + } + + err = s.handleSegmentationLayer(message) + if err != nil { + // Segments not completed yet, stop processing + if err == ErrMessageSegmentsIncomplete { + return nil, err + } + // Segments already completed, stop processing + if err == ErrMessageSegmentsAlreadyCompleted { + return nil, err + } + + // Not a critical error; message wasn't segmented, proceed with next layers. + } + + err = s.handleEncryptionLayer(context.Background(), message) + if err != nil { + hlogger.Debug("failed to handle an encryption message", zap.Error(err)) + + // Hash ratchet with a group id not found yet, stop processing + if err == encryption.ErrHashRatchetGroupIDNotFound { + return response, err + } + } + + if s.datasync != nil && s.datasyncEnabled { + err := s.unwrapDatasyncMessage(message, response) + if err != nil { + hlogger.Debug("failed to handle datasync message", zap.Error(err)) + } + } + + for _, msg := range response.Messages() { + err := populateMessageApplicationLayer(msg) + if err != nil { + hlogger.Error("failed to handle application metadata layer message", zap.Error(err)) + } + s.logger.Debug("calculated ID for envelope", + zap.String("envelopeHash", hexutil.Encode(msg.TransportLayer.Hash)), + zap.String("messageId", hexutil.Encode(msg.ApplicationLayer.ID)), + ) + } + + return response, nil +} + +// fetchDecryptionKey returns the private key associated with this public key, and returns true if it's an ephemeral key +func (s *MessageSender) fetchDecryptionKey(destination *ecdsa.PublicKey) (*ecdsa.PrivateKey, bool) { + destinationID := types.EncodeHex(crypto.FromECDSAPub(destination)) + + s.ephemeralKeysMutex.Lock() + decryptionKey, ok := s.ephemeralKeys[destinationID] + s.ephemeralKeysMutex.Unlock() + + // the key is not there, fallback on identity + if !ok { + return s.identity, false + } + return decryptionKey, true +} + +func (s *MessageSender) handleEncryptionLayer(ctx context.Context, message *messagingtypes.Message) error { + logger := s.logger.Named("handleEncryptionLayer") + publicKey := message.SigPubKey() + + // if it's an ephemeral key, we don't negotiate a topic + decryptionKey, skipNegotiation := s.fetchDecryptionKey(message.TransportLayer.Dst) + + err := populateMessageEncryptionLayer(message, decryptionKey, publicKey, s.protocol, skipNegotiation) + + // if it's an ephemeral key, we don't have to handle a device not found error + if err == encryption.ErrDeviceNotFound && !skipNegotiation { + if err := s.handleErrDeviceNotFound(ctx, publicKey); err != nil { + logger.Error("failed to handle ErrDeviceNotFound", zap.Error(err)) + } + } + if err != nil { + return err + } + + return nil +} + +func (s *MessageSender) handleErrDeviceNotFound(ctx context.Context, publicKey *ecdsa.PublicKey) error { + now := time.Now().Unix() + advertise, err := s.protocol.ShouldAdvertiseBundle(publicKey, now) + if err != nil { + return err + } + if !advertise { + return nil + } + + messageSpec, err := s.protocol.BuildBundleAdvertiseMessage(s.identity, publicKey) + if err != nil { + return err + } + + ctx, cancel := context.WithTimeout(ctx, time.Second) + defer cancel() + // We don't pass an array of messageIDs as no action needs to be taken + // when sending a bundle + _, _, err = s.sendMessageSpec(ctx, publicKey, messageSpec, nil) + if err != nil { + return err + } + + s.protocol.ConfirmBundleAdvertisement(publicKey, now) + + return nil +} + +func (s *MessageSender) wrapMessageV1(rawMessage *messagingtypes.RawMessage) ([]byte, error) { + wrappedMessage, err := v1protocol.WrapMessageV1(rawMessage.Payload, rawMessage.MessageType, rawMessage.Sender) + if err != nil { + return nil, errors.Wrap(err, "failed to wrap message") + } + return wrappedMessage, nil +} + +func (s *MessageSender) addToDataSync(publicKey *ecdsa.PublicKey, message []byte) ([]byte, error) { + groupID := datasync.ToOneToOneGroupID(&s.identity.PublicKey, publicKey) + peerID := datasyncpeer.PublicKeyToPeerID(*publicKey) + exist, err := s.datasync.IsPeerInGroup(groupID, peerID) + if err != nil { + return nil, errors.Wrap(err, "failed to check if peer is in group") + } + if !exist { + if err := s.datasync.AddPeer(groupID, peerID); err != nil { + return nil, errors.Wrap(err, "failed to add peer") + } + } + id, err := s.datasync.AppendMessage(groupID, message) + if err != nil { + return nil, errors.Wrap(err, "failed to append message to datasync") + } + + return id[:], nil +} + +// sendPrivateRawMessage sends a message not wrapped in an encryption layer +func (s *MessageSender) sendPrivateRawMessage(ctx context.Context, rawMessage *messagingtypes.RawMessage, publicKey *ecdsa.PublicKey, payload []byte) ([][]byte, []*wakutypes.NewMessage, error) { + newMessage := &wakutypes.NewMessage{ + Payload: payload, + PubsubTopic: rawMessage.PubsubTopic, + } + + newMessages, err := s.segmentMessage(newMessage) + if err != nil { + return nil, nil, err + } + + hashes := make([][]byte, 0, len(newMessages)) + var hash []byte + for _, newMessage := range newMessages { + if rawMessage.SendOnPersonalTopic { + hash, err = s.transport.SendPrivateOnPersonalTopic(ctx, newMessage, publicKey) + } else { + hash, err = s.transport.SendPrivateWithPartitioned(ctx, newMessage, publicKey) + } + if err != nil { + return nil, nil, err + } + hashes = append(hashes, hash) + } + + return hashes, newMessages, nil +} + +// sendCommunityMessage sends a message not wrapped in an encryption layer +// to a community +func (s *MessageSender) dispatchCommunityMessage(ctx context.Context, publicKey *ecdsa.PublicKey, wrappedMessage []byte, pubsubTopic string, rekey bool, rawMessage *messagingtypes.RawMessage) ([][]byte, []*wakutypes.NewMessage, error) { + payload := wrappedMessage + if rekey && len(rawMessage.HashRatchetGroupID) != 0 { + + var ratchet *encryption.HashRatchetKeyCompatibility + var err error + // We have just rekeyed, pull the latest + if RekeyCompatibility { + ratchet, err = s.protocol.GetCurrentKeyForGroup(rawMessage.HashRatchetGroupID) + if err != nil { + return nil, nil, err + } + + } + keyID, err := ratchet.GetKeyID() + if err != nil { + return nil, nil, err + } + s.logger.Debug("adding key id to message", zap.String("keyid", types.Bytes2Hex(keyID))) + // We send the message over the community topic + spec, err := s.protocol.BuildHashRatchetReKeyGroupMessage(s.identity, rawMessage.Recipients, rawMessage.HashRatchetGroupID, wrappedMessage, ratchet) + if err != nil { + return nil, nil, err + } + payload, err = proto.Marshal(spec.Message) + if err != nil { + return nil, nil, err + } + } + + newMessage := &wakutypes.NewMessage{ + Payload: payload, + PubsubTopic: pubsubTopic, + } + + newMessages, err := s.segmentMessage(newMessage) + if err != nil { + return nil, nil, err + } + + hashes := make([][]byte, 0, len(newMessages)) + for _, newMessage := range newMessages { + hash, err := s.transport.SendCommunityMessage(ctx, newMessage, publicKey) + if err != nil { + return nil, nil, err + } + hashes = append(hashes, hash) + } + + return hashes, newMessages, nil +} + +func (s *MessageSender) SendMessageSpec(ctx context.Context, publicKey *ecdsa.PublicKey, messageSpec *encryption.ProtocolMessageSpec, messageIDs [][]byte) ([][]byte, []*wakutypes.NewMessage, error) { + return s.sendMessageSpec(ctx, publicKey, messageSpec, messageIDs) +} + +// sendMessageSpec analyses the spec properties and selects a proper transport method. +func (s *MessageSender) sendMessageSpec(ctx context.Context, publicKey *ecdsa.PublicKey, messageSpec *encryption.ProtocolMessageSpec, messageIDs [][]byte) ([][]byte, []*wakutypes.NewMessage, error) { + logger := s.logger.With(zap.String("site", "sendMessageSpec")) + + newMessage, err := MessageSpecToWhisper(messageSpec) + if err != nil { + return nil, nil, err + } + + newMessages, err := s.segmentMessage(newMessage) + if err != nil { + return nil, nil, err + } + + hashes := make([][]byte, 0, len(newMessages)) + var hash []byte + for _, newMessage := range newMessages { + // The shared secret needs to be handle before we send a message + // otherwise the topic might not be set up before we receive a message + if messageSpec.SharedSecret != nil && s.handleSharedSecrets != nil { + err := s.handleSharedSecrets([]*sharedsecret.Secret{messageSpec.SharedSecret}) + if err != nil { + return nil, nil, err + } + + } + // process shared secret + if messageSpec.AgreedSecret { + logger.Debug("sending using shared secret") + hash, err = s.transport.SendPrivateWithSharedSecret(ctx, newMessage, publicKey, messageSpec.SharedSecret.Key) + } else { + logger.Debug("sending partitioned topic") + hash, err = s.transport.SendPrivateWithPartitioned(ctx, newMessage, publicKey) + } + if err != nil { + return nil, nil, err + } + hashes = append(hashes, hash) + } + + sentMessage := &messagingevents.SentMessage{ + PublicKey: publicKey, + Spec: messageSpec, + MessageIDs: messageIDs, + } + + s.notifyOnSentMessage(sentMessage) + + return hashes, newMessages, nil +} + +func (s *MessageSender) notifyOnSentMessage(sentMessage *messagingevents.SentMessage) { + pubsub.Publish(s.publisher, messagingevents.MessageEvent{ + Type: messagingevents.MessageSent, + SentMessage: sentMessage, + }) +} + +func (s *MessageSender) notifyOnSentRawMessage(rawMessage *messagingtypes.RawMessage) { + pubsub.Publish(s.publisher, messagingevents.MessageEvent{ + Type: messagingevents.RawMessageSent, + RawMessage: rawMessage, + }) +} + +func (s *MessageSender) notifyOnScheduledMessage(recipient *ecdsa.PublicKey, message *messagingtypes.RawMessage) { + pubsub.Publish(s.publisher, messagingevents.MessageEvent{ + Type: messagingevents.MessageScheduled, + Recipient: recipient, + RawMessage: message, + }) +} + +func (s *MessageSender) JoinPublic(id string) (*messagingtypes.ChatFilter, error) { + filter, err := s.transport.JoinPublic(id) + if err != nil { + return nil, err + } + return adapters.FromTransportFilter(filter), nil +} + +func (s *MessageSender) getRandomEphemeralKey() *ecdsa.PrivateKey { + k := rand.Intn(len(s.ephemeralKeys)) //nolint: gosec + for _, key := range s.ephemeralKeys { + if k == 0 { + return key + } + k-- + } + return nil +} + +func (s *MessageSender) GetEphemeralKey() (*ecdsa.PrivateKey, error) { + s.ephemeralKeysMutex.Lock() + if len(s.ephemeralKeys) >= maxMessageSenderEphemeralKeys { + s.ephemeralKeysMutex.Unlock() + return s.getRandomEphemeralKey(), nil + } + privateKey, err := crypto.GenerateKey() + if err != nil { + s.ephemeralKeysMutex.Unlock() + return nil, err + } + + s.ephemeralKeys[types.EncodeHex(crypto.FromECDSAPub(&privateKey.PublicKey))] = privateKey + s.ephemeralKeysMutex.Unlock() + _, err = s.transport.LoadKeyFilters(privateKey) + if err != nil { + return nil, err + } + + return privateKey, nil +} + +func MessageSpecToWhisper(spec *encryption.ProtocolMessageSpec) (*wakutypes.NewMessage, error) { + var newMessage *wakutypes.NewMessage + + payload, err := proto.Marshal(spec.Message) + if err != nil { + return newMessage, err + } + + newMessage = &wakutypes.NewMessage{ + Payload: payload, + } + return newMessage, nil +} + +func (s *MessageSender) StopDatasync() { + if s.datasync != nil { + s.datasync.Stop() + } +} + +// GetCurrentKeyForGroup returns the latest key timestampID belonging to a key group +func (s *MessageSender) GetCurrentKeyForGroup(groupID []byte) (*encryption.HashRatchetKeyCompatibility, error) { + return s.protocol.GetCurrentKeyForGroup(groupID) +} + +// GetKeyIDsForGroup returns a slice of key IDs belonging to a given group ID +func (s *MessageSender) GetKeysForGroup(groupID []byte) ([]*encryption.HashRatchetKeyCompatibility, error) { + return s.protocol.GetKeysForGroup(groupID) +} + +func (s *MessageSender) CleanupHashRatchetEncryptedMessages() error { + monthAgo := time.Now().AddDate(0, -1, 0).Unix() + + err := s.persistence.DeleteHashRatchetMessagesOlderThan(monthAgo) + if err != nil { + return err + } + + return nil +} + +func (s *MessageSender) Publisher() *pubsub.Publisher { + return s.publisher +} + +func populateMessageTransportLayer(m *messagingtypes.Message, msg *messagingtypes.ReceivedMessage) error { + publicKey, err := crypto.UnmarshalPubkey(msg.Sig) + if err != nil { + return errors.Wrap(err, "failed to get signature") + } + + m.TransportLayer.Message = msg + m.TransportLayer.Hash = msg.Hash + m.TransportLayer.SigPubKey = publicKey + m.TransportLayer.Payload = msg.Payload + + if msg.Dst != nil { + publicKey, err := crypto.UnmarshalPubkey(msg.Dst) + if err != nil { + return err + } + m.TransportLayer.Dst = publicKey + } + + return nil +} + +func populateMessageEncryptionLayer(m *messagingtypes.Message, myKey *ecdsa.PrivateKey, senderKey *ecdsa.PublicKey, enc *encryption.Protocol, skipNegotiation bool) error { + // As we handle non-encrypted messages, we make sure that DecryptPayload + // is set regardless of whether this step is successful + m.EncryptionLayer.Payload = m.TransportLayer.Payload + // Nothing to do + if skipNegotiation { + return nil + } + + var protocolMessage encryption.ProtocolMessage + err := proto.Unmarshal(m.TransportLayer.Payload, &protocolMessage) + if err != nil { + return errors.Wrap(err, "failed to unmarshal ProtocolMessage") + } + + response, err := enc.HandleMessage( + myKey, + senderKey, + &protocolMessage, + m.TransportLayer.Hash, + ) + + if err == encryption.ErrHashRatchetGroupIDNotFound { + + if response != nil { + m.EncryptionLayer.HashRatchetInfo = adapters.FromEncryptionHashRatchets(response.HashRatchetInfo) + } + return err + } + + if err != nil { + return errors.Wrap(err, "failed to handle Encryption message") + } + + m.EncryptionLayer.Payload = response.DecryptedMessage + m.EncryptionLayer.Installations = adapters.FromEncryptionInstallations(response.Installations) + m.EncryptionLayer.SharedSecrets = adapters.FromEncryptionSharedSecrets(response.SharedSecrets) + m.EncryptionLayer.HashRatchetInfo = adapters.FromEncryptionHashRatchets(response.HashRatchetInfo) + return nil +} + +func populateMessageApplicationLayer(m *messagingtypes.Message) error { + message, err := protobuf.Unmarshal(m.EncryptionLayer.Payload) + if err != nil { + return err + } + + recoveredKey, err := utils.RecoverKey(message) + if err != nil { + return err + } + + m.ApplicationLayer.SigPubKey = recoveredKey + // Calculate ID using the wrapped record + m.ApplicationLayer.ID = messagingtypes.MessageID(recoveredKey, m.EncryptionLayer.Payload) + m.ApplicationLayer.Payload = message.Payload + m.ApplicationLayer.Type = message.Type + return nil +} diff --git a/messaging/common/message_sender_test.go b/messaging/common/message_sender_test.go new file mode 100644 index 0000000000..814a91300b --- /dev/null +++ b/messaging/common/message_sender_test.go @@ -0,0 +1,382 @@ +package common + +import ( + "math" + "testing" + + "github.com/status-im/status-go/messaging/adapters" + "github.com/status-im/status-go/messaging/layers/transport" + messagingtypes "github.com/status-im/status-go/messaging/types" + wakuv2 "github.com/status-im/status-go/messaging/waku" + wakutypes "github.com/status-im/status-go/messaging/waku/types" + "github.com/status-im/status-go/t/helpers" + + "github.com/libp2p/go-libp2p/core/peer" + + "github.com/golang/protobuf/proto" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + datasyncproto "github.com/status-im/mvds/protobuf" + + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/messaging/datasync" + "github.com/status-im/status-go/messaging/layers/encryption" + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/sqlite" + v1protocol "github.com/status-im/status-go/protocol/v1" + + "github.com/status-im/status-go/appdatabase" +) + +func TestMessageSenderSuite(t *testing.T) { + suite.Run(t, new(MessageSenderSuite)) +} + +type MessageSenderSuite struct { + suite.Suite + + sender *MessageSender + testMessage protobuf.ChatMessage + logger *zap.Logger +} + +func (s *MessageSenderSuite) SetupTest() { + s.testMessage = protobuf.ChatMessage{ + Text: "abc123", + ChatId: "testing-adamb", + ContentType: protobuf.ChatMessage_TEXT_PLAIN, + MessageType: protobuf.MessageType_PUBLIC_GROUP, + Clock: 154593077368201, + Timestamp: 1545930773682, + } + + var err error + + s.logger, err = zap.NewDevelopment() + s.Require().NoError(err) + + identity, err := crypto.GenerateKey() + s.Require().NoError(err) + + database, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(database) + s.Require().NoError(err) + + encryptionProtocol := encryption.New( + database, + "installation-1", + s.logger, + ) + + wakuConfig := wakuv2.DefaultConfig + shh, err := wakuv2.New( + nil, + &wakuConfig, + s.logger, + database, + nil, + func([]byte, peer.AddrInfo, error) {}, + nil, + ) + s.Require().NoError(err) + s.Require().NoError(shh.Start()) + + stubPersistence := NewStubPersistence() + + transport, err := transport.NewTransport( + shh, + identity, + &adapters.KeysPersistence{P: stubPersistence}, + &adapters.ProcessedMessageIDsCache{P: stubPersistence}, + &transport.EnvelopesMonitorConfig{}, + s.logger, + ) + s.Require().NoError(err) + + s.sender, err = NewMessageSender( + identity, + database, + stubPersistence, + transport, + encryptionProtocol, + s.logger, + ) + s.Require().NoError(err) +} + +func (s *MessageSenderSuite) TearDownTest() { + _ = s.logger.Sync() +} + +func (s *MessageSenderSuite) TestHandleDecodedMessagesWrapped() { + relayerKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + authorKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + encodedPayload, err := proto.Marshal(&s.testMessage) + s.Require().NoError(err) + + wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey) + s.Require().NoError(err) + + message := &messagingtypes.ReceivedMessage{} + message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey) + message.Payload = wrappedPayload + + response, err := s.sender.HandleMessages(message) + s.Require().NoError(err) + decodedMessages := response.StatusMessages + + s.Require().Equal(1, len(decodedMessages)) + s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) + s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID) + s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload) + s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type) +} + +func (s *MessageSenderSuite) TestHandleDecodedMessagesDatasync() { + relayerKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + authorKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + encodedPayload, err := proto.Marshal(&s.testMessage) + s.Require().NoError(err) + + wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey) + s.Require().NoError(err) + + ds := datasync.New(nil, nil, false, s.sender.logger) + s.sender.datasync = ds + + dataSyncMessage := datasyncproto.Payload{ + Messages: []*datasyncproto.Message{ + {Body: wrappedPayload}, + }, + } + marshalledDataSyncMessage, err := proto.Marshal(&dataSyncMessage) + s.Require().NoError(err) + message := &messagingtypes.ReceivedMessage{} + message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey) + message.Payload = marshalledDataSyncMessage + + response, err := s.sender.HandleMessages(message) + s.Require().NoError(err) + decodedMessages := response.StatusMessages + + // We send two messages, the unwrapped one will be attributed to the relayer, while the wrapped one will be attributed to the author + s.Require().Equal(1, len(decodedMessages)) + s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) + s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID) + s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload) + s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type) +} + +func (s *MessageSenderSuite) TestHandleDecodedMessagesDatasyncEncrypted() { + relayerKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + authorKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + encodedPayload, err := proto.Marshal(&s.testMessage) + s.Require().NoError(err) + + wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey) + s.Require().NoError(err) + + dataSyncMessage := datasyncproto.Payload{ + Messages: []*datasyncproto.Message{ + {Body: wrappedPayload}, + }, + } + marshalledDataSyncMessage, err := proto.Marshal(&dataSyncMessage) + s.Require().NoError(err) + + // Create sender encryption protocol. + senderDatabase, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(senderDatabase) + s.Require().NoError(err) + + senderEncryptionProtocol := encryption.New( + senderDatabase, + "installation-2", + s.logger, + ) + + messageSpec, err := senderEncryptionProtocol.BuildEncryptedMessage( + relayerKey, + &s.sender.identity.PublicKey, + marshalledDataSyncMessage, + ) + s.Require().NoError(err) + + encryptedPayload, err := proto.Marshal(messageSpec.Message) + s.Require().NoError(err) + + message := &messagingtypes.ReceivedMessage{} + message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey) + message.Payload = encryptedPayload + + ds := datasync.New(nil, nil, false, s.sender.logger) + s.sender.datasync = ds + + response, err := s.sender.HandleMessages(message) + s.Require().NoError(err) + decodedMessages := response.StatusMessages + + // We send two messages, the unwrapped one will be attributed to the relayer, + // while the wrapped one will be attributed to the author. + s.Require().Equal(1, len(decodedMessages)) + s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) + s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID) + s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload) + s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type) +} + +func (s *MessageSenderSuite) TestHandleOutOfOrderHashRatchet() { + groupID := []byte("group-id") + senderKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + encodedPayload, err := proto.Marshal(&s.testMessage) + s.Require().NoError(err) + + // Create sender encryption protocol. + senderDatabase, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(senderDatabase) + s.Require().NoError(err) + + senderEncryptionProtocol := encryption.New( + senderDatabase, + "installation-2", + s.logger, + ) + + ratchet, err := senderEncryptionProtocol.GenerateHashRatchetKey(groupID) + s.Require().NoError(err) + + ratchets := []*encryption.HashRatchetKeyCompatibility{ratchet} + + hashRatchetKeyExchangeMessage, err := senderEncryptionProtocol.BuildHashRatchetKeyExchangeMessage(senderKey, &s.sender.identity.PublicKey, groupID, ratchets) + s.Require().NoError(err) + + encryptedPayload1, err := proto.Marshal(hashRatchetKeyExchangeMessage.Message) + s.Require().NoError(err) + + wrappedPayload2, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, senderKey) + s.Require().NoError(err) + + messageSpec2, err := senderEncryptionProtocol.BuildHashRatchetMessage( + groupID, + wrappedPayload2, + ) + s.Require().NoError(err) + + encryptedPayload2, err := proto.Marshal(messageSpec2.Message) + s.Require().NoError(err) + + message := &messagingtypes.ReceivedMessage{} + message.Sig = crypto.FromECDSAPub(&senderKey.PublicKey) + message.Hash = []byte{0x1} + message.Payload = encryptedPayload2 + + _, err = s.sender.HandleMessages(message) + s.Require().NoError(err) + + keyID, err := ratchet.GetKeyID() + s.Require().NoError(err) + + msgs, err := s.sender.persistence.GetHashRatchetMessages(keyID) + s.Require().NoError(err) + + s.Require().Len(msgs, 1) + + message = &messagingtypes.ReceivedMessage{} + message.Sig = crypto.FromECDSAPub(&senderKey.PublicKey) + message.Hash = []byte{0x2} + message.Payload = encryptedPayload1 + + response, err := s.sender.HandleMessages(message) + s.Require().NoError(err) + decodedMessages2 := response.StatusMessages + s.Require().NotNil(decodedMessages2) + + // It should have 2 messages, the key exchange and the one from the database + s.Require().Len(decodedMessages2, 2) + + // it deletes the messages after being processed + msgs, err = s.sender.persistence.GetHashRatchetMessages(keyID) + s.Require().NoError(err) + + s.Require().Len(msgs, 0) +} + +func (s *MessageSenderSuite) TestHandleSegmentMessages() { + relayerKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + authorKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + encodedPayload, err := proto.Marshal(&s.testMessage) + s.Require().NoError(err) + + wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey) + s.Require().NoError(err) + + segmentedMessages, err := segmentMessage(&wakutypes.NewMessage{Payload: wrappedPayload}, int(math.Ceil(float64(len(wrappedPayload))/2))) + s.Require().NoError(err) + s.Require().Len(segmentedMessages, 2) + + message := &messagingtypes.ReceivedMessage{} + message.Sig = crypto.FromECDSAPub(&relayerKey.PublicKey) + message.Payload = segmentedMessages[0].Payload + + // First segment is received, no messages are decoded + response, err := s.sender.HandleMessages(message) + s.Require().NoError(err) + s.Require().Nil(response) + + // Second (and final) segment is received, reassembled message is decoded + message.Payload = segmentedMessages[1].Payload + response, err = s.sender.HandleMessages(message) + s.Require().NoError(err) + + decodedMessages := response.StatusMessages + s.Require().Len(decodedMessages, 1) + s.Require().Equal(&authorKey.PublicKey, decodedMessages[0].SigPubKey()) + s.Require().Equal(v1protocol.MessageID(&authorKey.PublicKey, wrappedPayload), decodedMessages[0].ApplicationLayer.ID) + s.Require().Equal(encodedPayload, decodedMessages[0].ApplicationLayer.Payload) + s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].ApplicationLayer.Type) + + // Receiving another segment after the message has been reassembled is considered an error + _, err = s.sender.HandleMessages(message) + s.Require().ErrorIs(err, ErrMessageSegmentsAlreadyCompleted) +} + +func (s *MessageSenderSuite) TestGetEphemeralKey() { + keyMap := make(map[string]bool) + for i := 0; i < maxMessageSenderEphemeralKeys; i++ { + key, err := s.sender.GetEphemeralKey() + s.Require().NoError(err) + s.Require().NotNil(key) + keyMap[common.PubkeyToHex(&key.PublicKey)] = true + } + s.Require().Len(keyMap, maxMessageSenderEphemeralKeys) + // Add one more + key, err := s.sender.GetEphemeralKey() + s.Require().NoError(err) + s.Require().NotNil(key) + + s.Require().True(keyMap[common.PubkeyToHex(&key.PublicKey)]) +} diff --git a/messaging/common/persistence_stub_test.go b/messaging/common/persistence_stub_test.go new file mode 100644 index 0000000000..ead0d4dbfe --- /dev/null +++ b/messaging/common/persistence_stub_test.go @@ -0,0 +1,264 @@ +package common + +import ( + "crypto/ecdsa" + "encoding/hex" + "sort" + "sync" + + "github.com/jinzhu/copier" + "google.golang.org/protobuf/proto" + + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/messaging/types" + "github.com/status-im/status-go/protocol/protobuf" +) + +// StubPersistence is an in-memory implementation of types.Persistence for testing. +type StubPersistence struct { + mu sync.Mutex + + wakuKeys map[string][]byte + + messageCache map[string]uint64 + + hashRatchetMessages map[string]*types.ReceivedMessage // hash -> received message + hashRatchetMessagesByKeyID map[string][]*types.ReceivedMessage // keyID -> received messages + + messageSegments map[string]map[string][]*types.SegmentMessage // hash+pubkey -> segments + completedSegments map[string]struct{} // hash +} + +func NewStubPersistence() *StubPersistence { + return &StubPersistence{ + wakuKeys: make(map[string][]byte), + messageCache: make(map[string]uint64), + hashRatchetMessages: make(map[string]*types.ReceivedMessage), + hashRatchetMessagesByKeyID: make(map[string][]*types.ReceivedMessage), + messageSegments: make(map[string]map[string][]*types.SegmentMessage), + completedSegments: make(map[string]struct{}), + } +} + +func (s *StubPersistence) WakuKeys() (map[string][]byte, error) { + s.mu.Lock() + defer s.mu.Unlock() + + copy := make(map[string][]byte, len(s.wakuKeys)) + err := copier.Copy(©, s.wakuKeys) + if err != nil { + return nil, err + } + + return copy, nil +} + +func (s *StubPersistence) AddWakuKey(chatID string, key []byte) error { + s.mu.Lock() + defer s.mu.Unlock() + + copy := make([]byte, 0, len(key)) + err := copier.Copy(©, key) + if err != nil { + return err + } + + s.wakuKeys[chatID] = copy + return nil +} + +func (s *StubPersistence) MessageCacheAdd(ids []string, timestamp uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + + for _, id := range ids { + s.messageCache[id] = timestamp + } + return nil +} + +func (s *StubPersistence) MessageCacheClear() error { + s.mu.Lock() + defer s.mu.Unlock() + + s.messageCache = make(map[string]uint64) + return nil +} + +func (s *StubPersistence) MessageCacheClearOlderThan(timestamp uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + + for id, ts := range s.messageCache { + if ts < timestamp { + delete(s.messageCache, id) + } + } + return nil +} + +func (s *StubPersistence) MessageCacheHits(ids []string) (map[string]bool, error) { + s.mu.Lock() + defer s.mu.Unlock() + + hits := make(map[string]bool) + for _, id := range ids { + _, ok := s.messageCache[id] + hits[id] = ok + } + return hits, nil +} + +func (s *StubPersistence) SaveHashRatchetMessage(groupID []byte, keyID []byte, m *types.ReceivedMessage) error { + s.mu.Lock() + defer s.mu.Unlock() + + copy := &types.ReceivedMessage{} + err := copier.Copy(copy, m) + if err != nil { + return err + } + + hash := hex.EncodeToString(copy.Hash) + key := hex.EncodeToString(keyID) + s.hashRatchetMessages[hash] = copy + s.hashRatchetMessagesByKeyID[key] = append(s.hashRatchetMessagesByKeyID[key], copy) + + return nil +} + +func (s *StubPersistence) GetHashRatchetMessages(keyID []byte) ([]*types.ReceivedMessage, error) { + s.mu.Lock() + defer s.mu.Unlock() + + key := hex.EncodeToString(keyID) + msgs := s.hashRatchetMessagesByKeyID[key] + + copy := make([]*types.ReceivedMessage, 0, len(msgs)) + err := copier.Copy(©, msgs) + if err != nil { + return nil, err + } + + return copy, nil +} + +func (s *StubPersistence) DeleteHashRatchetMessages(ids [][]byte) error { + s.mu.Lock() + defer s.mu.Unlock() + + for _, id := range ids { + hash := hex.EncodeToString(id) + msg, ok := s.hashRatchetMessages[hash] + if ok { + // Remove from hashRatchetMessagesByKeyID as well + for key, arr := range s.hashRatchetMessagesByKeyID { + for i, m := range arr { + if m == msg { + s.hashRatchetMessagesByKeyID[key] = append(arr[:i], arr[i+1:]...) + break + } + } + } + delete(s.hashRatchetMessages, hash) + } + } + return nil +} + +func (s *StubPersistence) IsMessageAlreadyCompleted(hash []byte) (bool, error) { + s.mu.Lock() + defer s.mu.Unlock() + + _, exists := s.completedSegments[string(hash)] + return exists, nil +} + +func (s *StubPersistence) SaveMessageSegment(segment *types.SegmentMessage, sigPubKey *ecdsa.PublicKey, timestamp int64) error { + s.mu.Lock() + defer s.mu.Unlock() + + copy := &types.SegmentMessage{ + SegmentMessage: proto.Clone(segment.SegmentMessage).(*protobuf.SegmentMessage), + } + + hash := string(segment.EntireMessageHash) + pubKey := string(crypto.CompressPubkey(sigPubKey)) + if s.messageSegments[hash] == nil { + s.messageSegments[hash] = make(map[string][]*types.SegmentMessage) + } + s.messageSegments[hash][pubKey] = append(s.messageSegments[hash][pubKey], copy) + return nil +} + +func (s *StubPersistence) GetMessageSegments(hash []byte, sigPubKey *ecdsa.PublicKey) ([]*types.SegmentMessage, error) { + s.mu.Lock() + defer s.mu.Unlock() + + segments := s.messageSegments[string(hash)][string(crypto.CompressPubkey(sigPubKey))] + copy := make([]*types.SegmentMessage, 0, len(segments)) + for _, seg := range segments { + cloned := &types.SegmentMessage{ + SegmentMessage: proto.Clone(seg.SegmentMessage).(*protobuf.SegmentMessage), + } + copy = append(copy, cloned) + } + + // Sort segments: non-parity first, then by index, then by parity index + sort.SliceStable(copy, func(i, j int) bool { + si, sj := copy[i], copy[j] + + // Non-parity segments first + if si.SegmentsCount == 0 && sj.SegmentsCount > 0 { + return false + } + if si.SegmentsCount > 0 && sj.SegmentsCount == 0 { + return true + } + + if si.SegmentsCount > 0 { + return si.Index < sj.Index + } + + return si.ParitySegmentIndex < sj.ParitySegmentIndex + }) + + return copy, nil +} + +func (s *StubPersistence) CompleteMessageSegments(hash []byte, sigPubKey *ecdsa.PublicKey, timestamp int64) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.completedSegments[string(hash)] = struct{}{} + + h := string(hash) + pubKey := string(crypto.CompressPubkey(sigPubKey)) + if s.messageSegments[h] != nil { + delete(s.messageSegments[h], pubKey) + if len(s.messageSegments[h]) == 0 { + delete(s.messageSegments, h) + } + } + return nil +} + +func (s *StubPersistence) DeleteHashRatchetMessagesOlderThan(timestamp int64) error { + // Not implemented for stub + return nil +} + +func (s *StubPersistence) InsertPendingConfirmation(*types.RawMessageConfirmation) error { + // Not implemented for stub + return nil +} + +func (s *StubPersistence) RemoveMessageSegmentsOlderThan(timestamp int64) error { + // Not implemented for stub + return nil +} + +func (s *StubPersistence) RemoveMessageSegmentsCompletedOlderThan(timestamp int64) error { + // Not implemented for stub + return nil +} diff --git a/messaging/common/testdata/segmentationProtobufMissDecoding.bin b/messaging/common/testdata/segmentationProtobufMissDecoding.bin new file mode 100644 index 0000000000000000000000000000000000000000..6fb29c2ca4e28a6b2363470b4d1e61ceefd65848 GIT binary patch literal 19321 zcmeI)J8P6d6b9hTDoOmRu!Z>&EM#qD5u7=5M^GZcP75m$5#}mnQ4kXd>AXN11zpK+ zFrr{<8EjRErRfDtq3IRz+x&(!!aKv9Vg}xGcz(b%OZz+9_rI>c|8wK*)i1ZzyL%Vs zU)=e-yScY;ZfoWD>yPJ`?!NivFMS>zteqOP?S;`w@8PG7QSayGv%PJ5>*OQW-``@* zWxmdfE22hkye3alPYwl_i%C{`qkWWxxUD9VvmtAWnQ}~_#NZtjJNM(&uMg9M*AE? zhDkP4qUwT=C6#Wnnsag1XJum6%0^F>%b*?SP9~Bx>CdUEQbMgZM-rMx8zadoy08$7 z($-WPqD_%^qb6OeQC%nnTcVIE1tF?br25Ai#uj@m8_o}=)7oSYkFS;ot2A>)bzPRP zT%Wpmco7flm>r1%?T%TqGiFm*5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb n2tWV=5P$##AOHafK;S seqNo shouldn't occur + if seqNo-hrCache.SeqNo > maxHashRatchetSeqNoDelta { + return nil, ErrHashRatchetSeqNoTooHigh + } + for i := hrCache.SeqNo; i < seqNo; i++ { + hash = crypto.Keccak256Hash(hash).Bytes() + err := s.persistence.SaveHashRatchetKeyHash(ratchet, hash, i+1) + if err != nil { + return nil, err + } + } + } + + decryptedPayload, err := crypto.DecryptSymmetric(hash, payload) + + if err != nil { + s.logger.Error("failed to decrypt hash", zap.Error(err)) + return nil, err + } + return decryptedPayload, nil +} diff --git a/messaging/layers/encryption/helpers.go b/messaging/layers/encryption/helpers.go new file mode 100644 index 0000000000..c82e8b6a2a --- /dev/null +++ b/messaging/layers/encryption/helpers.go @@ -0,0 +1,152 @@ +package encryption + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/rand" + "encoding/binary" + "errors" + "io" + "time" + + "github.com/status-im/status-go/crypto" +) + +const keyBumpValue = uint64(10) + +// GetCurrentTime64 returns the current unix time in milliseconds +func GetCurrentTime() uint64 { + return (uint64)(time.Now().UnixMilli()) +} + +// bumpKeyID takes a timestampID and returns its value incremented by the keyBumpValue +func bumpKeyID(timestampID uint64) uint64 { + return timestampID + keyBumpValue +} + +func generateHashRatchetKeyID(groupID []byte, timestamp uint64, keyBytes []byte) []byte { + var keyMaterial []byte + + keyMaterial = append(keyMaterial, groupID...) + + timestampBytes := make([]byte, 8) // 8 bytes for a uint64 + binary.LittleEndian.PutUint64(timestampBytes, timestamp) + keyMaterial = append(keyMaterial, timestampBytes...) + + keyMaterial = append(keyMaterial, keyBytes...) + + return crypto.Keccak256(keyMaterial) +} + +func publicKeyMostRelevantBytes(key *ecdsa.PublicKey) uint32 { + + keyBytes := crypto.FromECDSAPub(key) + + return binary.LittleEndian.Uint32(keyBytes[1:5]) +} + +func encrypt(plaintext []byte, key []byte, reader io.Reader) ([]byte, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err = io.ReadFull(reader, nonce); err != nil { + return nil, err + } + + return gcm.Seal(nonce, nonce, plaintext, nil), nil +} + +func buildGroupRekeyMessage(privateKey *ecdsa.PrivateKey, groupID []byte, timestamp uint64, keyMaterial []byte, keys []*ecdsa.PublicKey) (*RekeyGroup, error) { + + message := &RekeyGroup{ + Timestamp: timestamp, + } + + message.Keys = make(map[uint32][]byte) + + for _, k := range keys { + + sharedKey, err := crypto.GenerateSharedKey(privateKey, k) + if err != nil { + return nil, err + } + + encryptedKey, err := encrypt(keyMaterial, sharedKey, rand.Reader) + if err != nil { + return nil, err + } + + kBytes := publicKeyMostRelevantBytes(k) + + if message.Keys[kBytes] == nil { + message.Keys[kBytes] = encryptedKey + } else { + message.Keys[kBytes] = append(message.Keys[kBytes], encryptedKey...) + } + } + + return message, nil +} + +const nonceLength = 12 + +func decrypt(cyphertext []byte, key []byte) ([]byte, error) { + if len(cyphertext) < nonceLength { + return nil, errors.New("invalid cyphertext length") + } + + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + nonce := cyphertext[:nonceLength] + return gcm.Open(nil, nonce, cyphertext[nonceLength:], nil) +} + +const keySize = 60 + +func decryptGroupRekeyMessage(privateKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, message *RekeyGroup) ([]byte, error) { + kBytes := publicKeyMostRelevantBytes(&privateKey.PublicKey) + if message.Keys == nil || message.Keys[kBytes] == nil { + return nil, nil + } + + sharedKey, err := crypto.GenerateSharedKey(privateKey, publicKey) + if err != nil { + return nil, err + } + + keys := message.Keys[kBytes] + + nKeys := len(keys) / keySize + + var decryptedKey []byte + for i := 0; i < nKeys; i++ { + + encryptedKey := keys[i*keySize : i*keySize+keySize] + decryptedKey, err = decrypt(encryptedKey, sharedKey) + if err != nil { + continue + } else { + break + } + + } + + return decryptedKey, nil +} diff --git a/messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.down.sql b/messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.down.sql new file mode 100644 index 0000000000..e458de8821 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.down.sql @@ -0,0 +1,4 @@ +DROP TABLE sessions; +DROP TABLE bundles; +DROP TABLE keys; +DROP TABLE ratchet_info; diff --git a/messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.up.sql b/messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.up.sql new file mode 100644 index 0000000000..1c6b318302 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1536754952_initial_schema.up.sql @@ -0,0 +1,40 @@ +CREATE TABLE sessions ( + dhr BLOB, + dhs_public BLOB, + dhs_private BLOB, + root_chain_key BLOB, + send_chain_key BLOB, + send_chain_n INTEGER, + recv_chain_key BLOB, + recv_chain_n INTEGER, + step INTEGER, + pn INTEGER, + id BLOB NOT NULL PRIMARY KEY, + UNIQUE(id) ON CONFLICT REPLACE +); + +CREATE TABLE keys ( + public_key BLOB NOT NULL, + msg_num INTEGER, + message_key BLOB NOT NULL, + UNIQUE (msg_num, message_key) ON CONFLICT REPLACE +); + +CREATE TABLE bundles ( + identity BLOB NOT NULL, + installation_id TEXT NOT NULL, + private_key BLOB, + signed_pre_key BLOB NOT NULL PRIMARY KEY ON CONFLICT IGNORE, + timestamp UNSIGNED BIG INT NOT NULL, + expired BOOLEAN DEFAULT 0 +); + +CREATE TABLE ratchet_info ( + bundle_id BLOB NOT NULL, + ephemeral_key BLOB, + identity BLOB NOT NULL, + symmetric_key BLOB NOT NULL, + installation_id TEXT NOT NULL, + UNIQUE(bundle_id, identity) ON CONFLICT REPLACE, + FOREIGN KEY (bundle_id) REFERENCES bundles(signed_pre_key) +); diff --git a/messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.down.sql b/messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.down.sql new file mode 100644 index 0000000000..22f67da7e0 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.down.sql @@ -0,0 +1,11 @@ +DROP TABLE ratchet_info_v2; + +CREATE TABLE ratchet_info ( + bundle_id BLOB NOT NULL, + ephemeral_key BLOB, + identity BLOB NOT NULL, + symmetric_key BLOB NOT NULL, + installation_id TEXT NOT NULL, + UNIQUE(bundle_id, identity) ON CONFLICT REPLACE, + FOREIGN KEY (bundle_id) REFERENCES bundles(signed_pre_key) +); diff --git a/messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.up.sql b/messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.up.sql new file mode 100644 index 0000000000..ca2a112f5b --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1539249977_update_ratchet_info.up.sql @@ -0,0 +1,13 @@ +DELETE FROM sessions; +DELETE FROM keys; +DROP TABLE ratchet_info; + +CREATE TABLE ratchet_info_v2 ( + bundle_id BLOB NOT NULL, + ephemeral_key BLOB, + identity BLOB NOT NULL, + symmetric_key BLOB NOT NULL, + installation_id TEXT NOT NULL, + UNIQUE(bundle_id, identity, installation_id) ON CONFLICT REPLACE, + FOREIGN KEY (bundle_id) REFERENCES bundles(signed_pre_key) +); diff --git a/messaging/layers/encryption/migrations/sqlite/1540715431_add_version.down.sql b/messaging/layers/encryption/migrations/sqlite/1540715431_add_version.down.sql new file mode 100644 index 0000000000..a6bc43c512 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1540715431_add_version.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE keys DROP COLUMN session_id; +ALTER TABLE sessions DROP COLUMN keys_count; +ALTER TABLE bundles DROP COLUMN version; diff --git a/messaging/layers/encryption/migrations/sqlite/1540715431_add_version.up.sql b/messaging/layers/encryption/migrations/sqlite/1540715431_add_version.up.sql new file mode 100644 index 0000000000..574eb99e5e --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1540715431_add_version.up.sql @@ -0,0 +1,5 @@ +DELETE FROM keys; +ALTER TABLE keys ADD COLUMN seq_num INTEGER NOT NULL DEFAULT 0; +ALTER TABLE keys ADD COLUMN session_id BLOB; +ALTER TABLE sessions ADD COLUMN keys_count INTEGER NOT NULL DEFAULT 0; +ALTER TABLE bundles ADD COLUMN version INTEGER NOT NULL DEFAULT 0; diff --git a/messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.down.sql b/messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.down.sql new file mode 100644 index 0000000000..adc8e2e570 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.down.sql @@ -0,0 +1 @@ +DROP TABLE installations; diff --git a/messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.up.sql b/messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.up.sql new file mode 100644 index 0000000000..b35f976597 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1541164797_add_installations.up.sql @@ -0,0 +1,7 @@ +CREATE TABLE installations ( + identity BLOB NOT NULL, + installation_id TEXT NOT NULL, + timestamp UNSIGNED BIG INT NOT NULL, + enabled BOOLEAN DEFAULT 1, + UNIQUE(identity, installation_id) ON CONFLICT REPLACE +); diff --git a/messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.down.sql b/messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.down.sql new file mode 100644 index 0000000000..1d1e25a51e --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.down.sql @@ -0,0 +1,2 @@ +DROP TABLE secret_installation_ids; +DROP TABLE secrets; diff --git a/messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.up.sql b/messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.up.sql new file mode 100644 index 0000000000..baf69f08b9 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1558084410_add_secret.up.sql @@ -0,0 +1,11 @@ +CREATE TABLE secrets ( + identity BLOB NOT NULL PRIMARY KEY ON CONFLICT IGNORE, + secret BLOB NOT NULL +); + +CREATE TABLE secret_installation_ids ( + id TEXT NOT NULL, + identity_id BLOB NOT NULL, + UNIQUE(id, identity_id) ON CONFLICT IGNORE, + FOREIGN KEY (identity_id) REFERENCES secrets(identity) +); diff --git a/messaging/layers/encryption/migrations/sqlite/1558588866_add_version.down.sql b/messaging/layers/encryption/migrations/sqlite/1558588866_add_version.down.sql new file mode 100644 index 0000000000..f8dba62ab3 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1558588866_add_version.down.sql @@ -0,0 +1 @@ +ALTER TABLE installations DROP COLUMN version; diff --git a/messaging/layers/encryption/migrations/sqlite/1558588866_add_version.up.sql b/messaging/layers/encryption/migrations/sqlite/1558588866_add_version.up.sql new file mode 100644 index 0000000000..10c1172080 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1558588866_add_version.up.sql @@ -0,0 +1 @@ +ALTER TABLE installations ADD version INTEGER DEFAULT 0; diff --git a/messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.down.sql b/messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.down.sql new file mode 100644 index 0000000000..5c891a3760 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.down.sql @@ -0,0 +1 @@ +DROP TABLE contact_code_config; diff --git a/messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.up.sql b/messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.up.sql new file mode 100644 index 0000000000..51ea8a0489 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1559627659_add_contact_code.up.sql @@ -0,0 +1,6 @@ +CREATE TABLE contact_code_config ( + unique_constraint varchar(1) NOT NULL PRIMARY KEY DEFAULT 'X', + last_published INTEGER NOT NULL DEFAULT 0 +); + +INSERT INTO contact_code_config VALUES ('X', 0); diff --git a/messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.down.sql b/messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.down.sql new file mode 100644 index 0000000000..ba2c563de4 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.down.sql @@ -0,0 +1 @@ +DROP TABLE installations_metadata; diff --git a/messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.up.sql b/messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.up.sql new file mode 100644 index 0000000000..84f84f7f4f --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1561368210_add_installation_metadata.up.sql @@ -0,0 +1,8 @@ +CREATE TABLE installation_metadata ( + identity BLOB NOT NULL, + installation_id TEXT NOT NULL, + name TEXT NOT NULL DEFAULT '', + device_type TEXT NOT NULL DEFAULT '', + fcm_token TEXT NOT NULL DEFAULT '', + UNIQUE(identity, installation_id) ON CONFLICT REPLACE +); diff --git a/messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.down.sql b/messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.down.sql new file mode 100644 index 0000000000..577d132b19 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.down.sql @@ -0,0 +1,5 @@ +DROP INDEX idx_hash_ratchet_enc; +DROP INDEX idx_hash_ratchet_enc_cache; + +DROP TABLE hash_ratchet_encryption_cache; +DROP TABLE hash_ratchet_encryption; diff --git a/messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.up.sql b/messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.up.sql new file mode 100644 index 0000000000..72db8e7b3b --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1632236298_add_communities.up.sql @@ -0,0 +1,20 @@ +CREATE TABLE hash_ratchet_encryption ( + group_id BLOB NOT NULL, + key_id INT NOT NULL, + key BLOB NOT NULL, + PRIMARY KEY(group_id, key_id) +); + +CREATE UNIQUE INDEX idx_hash_ratchet_enc ON hash_ratchet_encryption(group_id, key_id); + +CREATE TABLE hash_ratchet_encryption_cache ( + group_id BLOB NOT NULL, + key_id int NOT NULL, + seq_no INTEGER, + hash BLOB NOT NULL, + sym_enc_key BLOB, + FOREIGN KEY(group_id, key_id) REFERENCES hash_ratchet_encryption(group_id, key_id) +); + +CREATE UNIQUE INDEX idx_hash_ratchet_enc_cache ON hash_ratchet_encryption_cache(group_id, key_id, seq_no); + diff --git a/messaging/layers/encryption/migrations/sqlite/1636536507_add_index_bundles.up.sql b/messaging/layers/encryption/migrations/sqlite/1636536507_add_index_bundles.up.sql new file mode 100644 index 0000000000..992bb20e9a --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1636536507_add_index_bundles.up.sql @@ -0,0 +1,3 @@ +CREATE INDEX encryption_bundles_expired_identity_installation_id_version on bundles (expired, identity, installation_id, version); +CREATE INDEX encryption_bundles_expired_identity_installation_id on bundles (identity, installation_id, version); +CREATE INDEX ratchet_info_v2_identity_installation_id on ratchet_info_v2 (identity, installation_id); diff --git a/messaging/layers/encryption/migrations/sqlite/1698137564_add_migration_index.up.sql b/messaging/layers/encryption/migrations/sqlite/1698137564_add_migration_index.up.sql new file mode 100644 index 0000000000..c1bf16532e --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1698137564_add_migration_index.up.sql @@ -0,0 +1,11 @@ +CREATE INDEX IF NOT EXISTS idx_group_timestamp_desc +ON hash_ratchet_encryption (group_id, key_timestamp DESC); + +CREATE INDEX IF NOT EXISTS idx_hash_ratchet_encryption_keys_key_id +ON hash_ratchet_encryption (key_id); + +CREATE INDEX IF NOT EXISTS idx_hash_ratchet_encryption_keys_deprecated_key_id +ON hash_ratchet_encryption (deprecated_key_id); + +CREATE INDEX IF NOT EXISTS idx_hash_ratchet_cache_group_id_key_id_seq_no +ON hash_ratchet_encryption_cache (group_id, key_id, seq_no DESC); diff --git a/messaging/layers/encryption/migrations/sqlite/1709200114_add_migration_index.up.sql b/messaging/layers/encryption/migrations/sqlite/1709200114_add_migration_index.up.sql new file mode 100644 index 0000000000..c1bf16532e --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/1709200114_add_migration_index.up.sql @@ -0,0 +1,11 @@ +CREATE INDEX IF NOT EXISTS idx_group_timestamp_desc +ON hash_ratchet_encryption (group_id, key_timestamp DESC); + +CREATE INDEX IF NOT EXISTS idx_hash_ratchet_encryption_keys_key_id +ON hash_ratchet_encryption (key_id); + +CREATE INDEX IF NOT EXISTS idx_hash_ratchet_encryption_keys_deprecated_key_id +ON hash_ratchet_encryption (deprecated_key_id); + +CREATE INDEX IF NOT EXISTS idx_hash_ratchet_cache_group_id_key_id_seq_no +ON hash_ratchet_encryption_cache (group_id, key_id, seq_no DESC); diff --git a/messaging/layers/encryption/migrations/sqlite/doc.go b/messaging/layers/encryption/migrations/sqlite/doc.go new file mode 100644 index 0000000000..ff87a062b2 --- /dev/null +++ b/messaging/layers/encryption/migrations/sqlite/doc.go @@ -0,0 +1,9 @@ +// This file is necessary because "github.com/status-im/migrate/v4" +// can't handle files starting with a prefix. At least that's the case +// for go-bindata. +// If go-bindata is called from the same directory, asset names +// have no prefix and "github.com/status-im/migrate/v4" works as expected. + +package sqlite + +//go:generate go-bindata -modtime=1700000000 -pkg migrations -o ../migrations.go . diff --git a/messaging/layers/encryption/multidevice/multidevice.go b/messaging/layers/encryption/multidevice/multidevice.go new file mode 100644 index 0000000000..1468d96ba8 --- /dev/null +++ b/messaging/layers/encryption/multidevice/multidevice.go @@ -0,0 +1,129 @@ +package multidevice + +import ( + "crypto/ecdsa" + "database/sql" + + "github.com/status-im/status-go/crypto" +) + +type InstallationMetadata struct { + // The name of the device + Name string `json:"name"` + // The type of device + DeviceType string `json:"deviceType"` + // The FCMToken for mobile devices + FCMToken string `json:"fcmToken"` +} + +type Installation struct { + // Identity is the string identity of the owner + Identity string `json:"identity"` + // The installation-id of the device + ID string `json:"id"` + // The last known protocol version of the device + Version uint32 `json:"version"` + // Enabled is whether the installation is enabled + Enabled bool `json:"enabled"` + // Timestamp is the last time we saw this device + Timestamp int64 `json:"timestamp"` + // InstallationMetadata + InstallationMetadata *InstallationMetadata `json:"metadata"` +} + +func (i *Installation) UniqueKey() string { + return i.ID + i.Identity +} + +type Config struct { + MaxInstallations int + ProtocolVersion uint32 + InstallationID string +} + +type Multidevice struct { + persistence *sqlitePersistence + config *Config +} + +func New(db *sql.DB, config *Config) *Multidevice { + return &Multidevice{ + config: config, + persistence: newSQLitePersistence(db), + } +} + +func (s *Multidevice) InstallationID() string { + return s.config.InstallationID +} + +func (s *Multidevice) GetActiveInstallations(identity *ecdsa.PublicKey) ([]*Installation, error) { + identityC := crypto.CompressPubkey(identity) + return s.persistence.GetActiveInstallations(s.config.MaxInstallations, identityC) +} + +func (s *Multidevice) GetOurActiveInstallations(identity *ecdsa.PublicKey) ([]*Installation, error) { + identityC := crypto.CompressPubkey(identity) + installations, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations-1, identityC) + if err != nil { + return nil, err + } + + installations = append(installations, &Installation{ + ID: s.config.InstallationID, + Version: s.config.ProtocolVersion, + }) + + return installations, nil +} + +func (s *Multidevice) GetOurInstallations(identity *ecdsa.PublicKey) ([]*Installation, error) { + var found bool + identityC := crypto.CompressPubkey(identity) + installations, err := s.persistence.GetInstallations(identityC) + if err != nil { + return nil, err + } + + for _, installation := range installations { + if installation.ID == s.config.InstallationID { + found = true + installation.Enabled = true + installation.Version = s.config.ProtocolVersion + } + + } + if !found { + installations = append(installations, &Installation{ + ID: s.config.InstallationID, + Enabled: true, + Version: s.config.ProtocolVersion, + }) + } + + return installations, nil +} + +func (s *Multidevice) AddInstallations(identity []byte, timestamp int64, installations []*Installation, defaultEnabled bool) ([]*Installation, error) { + return s.persistence.AddInstallations(identity, timestamp, installations, defaultEnabled) +} + +func (s *Multidevice) SetInstallationMetadata(identity *ecdsa.PublicKey, installationID string, metadata *InstallationMetadata) error { + identityC := crypto.CompressPubkey(identity) + return s.persistence.SetInstallationMetadata(identityC, installationID, metadata) +} + +func (s *Multidevice) SetInstallationName(identity *ecdsa.PublicKey, installationID string, name string) error { + identityC := crypto.CompressPubkey(identity) + return s.persistence.SetInstallationName(identityC, installationID, name) +} + +func (s *Multidevice) EnableInstallation(identity *ecdsa.PublicKey, installationID string) error { + identityC := crypto.CompressPubkey(identity) + return s.persistence.EnableInstallation(identityC, installationID) +} + +func (s *Multidevice) DisableInstallation(myIdentityKey *ecdsa.PublicKey, installationID string) error { + myIdentityKeyC := crypto.CompressPubkey(myIdentityKey) + return s.persistence.DisableInstallation(myIdentityKeyC, installationID) +} diff --git a/messaging/layers/encryption/multidevice/persistence.go b/messaging/layers/encryption/multidevice/persistence.go new file mode 100644 index 0000000000..37e10f0021 --- /dev/null +++ b/messaging/layers/encryption/multidevice/persistence.go @@ -0,0 +1,282 @@ +package multidevice + +import "database/sql" + +type sqlitePersistence struct { + db *sql.DB +} + +func newSQLitePersistence(db *sql.DB) *sqlitePersistence { + return &sqlitePersistence{db: db} +} + +// GetActiveInstallations returns the active installations for a given identity +func (s *sqlitePersistence) GetActiveInstallations(maxInstallations int, identity []byte) ([]*Installation, error) { + stmt, err := s.db.Prepare(`SELECT installation_id, version + FROM installations + WHERE enabled = 1 AND identity = ? + ORDER BY timestamp DESC + LIMIT ?`) + if err != nil { + return nil, err + } + defer stmt.Close() + + var installations []*Installation + rows, err := stmt.Query(identity, maxInstallations) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var ( + installationID string + version uint32 + ) + err = rows.Scan( + &installationID, + &version, + ) + if err != nil { + return nil, err + } + installations = append(installations, &Installation{ + ID: installationID, + Version: version, + Enabled: true, + }) + + } + + return installations, nil + +} + +// GetInstallations returns all the installations for a given identity +// we both return the installations & the metadata +// metadata is currently stored in a separate table, as in some cases we +// might have metadata for a device, but no other information on the device +func (s *sqlitePersistence) GetInstallations(identity []byte) ([]*Installation, error) { + installationMap := make(map[string]*Installation) + var installations []*Installation + + // We query both tables as sqlite does not support full outer joins + installationsStmt, err := s.db.Prepare(`SELECT installation_id, version, enabled, timestamp FROM installations WHERE identity = ?`) + if err != nil { + return nil, err + } + defer installationsStmt.Close() + + installationRows, err := installationsStmt.Query(identity) + if err != nil { + return nil, err + } + + for installationRows.Next() { + var installation Installation + err = installationRows.Scan( + &installation.ID, + &installation.Version, + &installation.Enabled, + &installation.Timestamp, + ) + if err != nil { + return nil, err + } + // We initialized to empty in this case as we want to + // return metadata as well in this endpoint, but not in others + installation.InstallationMetadata = &InstallationMetadata{} + installationMap[installation.ID] = &installation + } + + metadataStmt, err := s.db.Prepare(`SELECT installation_id, name, device_type, fcm_token FROM installation_metadata WHERE identity = ?`) + if err != nil { + return nil, err + } + defer metadataStmt.Close() + + metadataRows, err := metadataStmt.Query(identity) + if err != nil { + return nil, err + } + + for metadataRows.Next() { + var ( + installationID string + name sql.NullString + deviceType sql.NullString + fcmToken sql.NullString + installation *Installation + ) + err = metadataRows.Scan( + &installationID, + &name, + &deviceType, + &fcmToken, + ) + if err != nil { + return nil, err + } + if _, ok := installationMap[installationID]; ok { + installation = installationMap[installationID] + } else { + installation = &Installation{ID: installationID} + } + installation.InstallationMetadata = &InstallationMetadata{ + Name: name.String, + DeviceType: deviceType.String, + FCMToken: fcmToken.String, + } + installationMap[installationID] = installation + } + + for _, installation := range installationMap { + installations = append(installations, installation) + } + + return installations, nil +} + +// AddInstallations adds the installations for a given identity, maintaining the enabled flag +func (s *sqlitePersistence) AddInstallations(identity []byte, timestamp int64, installations []*Installation, defaultEnabled bool) ([]*Installation, error) { + tx, err := s.db.Begin() + if err != nil { + return nil, err + } + + var insertedInstallations []*Installation + + for _, installation := range installations { + stmt, err := tx.Prepare(`SELECT enabled, version + FROM installations + WHERE identity = ? AND installation_id = ? + LIMIT 1`) + if err != nil { + return nil, err + } + defer stmt.Close() + + var oldEnabled bool + // We don't override version once we saw one + var oldVersion uint32 + latestVersion := installation.Version + + err = stmt.QueryRow(identity, installation.ID).Scan(&oldEnabled, &oldVersion) + if err != nil && err != sql.ErrNoRows { + return nil, err + } + + if err == sql.ErrNoRows { + stmt, err = tx.Prepare(`INSERT INTO installations(identity, installation_id, timestamp, enabled, version) + VALUES (?, ?, ?, ?, ?)`) + if err != nil { + return nil, err + } + defer stmt.Close() + + _, err = stmt.Exec( + identity, + installation.ID, + timestamp, + defaultEnabled, + latestVersion, + ) + if err != nil { + return nil, err + } + insertedInstallations = append(insertedInstallations, installation) + } else { + // We update timestamp if present without changing enabled, only if this is a new bundle + // and we set the version to the latest we ever saw + if oldVersion > installation.Version { + latestVersion = oldVersion + } + + stmt, err = tx.Prepare(`UPDATE installations + SET timestamp = ?, enabled = ?, version = ? + WHERE identity = ? + AND installation_id = ? + AND timestamp < ?`) + if err != nil { + return nil, err + } + defer stmt.Close() + + _, err = stmt.Exec( + timestamp, + oldEnabled, + latestVersion, + identity, + installation.ID, + timestamp, + ) + if err != nil { + return nil, err + } + } + + } + + if err := tx.Commit(); err != nil { + _ = tx.Rollback() + return nil, err + } + + return insertedInstallations, nil + +} + +// EnableInstallation enables the installation +func (s *sqlitePersistence) EnableInstallation(identity []byte, installationID string) error { + stmt, err := s.db.Prepare(`UPDATE installations + SET enabled = 1 + WHERE identity = ? AND installation_id = ?`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec(identity, installationID) + return err + +} + +// DisableInstallation disable the installation +func (s *sqlitePersistence) DisableInstallation(identity []byte, installationID string) error { + stmt, err := s.db.Prepare(`UPDATE installations + SET enabled = 0 + WHERE identity = ? AND installation_id = ?`) + if err != nil { + return err + } + defer stmt.Close() + _, err = stmt.Exec(identity, installationID) + return err +} + +// SetInstallationMetadata sets the metadata for a given installation +func (s *sqlitePersistence) SetInstallationMetadata(identity []byte, installationID string, metadata *InstallationMetadata) error { + stmt, err := s.db.Prepare(`INSERT INTO installation_metadata(name, device_type, fcm_token, identity, installation_id) VALUES(?,?,?,?,?)`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec(metadata.Name, metadata.DeviceType, metadata.FCMToken, identity, installationID) + return err +} + +// SetInstallationName sets the only the name in metadata for a given installation +func (s *sqlitePersistence) SetInstallationName(identity []byte, installationID string, name string) error { + stmt, err := s.db.Prepare(`UPDATE installation_metadata + SET name = ? + WHERE identity = ? AND installation_id = ?`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec(name, identity, installationID) + return err +} diff --git a/messaging/layers/encryption/multidevice/persistence_test.go b/messaging/layers/encryption/multidevice/persistence_test.go new file mode 100644 index 0000000000..3e272d2532 --- /dev/null +++ b/messaging/layers/encryption/multidevice/persistence_test.go @@ -0,0 +1,307 @@ +package multidevice + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/protocol/sqlite" + "github.com/status-im/status-go/t/helpers" +) + +func TestSQLLitePersistenceTestSuite(t *testing.T) { + suite.Run(t, new(SQLLitePersistenceTestSuite)) +} + +type SQLLitePersistenceTestSuite struct { + suite.Suite + service *sqlitePersistence +} + +func (s *SQLLitePersistenceTestSuite) SetupTest() { + db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(db) + s.Require().NoError(err) + + s.service = newSQLitePersistence(db) +} + +func (s *SQLLitePersistenceTestSuite) TestAddInstallations() { + identity := []byte("alice") + installations := []*Installation{ + {ID: "alice-1", Version: 1, Enabled: true}, + {ID: "alice-2", Version: 2, Enabled: true}, + } + addedInstallations, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + + enabledInstallations, err := s.service.GetActiveInstallations(5, identity) + s.Require().NoError(err) + + s.Require().Equal(installations, enabledInstallations) + s.Require().Equal(installations, addedInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestAddInstallationVersions() { + identity := []byte("alice") + installations := []*Installation{ + {ID: "alice-1", Version: 1, Enabled: true}, + } + _, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + + s.Require().NoError(err) + + enabledInstallations, err := s.service.GetActiveInstallations(5, identity) + s.Require().NoError(err) + + s.Require().Equal(installations, enabledInstallations) + + installationsWithDowngradedVersion := []*Installation{ + {ID: "alice-1", Version: 0}, + } + + _, err = s.service.AddInstallations( + identity, + 3, + installationsWithDowngradedVersion, + true, + ) + s.Require().NoError(err) + + enabledInstallations, err = s.service.GetActiveInstallations(5, identity) + s.Require().NoError(err) + s.Require().Equal(installations, enabledInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestAddInstallationsLimit() { + identity := []byte("alice") + + installations := []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + _, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + + installations = []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-3", Version: 3}, + } + + _, err = s.service.AddInstallations( + identity, + 2, + installations, + true, + ) + s.Require().NoError(err) + + installations = []*Installation{ + {ID: "alice-2", Version: 2, Enabled: true}, + {ID: "alice-3", Version: 3, Enabled: true}, + {ID: "alice-4", Version: 4, Enabled: true}, + } + + _, err = s.service.AddInstallations( + identity, + 3, + installations, + true, + ) + s.Require().NoError(err) + + enabledInstallations, err := s.service.GetActiveInstallations(3, identity) + s.Require().NoError(err) + + s.Require().Equal(installations, enabledInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestAddInstallationsDisabled() { + identity := []byte("alice") + + installations := []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + _, err := s.service.AddInstallations( + identity, + 1, + installations, + false, + ) + s.Require().NoError(err) + + actualInstallations, err := s.service.GetActiveInstallations(3, identity) + s.Require().NoError(err) + + s.Require().Nil(actualInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestDisableInstallation() { + identity := []byte("alice") + + installations := []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + _, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + + err = s.service.DisableInstallation(identity, "alice-1") + s.Require().NoError(err) + + // We add the installations again + installations = []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + addedInstallations, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + s.Require().Equal(0, len(addedInstallations)) + + actualInstallations, err := s.service.GetActiveInstallations(3, identity) + s.Require().NoError(err) + + expected := []*Installation{{ID: "alice-2", Version: 2, Enabled: true}} + s.Require().Equal(expected, actualInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestEnableInstallation() { + identity := []byte("alice") + + installations := []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + _, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + + err = s.service.DisableInstallation(identity, "alice-1") + s.Require().NoError(err) + + actualInstallations, err := s.service.GetActiveInstallations(3, identity) + s.Require().NoError(err) + + expected := []*Installation{{ID: "alice-2", Version: 2, Enabled: true}} + s.Require().Equal(expected, actualInstallations) + + err = s.service.EnableInstallation(identity, "alice-1") + s.Require().NoError(err) + + actualInstallations, err = s.service.GetActiveInstallations(3, identity) + s.Require().NoError(err) + + expected = []*Installation{ + {ID: "alice-1", Version: 1, Enabled: true}, + {ID: "alice-2", Version: 2, Enabled: true}, + } + s.Require().Equal(expected, actualInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestGetInstallations() { + identity := []byte("alice") + + installations := []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + _, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + + err = s.service.DisableInstallation(identity, "alice-1") + s.Require().NoError(err) + + actualInstallations, err := s.service.GetInstallations(identity) + s.Require().NoError(err) + + emptyMetadata := &InstallationMetadata{} + + expected := []*Installation{ + {ID: "alice-1", Version: 1, Timestamp: 1, Enabled: false, InstallationMetadata: emptyMetadata}, + {ID: "alice-2", Version: 2, Timestamp: 1, Enabled: true, InstallationMetadata: emptyMetadata}, + } + s.Require().Equal(2, len(actualInstallations)) + s.Require().ElementsMatch(expected, actualInstallations) +} + +func (s *SQLLitePersistenceTestSuite) TestSetMetadata() { + identity := []byte("alice") + + installations := []*Installation{ + {ID: "alice-1", Version: 1}, + {ID: "alice-2", Version: 2}, + } + + _, err := s.service.AddInstallations( + identity, + 1, + installations, + true, + ) + s.Require().NoError(err) + + err = s.service.DisableInstallation(identity, "alice-1") + s.Require().NoError(err) + + emptyMetadata := &InstallationMetadata{} + setMetadata := &InstallationMetadata{ + Name: "a", + FCMToken: "b", + DeviceType: "c", + } + + err = s.service.SetInstallationMetadata(identity, "alice-2", setMetadata) + s.Require().NoError(err) + + actualInstallations, err := s.service.GetInstallations(identity) + s.Require().NoError(err) + + expected := []*Installation{ + {ID: "alice-1", Version: 1, Timestamp: 1, Enabled: false, InstallationMetadata: emptyMetadata}, + {ID: "alice-2", Version: 2, Timestamp: 1, Enabled: true, InstallationMetadata: setMetadata}, + } + s.Require().ElementsMatch(expected, actualInstallations) +} diff --git a/messaging/layers/encryption/persistence.go b/messaging/layers/encryption/persistence.go new file mode 100644 index 0000000000..53e9d45fc4 --- /dev/null +++ b/messaging/layers/encryption/persistence.go @@ -0,0 +1,1011 @@ +package encryption + +import ( + "context" + "crypto/ecdsa" + "database/sql" + "errors" + "strings" + + dr "github.com/status-im/doubleratchet" + + "github.com/status-im/status-go/crypto" + + "github.com/status-im/status-go/messaging/layers/encryption/multidevice" +) + +// RatchetInfo holds the current ratchet state. +type RatchetInfo struct { + ID []byte + Sk []byte + PrivateKey []byte + PublicKey []byte + Identity []byte + BundleID []byte + EphemeralKey []byte + InstallationID string +} + +// A safe max number of rows. +const maxNumberOfRows = 100000000 + +type sqlitePersistence struct { + DB *sql.DB + keysStorage dr.KeysStorage + sessionStorage dr.SessionStorage +} + +func newSQLitePersistence(db *sql.DB) *sqlitePersistence { + return &sqlitePersistence{ + DB: db, + keysStorage: newSQLiteKeysStorage(db), + sessionStorage: newSQLiteSessionStorage(db), + } +} + +// GetKeysStorage returns the associated double ratchet KeysStorage object +func (s *sqlitePersistence) KeysStorage() dr.KeysStorage { + return s.keysStorage +} + +// GetSessionStorage returns the associated double ratchet SessionStorage object +func (s *sqlitePersistence) SessionStorage() dr.SessionStorage { + return s.sessionStorage +} + +// AddPrivateBundle adds the specified BundleContainer to the database +func (s *sqlitePersistence) AddPrivateBundle(bc *BundleContainer) error { + tx, err := s.DB.Begin() + if err != nil { + return err + } + + for installationID, signedPreKey := range bc.GetBundle().GetSignedPreKeys() { + var version uint32 + stmt, err := tx.Prepare(`SELECT version + FROM bundles + WHERE installation_id = ? AND identity = ? + ORDER BY version DESC + LIMIT 1`) + if err != nil { + return err + } + + defer stmt.Close() + + err = stmt.QueryRow(installationID, bc.GetBundle().GetIdentity()).Scan(&version) + if err != nil && err != sql.ErrNoRows { + return err + } + + stmt, err = tx.Prepare(`INSERT INTO bundles(identity, private_key, signed_pre_key, installation_id, version, timestamp) + VALUES(?, ?, ?, ?, ?, ?)`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + bc.GetBundle().GetIdentity(), + bc.GetPrivateSignedPreKey(), + signedPreKey.GetSignedPreKey(), + installationID, + version+1, + bc.GetBundle().GetTimestamp(), + ) + if err != nil { + _ = tx.Rollback() + return err + } + } + + if err := tx.Commit(); err != nil { + _ = tx.Rollback() + return err + } + + return nil +} + +// AddPublicBundle adds the specified Bundle to the database +func (s *sqlitePersistence) AddPublicBundle(b *Bundle) error { + tx, err := s.DB.Begin() + + if err != nil { + return err + } + + for installationID, signedPreKeyContainer := range b.GetSignedPreKeys() { + signedPreKey := signedPreKeyContainer.GetSignedPreKey() + version := signedPreKeyContainer.GetVersion() + insertStmt, err := tx.Prepare(`INSERT INTO bundles(identity, signed_pre_key, installation_id, version, timestamp) + VALUES( ?, ?, ?, ?, ?)`) + if err != nil { + return err + } + defer insertStmt.Close() + + _, err = insertStmt.Exec( + b.GetIdentity(), + signedPreKey, + installationID, + version, + b.GetTimestamp(), + ) + if err != nil { + _ = tx.Rollback() + return err + } + // Mark old bundles as expired + updateStmt, err := tx.Prepare(`UPDATE bundles + SET expired = 1 + WHERE identity = ? AND installation_id = ? AND version < ?`) + if err != nil { + return err + } + defer updateStmt.Close() + + _, err = updateStmt.Exec( + b.GetIdentity(), + installationID, + version, + ) + if err != nil { + _ = tx.Rollback() + return err + } + + } + + return tx.Commit() +} + +// GetAnyPrivateBundle retrieves any bundle from the database containing a private key +func (s *sqlitePersistence) GetAnyPrivateBundle(myIdentityKey []byte, installations []*multidevice.Installation) (*BundleContainer, error) { + + versions := make(map[string]uint32) + /* #nosec */ + statement := `SELECT identity, private_key, signed_pre_key, installation_id, timestamp, version + FROM bundles + WHERE expired = 0 AND identity = ? AND installation_id IN (?` + strings.Repeat(",?", len(installations)-1) + ")" + stmt, err := s.DB.Prepare(statement) + if err != nil { + return nil, err + } + defer stmt.Close() + + var timestamp int64 + var identity []byte + var privateKey []byte + var version uint32 + + args := make([]interface{}, len(installations)+1) + args[0] = myIdentityKey + for i, installation := range installations { + // Lookup up map for versions + versions[installation.ID] = installation.Version + + args[i+1] = installation.ID + } + + rows, err := stmt.Query(args...) + rowCount := 0 + + if err != nil { + return nil, err + } + + defer rows.Close() + + bundle := &Bundle{ + SignedPreKeys: make(map[string]*SignedPreKey), + } + + bundleContainer := &BundleContainer{ + Bundle: bundle, + } + + for rows.Next() { + var signedPreKey []byte + var installationID string + rowCount++ + err = rows.Scan( + &identity, + &privateKey, + &signedPreKey, + &installationID, + ×tamp, + &version, + ) + if err != nil { + return nil, err + } + // If there is a private key, we set the timestamp of the bundle container + if privateKey != nil { + bundle.Timestamp = timestamp + } + + bundle.SignedPreKeys[installationID] = &SignedPreKey{ + SignedPreKey: signedPreKey, + Version: version, + ProtocolVersion: versions[installationID], + } + bundle.Identity = identity + } + + // If no records are found or no record with private key, return nil + if rowCount == 0 || bundleContainer.GetBundle().Timestamp == 0 { + return nil, nil + } + + return bundleContainer, nil + +} + +// GetPrivateKeyBundle retrieves a private key for a bundle from the database +func (s *sqlitePersistence) GetPrivateKeyBundle(bundleID []byte) ([]byte, error) { + stmt, err := s.DB.Prepare(`SELECT private_key + FROM bundles + WHERE signed_pre_key = ? LIMIT 1`) + if err != nil { + return nil, err + } + defer stmt.Close() + + var privateKey []byte + + err = stmt.QueryRow(bundleID).Scan(&privateKey) + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + return privateKey, nil + default: + return nil, err + } +} + +// MarkBundleExpired expires any private bundle for a given identity +func (s *sqlitePersistence) MarkBundleExpired(identity []byte) error { + stmt, err := s.DB.Prepare(`UPDATE bundles + SET expired = 1 + WHERE identity = ? AND private_key IS NOT NULL`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec(identity) + + return err +} + +// GetPublicBundle retrieves an existing Bundle for the specified public key from the database +func (s *sqlitePersistence) GetPublicBundle(publicKey *ecdsa.PublicKey, installations []*multidevice.Installation) (*Bundle, error) { + + if len(installations) == 0 { + return nil, nil + } + + versions := make(map[string]uint32) + identity := crypto.CompressPubkey(publicKey) + + /* #nosec */ + statement := `SELECT signed_pre_key,installation_id, version + FROM bundles + WHERE expired = 0 AND identity = ? AND installation_id IN (?` + strings.Repeat(",?", len(installations)-1) + `) + ORDER BY version DESC` + stmt, err := s.DB.Prepare(statement) + if err != nil { + return nil, err + } + defer stmt.Close() + + args := make([]interface{}, len(installations)+1) + args[0] = identity + for i, installation := range installations { + // Lookup up map for versions + versions[installation.ID] = installation.Version + args[i+1] = installation.ID + } + + rows, err := stmt.Query(args...) + rowCount := 0 + + if err != nil { + return nil, err + } + + defer rows.Close() + + bundle := &Bundle{ + Identity: identity, + SignedPreKeys: make(map[string]*SignedPreKey), + } + + for rows.Next() { + var signedPreKey []byte + var installationID string + var version uint32 + rowCount++ + err = rows.Scan( + &signedPreKey, + &installationID, + &version, + ) + if err != nil { + return nil, err + } + + bundle.SignedPreKeys[installationID] = &SignedPreKey{ + SignedPreKey: signedPreKey, + Version: version, + ProtocolVersion: versions[installationID], + } + + } + + if rowCount == 0 { + return nil, nil + } + + return bundle, nil + +} + +// AddRatchetInfo persists the specified ratchet info into the database +func (s *sqlitePersistence) AddRatchetInfo(key []byte, identity []byte, bundleID []byte, ephemeralKey []byte, installationID string) error { + stmt, err := s.DB.Prepare(`INSERT INTO ratchet_info_v2(symmetric_key, identity, bundle_id, ephemeral_key, installation_id) + VALUES(?, ?, ?, ?, ?)`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + key, + identity, + bundleID, + ephemeralKey, + installationID, + ) + + return err +} + +// GetRatchetInfo retrieves the existing RatchetInfo for a specified bundle ID and interlocutor public key from the database +func (s *sqlitePersistence) GetRatchetInfo(bundleID []byte, theirIdentity []byte, installationID string) (*RatchetInfo, error) { + stmt, err := s.DB.Prepare(`SELECT ratchet_info_v2.identity, ratchet_info_v2.symmetric_key, bundles.private_key, bundles.signed_pre_key, ratchet_info_v2.ephemeral_key, ratchet_info_v2.installation_id + FROM ratchet_info_v2 JOIN bundles ON bundle_id = signed_pre_key + WHERE ratchet_info_v2.identity = ? AND ratchet_info_v2.installation_id = ? AND bundle_id = ? + LIMIT 1`) + if err != nil { + return nil, err + } + defer stmt.Close() + + ratchetInfo := &RatchetInfo{ + BundleID: bundleID, + } + + err = stmt.QueryRow(theirIdentity, installationID, bundleID).Scan( + &ratchetInfo.Identity, + &ratchetInfo.Sk, + &ratchetInfo.PrivateKey, + &ratchetInfo.PublicKey, + &ratchetInfo.EphemeralKey, + &ratchetInfo.InstallationID, + ) + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + ratchetInfo.ID = append(bundleID, []byte(ratchetInfo.InstallationID)...) + return ratchetInfo, nil + default: + return nil, err + } +} + +// GetAnyRatchetInfo retrieves any existing RatchetInfo for a specified interlocutor public key from the database +func (s *sqlitePersistence) GetAnyRatchetInfo(identity []byte, installationID string) (*RatchetInfo, error) { + stmt, err := s.DB.Prepare(`SELECT symmetric_key, bundles.private_key, signed_pre_key, bundle_id, ephemeral_key + FROM ratchet_info_v2 JOIN bundles ON bundle_id = signed_pre_key + WHERE expired = 0 AND ratchet_info_v2.identity = ? AND ratchet_info_v2.installation_id = ? + LIMIT 1`) + if err != nil { + return nil, err + } + defer stmt.Close() + + ratchetInfo := &RatchetInfo{ + Identity: identity, + InstallationID: installationID, + } + + err = stmt.QueryRow(identity, installationID).Scan( + &ratchetInfo.Sk, + &ratchetInfo.PrivateKey, + &ratchetInfo.PublicKey, + &ratchetInfo.BundleID, + &ratchetInfo.EphemeralKey, + ) + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + ratchetInfo.ID = append(ratchetInfo.BundleID, []byte(installationID)...) + return ratchetInfo, nil + default: + return nil, err + } +} + +// RatchetInfoConfirmed clears the ephemeral key in the RatchetInfo +// associated with the specified bundle ID and interlocutor identity public key +func (s *sqlitePersistence) RatchetInfoConfirmed(bundleID []byte, theirIdentity []byte, installationID string) error { + stmt, err := s.DB.Prepare(`UPDATE ratchet_info_v2 + SET ephemeral_key = NULL + WHERE identity = ? AND bundle_id = ? AND installation_id = ?`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + theirIdentity, + bundleID, + installationID, + ) + + return err +} + +type sqliteKeysStorage struct { + db *sql.DB +} + +func newSQLiteKeysStorage(db *sql.DB) *sqliteKeysStorage { + return &sqliteKeysStorage{ + db: db, + } +} + +// Get retrieves the message key for a specified public key and message number +func (s *sqliteKeysStorage) Get(pubKey dr.Key, msgNum uint) (dr.Key, bool, error) { + var key []byte + stmt, err := s.db.Prepare(`SELECT message_key + FROM keys + WHERE public_key = ? AND msg_num = ? + LIMIT 1`) + + if err != nil { + return key, false, err + } + defer stmt.Close() + + err = stmt.QueryRow(pubKey, msgNum).Scan(&key) + switch err { + case sql.ErrNoRows: + return key, false, nil + case nil: + return key, true, nil + default: + return key, false, err + } +} + +// Put stores a key with the specified public key, message number and message key +func (s *sqliteKeysStorage) Put(sessionID []byte, pubKey dr.Key, msgNum uint, mk dr.Key, seqNum uint) error { + stmt, err := s.db.Prepare(`INSERT INTO keys(session_id, public_key, msg_num, message_key, seq_num) + VALUES(?, ?, ?, ?, ?)`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + sessionID, + pubKey, + msgNum, + mk, + seqNum, + ) + + return err +} + +// DeleteOldMks caps remove any key < seq_num, included +func (s *sqliteKeysStorage) DeleteOldMks(sessionID []byte, deleteUntil uint) error { + stmt, err := s.db.Prepare(`DELETE FROM keys + WHERE session_id = ? AND seq_num <= ?`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + sessionID, + deleteUntil, + ) + + return err +} + +// TruncateMks caps the number of keys to maxKeysPerSession deleting them in FIFO fashion +func (s *sqliteKeysStorage) TruncateMks(sessionID []byte, maxKeysPerSession int) error { + stmt, err := s.db.Prepare(`DELETE FROM keys + WHERE rowid IN (SELECT rowid FROM keys WHERE session_id = ? ORDER BY seq_num DESC LIMIT ? OFFSET ?)`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + sessionID, + // We LIMIT to the max number of rows here, as OFFSET can't be used without a LIMIT + maxNumberOfRows, + maxKeysPerSession, + ) + + return err +} + +// DeleteMk deletes the key with the specified public key and message key +func (s *sqliteKeysStorage) DeleteMk(pubKey dr.Key, msgNum uint) error { + stmt, err := s.db.Prepare(`DELETE FROM keys + WHERE public_key = ? AND msg_num = ?`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + pubKey, + msgNum, + ) + + return err +} + +// Count returns the count of keys with the specified public key +func (s *sqliteKeysStorage) Count(pubKey dr.Key) (uint, error) { + stmt, err := s.db.Prepare(`SELECT COUNT(1) + FROM keys + WHERE public_key = ?`) + if err != nil { + return 0, err + } + defer stmt.Close() + + var count uint + err = stmt.QueryRow(pubKey).Scan(&count) + if err != nil { + return 0, err + } + + return count, nil +} + +// CountAll returns the count of keys with the specified public key +func (s *sqliteKeysStorage) CountAll() (uint, error) { + stmt, err := s.db.Prepare(`SELECT COUNT(1) + FROM keys`) + if err != nil { + return 0, err + } + defer stmt.Close() + + var count uint + err = stmt.QueryRow().Scan(&count) + if err != nil { + return 0, err + } + + return count, nil +} + +// All returns nil +func (s *sqliteKeysStorage) All() (map[string]map[uint]dr.Key, error) { + return nil, nil +} + +type sqliteSessionStorage struct { + db *sql.DB +} + +func newSQLiteSessionStorage(db *sql.DB) *sqliteSessionStorage { + return &sqliteSessionStorage{ + db: db, + } +} + +// Save persists the specified double ratchet state +func (s *sqliteSessionStorage) Save(id []byte, state *dr.State) error { + dhr := state.DHr + dhs := state.DHs + dhsPublic := dhs.PublicKey() + dhsPrivate := dhs.PrivateKey() + pn := state.PN + step := state.Step + keysCount := state.KeysCount + + rootChainKey := state.RootCh.CK + + sendChainKey := state.SendCh.CK + sendChainN := state.SendCh.N + + recvChainKey := state.RecvCh.CK + recvChainN := state.RecvCh.N + + stmt, err := s.db.Prepare(`INSERT INTO sessions(id, dhr, dhs_public, dhs_private, root_chain_key, send_chain_key, send_chain_n, recv_chain_key, recv_chain_n, pn, step, keys_count) + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec( + id, + dhr, + dhsPublic, + dhsPrivate, + rootChainKey, + sendChainKey, + sendChainN, + recvChainKey, + recvChainN, + pn, + step, + keysCount, + ) + + return err +} + +// Load retrieves the double ratchet state for a given ID +func (s *sqliteSessionStorage) Load(id []byte) (*dr.State, error) { + stmt, err := s.db.Prepare(`SELECT dhr, dhs_public, dhs_private, root_chain_key, send_chain_key, send_chain_n, recv_chain_key, recv_chain_n, pn, step, keys_count + FROM sessions + WHERE id = ?`) + if err != nil { + return nil, err + } + + defer stmt.Close() + + var ( + dhr []byte + dhsPublic []byte + dhsPrivate []byte + rootChainKey []byte + sendChainKey []byte + sendChainN uint + recvChainKey []byte + recvChainN uint + pn uint + step uint + keysCount uint + ) + + err = stmt.QueryRow(id).Scan( + &dhr, + &dhsPublic, + &dhsPrivate, + &rootChainKey, + &sendChainKey, + &sendChainN, + &recvChainKey, + &recvChainN, + &pn, + &step, + &keysCount, + ) + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + state := dr.DefaultState(rootChainKey) + + state.PN = uint32(pn) + state.Step = step + state.KeysCount = keysCount + + state.DHs = crypto.DHPair{ + PrvKey: dhsPrivate, + PubKey: dhsPublic, + } + + state.DHr = dhr + + state.SendCh.CK = sendChainKey + state.SendCh.N = uint32(sendChainN) + + state.RecvCh.CK = recvChainKey + state.RecvCh.N = uint32(recvChainN) + + return &state, nil + default: + return nil, err + } +} + +type HRCache struct { + GroupID []byte + KeyID []byte + DeprecatedKeyID uint32 + Key []byte + Hash []byte + SeqNo uint32 +} + +// GetHashRatchetCache retrieves a hash ratchet key by group ID and seqNo. +// If cache data with given seqNo (e.g. 0) is not found, +// then the query will return the cache data with the latest seqNo +func (s *sqlitePersistence) GetHashRatchetCache(ratchet *HashRatchetKeyCompatibility, seqNo uint32) (*HRCache, error) { + tx, err := s.DB.BeginTx(context.Background(), &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer func() { + if err == nil { + err = tx.Commit() + return + } + // don't shadow original error + _ = tx.Rollback() + }() + + var key, keyID []byte + if !ratchet.IsOldFormat() { + keyID, err = ratchet.GetKeyID() + if err != nil { + return nil, err + } + } + + err = tx.QueryRow("SELECT key FROM hash_ratchet_encryption WHERE key_id = ? OR (deprecated_key_id = ? AND group_id = ?)", + keyID, + ratchet.DeprecatedKeyID(), + ratchet.GroupID, + ).Scan(&key) + if err == sql.ErrNoRows { + return nil, nil + } + if err != nil { + return nil, err + } + + args := make([]interface{}, 0) + args = append(args, ratchet.GroupID) + args = append(args, keyID) + args = append(args, ratchet.DeprecatedKeyID()) + var query string + if seqNo == 0 { + query = "SELECT seq_no, hash FROM hash_ratchet_encryption_cache WHERE group_id = ? AND (key_id = ? OR key_id = ?) ORDER BY seq_no DESC limit 1" + } else { + query = "SELECT seq_no, hash FROM hash_ratchet_encryption_cache WHERE group_id = ? AND (key_id = ? OR key_id = ?) AND seq_no == ? ORDER BY seq_no DESC limit 1" + args = append(args, seqNo) + } + + var hash []byte + var seqNoPtr *uint32 + + err = tx.QueryRow(query, args...).Scan(&seqNoPtr, &hash) //nolint: ineffassign,staticcheck + switch err { + case sql.ErrNoRows, nil: + var seqNoResult uint32 + if seqNoPtr == nil { + seqNoResult = 0 + } else { + seqNoResult = *seqNoPtr + } + + ratchet.Key = key + keyID, err := ratchet.GetKeyID() + + if err != nil { + return nil, err + } + + res := &HRCache{ + KeyID: keyID, + Key: key, + Hash: hash, + SeqNo: seqNoResult, + } + + return res, nil + default: + return nil, err + } +} + +type HashRatchetKeyCompatibility struct { + GroupID []byte + keyID []byte + Timestamp uint64 + Key []byte +} + +func (h *HashRatchetKeyCompatibility) DeprecatedKeyID() uint32 { + return uint32(h.Timestamp) +} + +func (h *HashRatchetKeyCompatibility) IsOldFormat() bool { + return len(h.keyID) == 0 && len(h.Key) == 0 +} + +func (h *HashRatchetKeyCompatibility) GetKeyID() ([]byte, error) { + if len(h.keyID) != 0 { + return h.keyID, nil + } + + if len(h.GroupID) == 0 || h.Timestamp == 0 || len(h.Key) == 0 { + return nil, errors.New("could not create key") + } + + return generateHashRatchetKeyID(h.GroupID, h.Timestamp, h.Key), nil +} + +func (h *HashRatchetKeyCompatibility) GenerateNext() (*HashRatchetKeyCompatibility, error) { + + ratchet := &HashRatchetKeyCompatibility{ + GroupID: h.GroupID, + } + + // Randomly generate a hash ratchet key + hrKey, err := crypto.GenerateKey() + if err != nil { + return nil, err + } + hrKeyBytes := crypto.FromECDSA(hrKey) + + if err != nil { + return nil, err + } + + currentTime := GetCurrentTime() + if h.Timestamp < currentTime { + ratchet.Timestamp = bumpKeyID(currentTime) + } else { + ratchet.Timestamp = h.Timestamp + 1 + } + + ratchet.Key = hrKeyBytes + + _, err = ratchet.GetKeyID() + if err != nil { + return nil, err + } + + return ratchet, nil +} + +// GetCurrentKeyForGroup retrieves a key ID for given group ID +// (with an assumption that key ids are shared in the group, and +// at any given time there is a single key used) +func (s *sqlitePersistence) GetCurrentKeyForGroup(groupID []byte) (*HashRatchetKeyCompatibility, error) { + ratchet := &HashRatchetKeyCompatibility{ + GroupID: groupID, + } + + stmt, err := s.DB.Prepare(`SELECT key_id, key_timestamp, key + FROM hash_ratchet_encryption + WHERE group_id = ? order by key_timestamp desc limit 1`) + if err != nil { + return nil, err + } + defer stmt.Close() + + var keyID, key []byte + var timestamp uint64 + err = stmt.QueryRow(groupID).Scan(&keyID, ×tamp, &key) + + switch err { + case sql.ErrNoRows: + return ratchet, nil + case nil: + ratchet.Key = key + ratchet.Timestamp = timestamp + _, err = ratchet.GetKeyID() + if err != nil { + return nil, err + } + return ratchet, nil + default: + return nil, err + } +} + +// GetKeysForGroup retrieves all key IDs for given group ID +func (s *sqlitePersistence) GetKeysForGroup(groupID []byte) ([]*HashRatchetKeyCompatibility, error) { + + var ratchets []*HashRatchetKeyCompatibility + stmt, err := s.DB.Prepare(`SELECT key_id, key_timestamp, key + FROM hash_ratchet_encryption + WHERE group_id = ? order by key_timestamp desc`) + if err != nil { + return nil, err + } + defer stmt.Close() + + rows, err := stmt.Query(groupID) + if err != nil { + return nil, err + } + + for rows.Next() { + ratchet := &HashRatchetKeyCompatibility{GroupID: groupID} + err := rows.Scan(&ratchet.keyID, &ratchet.Timestamp, &ratchet.Key) + if err != nil { + return nil, err + } + ratchets = append(ratchets, ratchet) + } + + return ratchets, nil +} + +// SaveHashRatchetKeyHash saves a hash ratchet key cache data +func (s *sqlitePersistence) SaveHashRatchetKeyHash( + ratchet *HashRatchetKeyCompatibility, + hash []byte, + seqNo uint32, +) error { + + stmt, err := s.DB.Prepare(`INSERT INTO hash_ratchet_encryption_cache(group_id, key_id, hash, seq_no) + VALUES(?, ?, ?, ?)`) + if err != nil { + return err + } + defer stmt.Close() + + keyID, err := ratchet.GetKeyID() + if err != nil { + return err + } + + _, err = stmt.Exec(ratchet.GroupID, keyID, hash, seqNo) + + return err +} + +// SaveHashRatchetKey saves a hash ratchet key +func (s *sqlitePersistence) SaveHashRatchetKey(ratchet *HashRatchetKeyCompatibility) error { + stmt, err := s.DB.Prepare(`INSERT INTO hash_ratchet_encryption(group_id, key_id, key_timestamp, deprecated_key_id, key) + VALUES(?,?,?,?,?)`) + if err != nil { + return err + } + defer stmt.Close() + + keyID, err := ratchet.GetKeyID() + if err != nil { + return err + } + + _, err = stmt.Exec(ratchet.GroupID, keyID, ratchet.Timestamp, ratchet.DeprecatedKeyID(), ratchet.Key) + + return err +} + +func (s *sqlitePersistence) GetHashRatchetKeyByID(keyID []byte) (*HashRatchetKeyCompatibility, error) { + ratchet := &HashRatchetKeyCompatibility{ + keyID: keyID, + } + + err := s.DB.QueryRow(` + SELECT group_id, key_timestamp, key + FROM hash_ratchet_encryption + WHERE key_id = ?`, keyID).Scan(&ratchet.GroupID, &ratchet.Timestamp, &ratchet.Key) + + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, err + } + + return ratchet, nil +} diff --git a/messaging/layers/encryption/persistence_keys_storage_test.go b/messaging/layers/encryption/persistence_keys_storage_test.go new file mode 100644 index 0000000000..7f6d681060 --- /dev/null +++ b/messaging/layers/encryption/persistence_keys_storage_test.go @@ -0,0 +1,201 @@ +package encryption + +import ( + "testing" + + dr "github.com/status-im/doubleratchet" + "github.com/stretchr/testify/suite" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/protocol/sqlite" + "github.com/status-im/status-go/t/helpers" +) + +var ( + pubKey1 = dr.Key{0xe3, 0xbe, 0xb9, 0x4e, 0x70, 0x17, 0x37, 0xc, 0x1, 0x8f, 0xa9, 0x7e, 0xef, 0x4, 0xfb, 0x23, 0xac, 0xea, 0x28, 0xf7, 0xa9, 0x56, 0xcc, 0x1d, 0x46, 0xf3, 0xb5, 0x1d, 0x7d, 0x7d, 0x5e, 0x2c} + pubKey2 = dr.Key{0xec, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40} + mk1 = dr.Key{0x00, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40} + mk2 = dr.Key{0x01, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40} + mk3 = dr.Key{0x02, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40} + mk4 = dr.Key{0x03, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40} + mk5 = dr.Key{0x04, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40} +) + +func TestSQLLitePersistenceKeysStorageTestSuite(t *testing.T) { + suite.Run(t, new(SQLLitePersistenceKeysStorageTestSuite)) +} + +type SQLLitePersistenceKeysStorageTestSuite struct { + suite.Suite + service dr.KeysStorage +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) SetupTest() { + db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(db) + s.Require().NoError(err) + + p := newSQLitePersistence(db) + s.service = p.KeysStorage() +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLiteGetMissing() { + // Act. + _, ok, err := s.service.Get(pubKey1, 0) + + // Assert. + s.NoError(err) + s.False(ok, "It returns false") +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLite_Put() { + // Act and assert. + err := s.service.Put([]byte("session-id"), pubKey1, 0, mk1, 1) + s.NoError(err) +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLite_DeleteOldMks() { + // Insert keys out-of-order + err := s.service.Put([]byte("session-id"), pubKey1, 0, mk1, 1) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey1, 1, mk2, 2) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey1, 2, mk3, 20) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey1, 3, mk4, 21) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey1, 4, mk5, 22) + s.NoError(err) + + err = s.service.DeleteOldMks([]byte("session-id"), 20) + s.NoError(err) + + _, ok, err := s.service.Get(pubKey1, 0) + s.NoError(err) + s.False(ok) + + _, ok, err = s.service.Get(pubKey1, 1) + s.NoError(err) + s.False(ok) + + _, ok, err = s.service.Get(pubKey1, 2) + s.NoError(err) + s.False(ok) + + _, ok, err = s.service.Get(pubKey1, 3) + s.NoError(err) + s.True(ok) + + _, ok, err = s.service.Get(pubKey1, 4) + s.NoError(err) + s.True(ok) +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLite_TruncateMks() { + // Insert keys out-of-order + err := s.service.Put([]byte("session-id"), pubKey2, 2, mk5, 5) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey2, 0, mk3, 3) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey1, 1, mk2, 2) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey2, 1, mk4, 4) + s.NoError(err) + err = s.service.Put([]byte("session-id"), pubKey1, 0, mk1, 1) + s.NoError(err) + + err = s.service.TruncateMks([]byte("session-id"), 2) + s.NoError(err) + + _, ok, err := s.service.Get(pubKey1, 0) + s.NoError(err) + s.False(ok) + + _, ok, err = s.service.Get(pubKey1, 1) + s.NoError(err) + s.False(ok) + + _, ok, err = s.service.Get(pubKey2, 0) + s.NoError(err) + s.False(ok) + + _, ok, err = s.service.Get(pubKey2, 1) + s.NoError(err) + s.True(ok) + + _, ok, err = s.service.Get(pubKey2, 2) + s.NoError(err) + s.True(ok) +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLite_Count() { + + // Act. + cnt, err := s.service.Count(pubKey1) + + // Assert. + s.NoError(err) + s.EqualValues(0, cnt, "It returns 0 when no keys are in the database") +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLite_Delete() { + // Arrange. + + // Act and assert. + err := s.service.DeleteMk(pubKey1, 0) + s.NoError(err) +} + +func (s *SQLLitePersistenceKeysStorageTestSuite) TestKeysStorageSqlLite_Flow() { + + // Act. + err := s.service.Put([]byte("session-id"), pubKey1, 0, mk1, 1) + s.NoError(err) + + k, ok, err := s.service.Get(pubKey1, 0) + + // Assert. + s.NoError(err) + s.True(ok, "It returns true") + s.Equal(mk1, k, "It returns the message key") + + // Act. + _, ok, err = s.service.Get(pubKey2, 0) + + // Assert. + s.NoError(err) + s.False(ok, "It returns false when querying non existing public key") + + // Act. + _, ok, err = s.service.Get(pubKey1, 1) + + // Assert. + s.NoError(err) + s.False(ok, "It returns false when querying the wrong msg number") + + // Act. + cnt, err := s.service.Count(pubKey1) + + // Assert. + s.NoError(err) + s.EqualValues(1, cnt) + + // Act and assert. + err = s.service.DeleteMk(pubKey1, 1) + s.NoError(err) + + // Act and assert. + err = s.service.DeleteMk(pubKey2, 0) + s.NoError(err) + + // Act. + err = s.service.DeleteMk(pubKey1, 0) + s.NoError(err) + + cnt, err = s.service.Count(pubKey1) + + // Assert. + s.NoError(err) + s.EqualValues(0, cnt) +} diff --git a/messaging/layers/encryption/persistence_test.go b/messaging/layers/encryption/persistence_test.go new file mode 100644 index 0000000000..108f15c2d2 --- /dev/null +++ b/messaging/layers/encryption/persistence_test.go @@ -0,0 +1,391 @@ +package encryption + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/t/helpers" + + "github.com/status-im/status-go/messaging/layers/encryption/multidevice" + "github.com/status-im/status-go/protocol/sqlite" +) + +func TestSQLLitePersistenceTestSuite(t *testing.T) { + suite.Run(t, new(SQLLitePersistenceTestSuite)) +} + +type SQLLitePersistenceTestSuite struct { + suite.Suite + service *sqlitePersistence +} + +func (s *SQLLitePersistenceTestSuite) SetupTest() { + db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(db) + s.Require().NoError(err) + + s.service = newSQLitePersistence(db) +} + +func (s *SQLLitePersistenceTestSuite) TestPrivateBundle() { + installationID := "1" + + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + actualKey, err := s.service.GetPrivateKeyBundle([]byte("non-existing")) + s.Require().NoError(err, "Error was not returned even though bundle is not there") + s.Nil(actualKey) + + anyPrivateBundle, err := s.service.GetAnyPrivateBundle([]byte("non-existing-id"), []*multidevice.Installation{{ID: installationID, Version: 1}}) + s.Require().NoError(err) + s.Nil(anyPrivateBundle) + + bundle, err := NewBundleContainer(key, installationID) + s.Require().NoError(err) + + err = s.service.AddPrivateBundle(bundle) + s.Require().NoError(err) + + bundleID := bundle.GetBundle().GetSignedPreKeys()[installationID].GetSignedPreKey() + + actualKey, err = s.service.GetPrivateKeyBundle(bundleID) + s.Require().NoError(err) + s.Equal(bundle.GetPrivateSignedPreKey(), actualKey, "It returns the same key") + + identity := crypto.CompressPubkey(&key.PublicKey) + anyPrivateBundle, err = s.service.GetAnyPrivateBundle(identity, []*multidevice.Installation{{ID: installationID, Version: 1}}) + s.Require().NoError(err) + s.NotNil(anyPrivateBundle) + s.Equal(bundle.GetBundle().GetSignedPreKeys()[installationID].SignedPreKey, anyPrivateBundle.GetBundle().GetSignedPreKeys()[installationID].SignedPreKey, "It returns the same bundle") +} + +func (s *SQLLitePersistenceTestSuite) TestPublicBundle() { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err, "Error was not returned even though bundle is not there") + s.Nil(actualBundle) + + bundleContainer, err := NewBundleContainer(key, "1") + s.Require().NoError(err) + + bundle := bundleContainer.GetBundle() + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err) + s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity") + s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the right prekeys") +} + +func (s *SQLLitePersistenceTestSuite) TestUpdatedBundle() { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err, "Error was not returned even though bundle is not there") + s.Nil(actualBundle) + + // Create & add initial bundle + bundleContainer, err := NewBundleContainer(key, "1") + s.Require().NoError(err) + + bundle := bundleContainer.GetBundle() + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Create & add a new bundle + bundleContainer, err = NewBundleContainer(key, "1") + s.Require().NoError(err) + bundle = bundleContainer.GetBundle() + // We set the version + bundle.GetSignedPreKeys()["1"].Version = 1 + + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err) + s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity") + s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the right prekeys") +} + +func (s *SQLLitePersistenceTestSuite) TestOutOfOrderBundles() { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err, "Error was not returned even though bundle is not there") + s.Nil(actualBundle) + + // Create & add initial bundle + bundleContainer, err := NewBundleContainer(key, "1") + s.Require().NoError(err) + + bundle1 := bundleContainer.GetBundle() + err = s.service.AddPublicBundle(bundle1) + s.Require().NoError(err) + + // Create & add a new bundle + bundleContainer, err = NewBundleContainer(key, "1") + s.Require().NoError(err) + + bundle2 := bundleContainer.GetBundle() + // We set the version + bundle2.GetSignedPreKeys()["1"].Version = 1 + + err = s.service.AddPublicBundle(bundle2) + s.Require().NoError(err) + + // Add again the initial bundle + err = s.service.AddPublicBundle(bundle1) + s.Require().NoError(err) + + actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err) + s.Equal(bundle2.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity") + s.Equal(bundle2.GetSignedPreKeys()["1"].GetVersion(), uint32(1)) + s.Equal(bundle2.GetSignedPreKeys()["1"].GetSignedPreKey(), actualBundle.GetSignedPreKeys()["1"].GetSignedPreKey(), "It sets the right prekeys") +} + +func (s *SQLLitePersistenceTestSuite) TestMultiplePublicBundle() { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err, "Error was not returned even though bundle is not there") + s.Nil(actualBundle) + + bundleContainer, err := NewBundleContainer(key, "1") + s.Require().NoError(err) + + bundle := bundleContainer.GetBundle() + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Adding it again does not throw an error + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Adding a different bundle + bundleContainer, err = NewBundleContainer(key, "1") + s.Require().NoError(err) + // We set the version + bundle = bundleContainer.GetBundle() + bundle.GetSignedPreKeys()["1"].Version = 1 + + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Returns the most recent bundle + actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err) + + s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the identity") + s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the signed pre keys") + +} + +func (s *SQLLitePersistenceTestSuite) TestMultiDevicePublicBundle() { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}}) + s.Require().NoError(err, "Error was not returned even though bundle is not there") + s.Nil(actualBundle) + + bundleContainer, err := NewBundleContainer(key, "1") + s.Require().NoError(err) + + bundle := bundleContainer.GetBundle() + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Adding it again does not throw an error + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Adding a different bundle from a different instlation id + bundleContainer, err = NewBundleContainer(key, "2") + s.Require().NoError(err) + + bundle = bundleContainer.GetBundle() + err = s.service.AddPublicBundle(bundle) + s.Require().NoError(err) + + // Returns the most recent bundle + actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, + []*multidevice.Installation{ + {ID: "1", Version: 1}, + {ID: "2", Version: 1}, + }) + s.Require().NoError(err) + + s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the identity") + s.NotNil(actualBundle.GetSignedPreKeys()["1"]) + s.NotNil(actualBundle.GetSignedPreKeys()["2"]) +} + +func (s *SQLLitePersistenceTestSuite) TestRatchetInfoPrivateBundle() { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + // Add a private bundle + bundle, err := NewBundleContainer(key, "2") + s.Require().NoError(err) + + err = s.service.AddPrivateBundle(bundle) + s.Require().NoError(err) + + err = s.service.AddRatchetInfo( + []byte("symmetric-key"), + []byte("their-public-key"), + bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), + []byte("ephemeral-public-key"), + "1", + ) + s.Require().NoError(err) + + ratchetInfo, err := s.service.GetRatchetInfo(bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), []byte("their-public-key"), "1") + + s.Require().NoError(err) + s.Require().NotNil(ratchetInfo) + s.NotNil(ratchetInfo.ID, "It adds an id") + s.Equal(ratchetInfo.PrivateKey, bundle.GetPrivateSignedPreKey(), "It returns the private key") + s.Equal(ratchetInfo.Sk, []byte("symmetric-key"), "It returns the symmetric key") + s.Equal(ratchetInfo.Identity, []byte("their-public-key"), "It returns the identity of the contact") + s.Equal(ratchetInfo.PublicKey, bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), "It returns the public key of the bundle") + s.Equal(bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), ratchetInfo.BundleID, "It returns the bundle id") + s.Equal([]byte("ephemeral-public-key"), ratchetInfo.EphemeralKey, "It returns the ratchet ephemeral key") + s.Equal("1", ratchetInfo.InstallationID, "It returns the right installation id") +} + +func (s *SQLLitePersistenceTestSuite) TestRatchetInfoPublicBundle() { + installationID := "1" + theirPublicKey := []byte("their-public-key") + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + // Add a private bundle + bundle, err := NewBundleContainer(key, installationID) + s.Require().NoError(err) + + err = s.service.AddPublicBundle(bundle.GetBundle()) + s.Require().NoError(err) + + signedPreKey := bundle.GetBundle().GetSignedPreKeys()[installationID].GetSignedPreKey() + + err = s.service.AddRatchetInfo( + []byte("symmetric-key"), + theirPublicKey, + signedPreKey, + []byte("public-ephemeral-key"), + installationID, + ) + s.Require().NoError(err) + + ratchetInfo, err := s.service.GetRatchetInfo(signedPreKey, theirPublicKey, installationID) + + s.Require().NoError(err) + s.Require().NotNil(ratchetInfo, "It returns the ratchet info") + + s.NotNil(ratchetInfo.ID, "It adds an id") + s.Nil(ratchetInfo.PrivateKey, "It does not return the private key") + s.Equal(ratchetInfo.Sk, []byte("symmetric-key"), "It returns the symmetric key") + s.Equal(ratchetInfo.Identity, theirPublicKey, "It returns the identity of the contact") + s.Equal(ratchetInfo.PublicKey, signedPreKey, "It returns the public key of the bundle") + s.Equal(installationID, ratchetInfo.InstallationID, "It returns the right installationID") + s.Nilf(ratchetInfo.PrivateKey, "It does not return the private key") + + ratchetInfo, err = s.service.GetAnyRatchetInfo(theirPublicKey, installationID) + s.Require().NoError(err) + s.Require().NotNil(ratchetInfo, "It returns the ratchet info") + s.NotNil(ratchetInfo.ID, "It adds an id") + s.Nil(ratchetInfo.PrivateKey, "It does not return the private key") + s.Equal(ratchetInfo.Sk, []byte("symmetric-key"), "It returns the symmetric key") + s.Equal(ratchetInfo.Identity, theirPublicKey, "It returns the identity of the contact") + s.Equal(ratchetInfo.PublicKey, signedPreKey, "It returns the public key of the bundle") + s.Equal(signedPreKey, ratchetInfo.BundleID, "It returns the bundle id") + s.Equal(installationID, ratchetInfo.InstallationID, "It saves the right installation ID") +} + +func (s *SQLLitePersistenceTestSuite) TestRatchetInfoNoBundle() { + err := s.service.AddRatchetInfo( + []byte("symmetric-key"), + []byte("their-public-key"), + []byte("non-existing-bundle"), + []byte("non-existing-ephemeral-key"), + "none", + ) + + s.Error(err, "It returns an error") + + _, err = s.service.GetRatchetInfo([]byte("non-existing-bundle"), []byte("their-public-key"), "none") + s.Require().NoError(err) + + ratchetInfo, err := s.service.GetAnyRatchetInfo([]byte("their-public-key"), "4") + s.Require().NoError(err) + s.Nil(ratchetInfo, "It returns nil when no bundle is there") +} + +// TODO: Add test for MarkBundleExpired + +func (s *SQLLitePersistenceTestSuite) TestGetHashRatchetKeyByID() { + key := &HashRatchetKeyCompatibility{ + GroupID: []byte{1, 2, 3}, + keyID: []byte{4, 5, 6}, + Timestamp: 1, + Key: []byte{7, 8, 9}, + } + err := s.service.SaveHashRatchetKey(key) + s.Require().NoError(err) + + retrievedKey, err := s.service.GetHashRatchetKeyByID(key.keyID) + s.Require().NoError(err) + s.Require().True(reflect.DeepEqual(key.GroupID, retrievedKey.GroupID)) + s.Require().True(reflect.DeepEqual(key.keyID, retrievedKey.keyID)) + s.Require().True(reflect.DeepEqual(key.Key, retrievedKey.Key)) + s.Require().Equal(key.Timestamp, retrievedKey.Timestamp) + + cachedKey, err := s.service.GetHashRatchetCache(retrievedKey, 0) + s.Require().NoError(err) + s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID)) + s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key)) + s.Require().EqualValues(0, cachedKey.SeqNo) + + var newSeqNo uint32 = 1 + newHash := []byte{10, 11, 12} + err = s.service.SaveHashRatchetKeyHash(key, newHash, newSeqNo) + s.Require().NoError(err) + + cachedKey, err = s.service.GetHashRatchetCache(retrievedKey, 0) + s.Require().NoError(err) + s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID)) + s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key)) + s.Require().EqualValues(1, cachedKey.SeqNo) + + newSeqNo = 4 + newHash = []byte{10, 11, 13} + err = s.service.SaveHashRatchetKeyHash(key, newHash, newSeqNo) + s.Require().NoError(err) + + cachedKey, err = s.service.GetHashRatchetCache(retrievedKey, 0) + s.Require().NoError(err) + s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID)) + s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key)) + s.Require().EqualValues(4, cachedKey.SeqNo) + + cachedKey, err = s.service.GetHashRatchetCache(retrievedKey, 1) + s.Require().NoError(err) + s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID)) + s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key)) + s.Require().EqualValues(1, cachedKey.SeqNo) +} diff --git a/messaging/layers/encryption/protocol.go b/messaging/layers/encryption/protocol.go new file mode 100644 index 0000000000..6f8ee8b6d2 --- /dev/null +++ b/messaging/layers/encryption/protocol.go @@ -0,0 +1,919 @@ +package encryption + +import ( + "bytes" + "crypto/ecdsa" + "crypto/rand" + "database/sql" + "fmt" + + "go.uber.org/zap" + + "github.com/golang/protobuf/proto" + "github.com/pkg/errors" + + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" + + "github.com/status-im/status-go/messaging/layers/encryption/multidevice" + "github.com/status-im/status-go/messaging/layers/encryption/publisher" + "github.com/status-im/status-go/messaging/layers/encryption/sharedsecret" +) + +//go:generate protoc --go_out=. ./protocol_message.proto + +const ( + protocolVersion = 1 + sharedSecretNegotiationVersion = 1 + partitionedTopicMinVersion = 1 + defaultMinVersion = 0 + maxKeysChannelSize = 10000 +) + +type PartitionTopicMode int + +const ( + PartitionTopicNoSupport PartitionTopicMode = iota + PartitionTopicV1 +) + +type ProtocolMessageSpec struct { + Message *ProtocolMessage + // Installations is the targeted devices + Installations []*multidevice.Installation + // SharedSecret is a shared secret established among the installations + SharedSecret *sharedsecret.Secret + // AgreedSecret indicates whether the shared secret has been agreed + AgreedSecret bool + // Public means that the spec contains a public wrapped message + Public bool +} + +func (p *ProtocolMessageSpec) MinVersion() uint32 { + if len(p.Installations) == 0 { + return defaultMinVersion + } + + version := p.Installations[0].Version + + for _, installation := range p.Installations[1:] { + if installation.Version < version { + version = installation.Version + } + } + return version +} + +func (p *ProtocolMessageSpec) PartitionedTopicMode() PartitionTopicMode { + if p.MinVersion() >= partitionedTopicMinVersion { + return PartitionTopicV1 + } + return PartitionTopicNoSupport +} + +type Protocol struct { + encryptor *encryptor + secret *sharedsecret.SharedSecret + multidevice *multidevice.Multidevice + publisher *publisher.Publisher + subscriptions *Subscriptions + + logger *zap.Logger +} + +var ( + // ErrNoPayload means that there was no payload found in the received protocol message. + ErrNoPayload = errors.New("no payload") + ErrNoRatchetKey = errors.New("no ratchet key for given keyID") +) + +// New creates a new ProtocolService instance +func New( + db *sql.DB, + installationID string, + logger *zap.Logger, +) *Protocol { + return NewWithEncryptorConfig( + db, + installationID, + defaultEncryptorConfig(installationID, logger), + logger, + ) +} + +// DB and migrations are shared between encryption package +// and its sub-packages. +func NewWithEncryptorConfig( + db *sql.DB, + installationID string, + encryptorConfig encryptorConfig, + logger *zap.Logger, +) *Protocol { + return &Protocol{ + encryptor: newEncryptor(db, encryptorConfig), + secret: sharedsecret.New(db, logger), + multidevice: multidevice.New(db, &multidevice.Config{ + MaxInstallations: 3, + ProtocolVersion: protocolVersion, + InstallationID: installationID, + }), + publisher: publisher.New(logger), + logger: logger.With(zap.Namespace("Protocol")), + } +} + +type Subscriptions struct { + SharedSecrets []*sharedsecret.Secret + SendContactCode <-chan struct{} + NewHashRatchetKeys chan []*HashRatchetInfo + Quit chan struct{} +} + +func (p *Protocol) Start(myIdentity *ecdsa.PrivateKey) (*Subscriptions, error) { + // Propagate currently cached shared secrets. + secrets, err := p.secret.All() + if err != nil { + return nil, errors.Wrap(err, "failed to get all secrets") + } + p.subscriptions = &Subscriptions{ + SharedSecrets: secrets, + SendContactCode: p.publisher.Start(), + NewHashRatchetKeys: make(chan []*HashRatchetInfo, maxKeysChannelSize), + Quit: make(chan struct{}), + } + return p.subscriptions, nil +} + +func (p *Protocol) Stop() error { + p.publisher.Stop() + if p.subscriptions != nil { + close(p.subscriptions.Quit) + } + return nil +} + +func (p *Protocol) Subscriptions() *Subscriptions { + return p.subscriptions +} + +func (p *Protocol) addBundle(myIdentityKey *ecdsa.PrivateKey, msg *ProtocolMessage) error { + // Get a bundle + installations, err := p.multidevice.GetOurActiveInstallations(&myIdentityKey.PublicKey) + if err != nil { + return err + } + + bundle, err := p.encryptor.CreateBundle(myIdentityKey, installations) + if err != nil { + return err + } + + msg.Bundles = []*Bundle{bundle} + + return nil +} + +// BuildPublicMessage marshals a public chat message given the user identity private key and a payload +func (p *Protocol) BuildPublicMessage(myIdentityKey *ecdsa.PrivateKey, payload []byte) (*ProtocolMessageSpec, error) { + // Build message not encrypted + message := &ProtocolMessage{ + InstallationId: p.encryptor.config.InstallationID, + PublicMessage: payload, + } + + err := p.addBundle(myIdentityKey, message) + if err != nil { + return nil, err + } + + return &ProtocolMessageSpec{Message: message, Public: true}, nil +} + +// BuildEncryptedMessage returns a 1:1 chat message and optionally a negotiated topic given the user identity private key, the recipient's public key, and a payload +func (p *Protocol) BuildEncryptedMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, payload []byte) (*ProtocolMessageSpec, error) { + + // Get recipients installations. + activeInstallations, err := p.multidevice.GetActiveInstallations(publicKey) + if err != nil { + return nil, err + } + + // Encrypt payload + encryptedMessagesByInstalls, installations, err := p.encryptor.EncryptPayload(publicKey, myIdentityKey, activeInstallations, payload) + if err != nil { + return nil, err + } + + // Build message + message := &ProtocolMessage{ + InstallationId: p.encryptor.config.InstallationID, + EncryptedMessage: encryptedMessagesByInstalls, + } + + err = p.addBundle(myIdentityKey, message) + if err != nil { + return nil, err + } + + // Check who we are sending the message to, and see if we have a shared secret + // across devices + var installationIDs []string + for installationID := range message.GetEncryptedMessage() { + if installationID != noInstallationID { + installationIDs = append(installationIDs, installationID) + } + } + + sharedSecret, agreed, err := p.secret.Agreed(myIdentityKey, p.encryptor.config.InstallationID, publicKey, installationIDs) + if err != nil { + return nil, err + } + + spec := &ProtocolMessageSpec{ + SharedSecret: sharedSecret, + AgreedSecret: agreed, + Message: message, + Installations: installations, + } + return spec, nil +} + +func (p *Protocol) GenerateHashRatchetKey(groupID []byte) (*HashRatchetKeyCompatibility, error) { + return p.encryptor.GenerateHashRatchetKey(groupID) +} + +// Deprecated: This function is deprecated as it does not marshal groupID. Kept for backward compatibility. +func (p *Protocol) GetAllHRKeysMarshaledV1(groupID []byte) ([]byte, error) { + keys, err := p.GetAllHRKeys(groupID) + if err != nil { + return nil, err + } + if keys == nil { + return nil, nil + } + + return proto.Marshal(keys) +} + +func (p *Protocol) GetAllHRKeysMarshaledV2(groupID []byte) ([]byte, error) { + keys, err := p.GetAllHRKeys(groupID) + if err != nil { + return nil, err + } + if keys == nil { + return nil, nil + } + + header := &HRHeader{ + SeqNo: 0, + GroupId: groupID, + Keys: keys, + } + return proto.Marshal(header) +} + +func (p *Protocol) GetAllHRKeys(groupID []byte) (*HRKeys, error) { + ratchets, err := p.encryptor.persistence.GetKeysForGroup(groupID) + if err != nil { + return nil, err + } + if len(ratchets) == 0 { + return nil, nil + } + return p.GetHRKeys(ratchets), nil +} + +// GetKeyIDsForGroup returns a slice of key IDs belonging to a given group ID +func (p *Protocol) GetKeysForGroup(groupID []byte) ([]*HashRatchetKeyCompatibility, error) { + return p.encryptor.persistence.GetKeysForGroup(groupID) +} + +func (p *Protocol) GetHRKeys(ratchets []*HashRatchetKeyCompatibility) *HRKeys { + keys := &HRKeys{} + for _, ratchet := range ratchets { + key := &HRKey{ + DeprecatedKeyId: ratchet.DeprecatedKeyID(), + Key: ratchet.Key, + Timestamp: ratchet.Timestamp, + } + keys.Keys = append(keys.Keys, key) + } + + return keys +} + +// BuildHashRatchetRekeyGroup builds a public message +// with the new key +func (p *Protocol) BuildHashRatchetReKeyGroupMessage(myIdentityKey *ecdsa.PrivateKey, recipients []*ecdsa.PublicKey, groupID []byte, payload []byte, ratchet *HashRatchetKeyCompatibility) (*ProtocolMessageSpec, error) { + + var err error + if ratchet == nil { + ratchet, err = p.GenerateHashRatchetKey(groupID) + if err != nil { + return nil, err + } + } + + message, err := buildGroupRekeyMessage(myIdentityKey, groupID, ratchet.Timestamp, ratchet.Key, recipients) + if err != nil { + return nil, err + } + + keys := &HRKeys{ + RekeyGroup: message, + } + spec := &ProtocolMessageSpec{ + Public: true, + Message: &ProtocolMessage{ + InstallationId: p.encryptor.config.InstallationID, + EncryptedMessage: map[string]*EncryptedMessageProtocol{noInstallationID: &EncryptedMessageProtocol{ + HRHeader: &HRHeader{ + SeqNo: 0, + GroupId: groupID, + Keys: keys, + }, + Payload: payload, + }, + }, + }, + } + + return spec, nil +} + +// BuildHashRatchetKeyExchangeMessage builds a 1:1 message +// containing newly generated hash ratchet key +func (p *Protocol) BuildHashRatchetKeyExchangeMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, groupID []byte, ratchets []*HashRatchetKeyCompatibility) (*ProtocolMessageSpec, error) { + + keys := p.GetHRKeys(ratchets) + + encodedKeys, err := proto.Marshal(keys) + if err != nil { + return nil, err + } + + response, err := p.BuildEncryptedMessage(myIdentityKey, publicKey, encodedKeys) + if err != nil { + return nil, err + } + + // Loop through installations and assign HRHeader + // SeqNo=0 has a special meaning for HandleMessage + // and signifies a message with hash ratchet key payload + for _, v := range response.Message.EncryptedMessage { + v.HRHeader = &HRHeader{ + SeqNo: 0, + GroupId: groupID, + Keys: keys, + } + + } + + return response, err +} + +func (p *Protocol) BuildHashRatchetKeyExchangeMessageWithPayload(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, groupID []byte, ratchets []*HashRatchetKeyCompatibility, payload []byte) (*ProtocolMessageSpec, error) { + + keys := p.GetHRKeys(ratchets) + + response, err := p.BuildEncryptedMessage(myIdentityKey, publicKey, payload) + if err != nil { + return nil, err + } + + // Loop through installations and assign HRHeader + // SeqNo=0 has a special meaning for HandleMessage + // and signifies a message with hash ratchet key payload + for _, v := range response.Message.EncryptedMessage { + v.HRHeader = &HRHeader{ + SeqNo: 0, + GroupId: groupID, + Keys: keys, + } + + } + + return response, err +} + +func (p *Protocol) GetCurrentKeyForGroup(groupID []byte) (*HashRatchetKeyCompatibility, error) { + return p.encryptor.persistence.GetCurrentKeyForGroup(groupID) + +} + +// BuildHashRatchetMessage returns a hash ratchet chat message +func (p *Protocol) BuildHashRatchetMessage(groupID []byte, payload []byte) (*ProtocolMessageSpec, error) { + + ratchet, err := p.encryptor.persistence.GetCurrentKeyForGroup(groupID) + if err != nil { + return nil, err + } + + // Encrypt payload + encryptedMessagesByInstalls, err := p.encryptor.EncryptHashRatchetPayload(ratchet, payload) + if err != nil { + return nil, err + } + + // Build message + message := &ProtocolMessage{ + InstallationId: p.encryptor.config.InstallationID, + EncryptedMessage: encryptedMessagesByInstalls, + } + + spec := &ProtocolMessageSpec{ + Message: message, + } + return spec, nil +} + +func (p *Protocol) EncryptCommunityGrants(privateKey *ecdsa.PrivateKey, recipientGrants map[*ecdsa.PublicKey][]byte) (map[uint32][]byte, error) { + grants := make(map[uint32][]byte) + + for recipientKey, grant := range recipientGrants { + sharedKey, err := crypto.GenerateSharedKey(privateKey, recipientKey) + if err != nil { + return nil, err + } + + encryptedGrant, err := encrypt(grant, sharedKey, rand.Reader) + if err != nil { + return nil, err + } + + kBytes := publicKeyMostRelevantBytes(recipientKey) + grants[kBytes] = encryptedGrant + } + + return grants, nil +} + +func (p *Protocol) DecryptCommunityGrant(myIdentityKey *ecdsa.PrivateKey, senderKey *ecdsa.PublicKey, grants map[uint32][]byte) ([]byte, error) { + kBytes := publicKeyMostRelevantBytes(&myIdentityKey.PublicKey) + + ecryptedGrant, ok := grants[kBytes] + if !ok { + return nil, errors.New("can't find related grant in the map") + } + + sharedKey, err := crypto.GenerateSharedKey(myIdentityKey, senderKey) + if err != nil { + return nil, err + } + + return decrypt(ecryptedGrant, sharedKey) +} + +func (p *Protocol) GetKeyExMessageSpecs(groupID []byte, identity *ecdsa.PrivateKey, recipients []*ecdsa.PublicKey, forceRekey bool) ([]*ProtocolMessageSpec, error) { + var ratchets []*HashRatchetKeyCompatibility + var err error + if !forceRekey { + ratchets, err = p.encryptor.persistence.GetKeysForGroup(groupID) + if err != nil { + return nil, err + } + } + if len(ratchets) == 0 || forceRekey { + ratchet, err := p.GenerateHashRatchetKey(groupID) + if err != nil { + return nil, err + } + ratchets = []*HashRatchetKeyCompatibility{ratchet} + } + specs := make([]*ProtocolMessageSpec, len(recipients)) + for i, recipient := range recipients { + keyExMsg, err := p.BuildHashRatchetKeyExchangeMessage(identity, recipient, groupID, ratchets) + if err != nil { + return nil, err + } + specs[i] = keyExMsg + + } + + return specs, nil +} + +// BuildDHMessage builds a message with DH encryption so that it can be decrypted by any other device. +func (p *Protocol) BuildDHMessage(myIdentityKey *ecdsa.PrivateKey, destination *ecdsa.PublicKey, payload []byte) (*ProtocolMessageSpec, error) { + // Encrypt payload + encryptionResponse, err := p.encryptor.EncryptPayloadWithDH(destination, payload) + if err != nil { + return nil, err + } + + // Build message + message := &ProtocolMessage{ + InstallationId: p.encryptor.config.InstallationID, + EncryptedMessage: encryptionResponse, + } + + err = p.addBundle(myIdentityKey, message) + if err != nil { + return nil, err + } + + return &ProtocolMessageSpec{Message: message}, nil +} + +// ProcessPublicBundle processes a received X3DH bundle. +func (p *Protocol) ProcessPublicBundle(myIdentityKey *ecdsa.PrivateKey, bundle *Bundle) ([]*multidevice.Installation, error) { + logger := p.logger.With(zap.String("site", "ProcessPublicBundle")) + + if err := p.encryptor.ProcessPublicBundle(myIdentityKey, bundle); err != nil { + return nil, err + } + + installations, enabled, err := p.recoverInstallationsFromBundle(myIdentityKey, bundle) + if err != nil { + return nil, err + } + + // TODO(adam): why do we add installations using identity obtained from GetIdentity() + // instead of the output of crypto.CompressPubkey()? I tried the second option + // and the unit tests TestTopic and TestMaxDevices fail. + identityFromBundle := bundle.GetIdentity() + theirIdentity, err := ExtractIdentity(bundle) + if err != nil { + logger.Panic("unrecoverable error extracting identity", zap.Error(err)) + } + compressedIdentity := crypto.CompressPubkey(theirIdentity) + if !bytes.Equal(identityFromBundle, compressedIdentity) { + logger.Panic("identity from bundle and compressed are not equal") + } + + return p.multidevice.AddInstallations(bundle.GetIdentity(), bundle.GetTimestamp(), installations, enabled) +} + +func (p *Protocol) AddInstallation(identity []byte, timestamp int64, installation *multidevice.Installation, enabled bool) ([]*multidevice.Installation, error) { + return p.multidevice.AddInstallations(identity, timestamp, []*multidevice.Installation{installation}, enabled) +} + +func (p *Protocol) AddInstallations(identity []byte, timestamp int64, installations []*multidevice.Installation, defaultEnabled bool) ([]*multidevice.Installation, error) { + return p.multidevice.AddInstallations(identity, timestamp, installations, defaultEnabled) +} + +func (p *Protocol) GetMultiDevice() *multidevice.Multidevice { + return p.multidevice +} + +// recoverInstallationsFromBundle extracts installations from the bundle. +// It returns extracted installations and true if the installations +// are ours, i.e. the bundle was created by our identity key. +func (p *Protocol) recoverInstallationsFromBundle(myIdentityKey *ecdsa.PrivateKey, bundle *Bundle) ([]*multidevice.Installation, bool, error) { + var installations []*multidevice.Installation + + theirIdentity, err := ExtractIdentity(bundle) + if err != nil { + return nil, false, err + } + + myIdentityStr := fmt.Sprintf("0x%x", crypto.FromECDSAPub(&myIdentityKey.PublicKey)) + theirIdentityStr := fmt.Sprintf("0x%x", crypto.FromECDSAPub(theirIdentity)) + // Any device from other peers will be considered enabled, ours needs to + // be explicitly enabled. + enabled := theirIdentityStr != myIdentityStr + signedPreKeys := bundle.GetSignedPreKeys() + + for installationID, signedPreKey := range signedPreKeys { + if installationID != p.multidevice.InstallationID() { + installations = append(installations, &multidevice.Installation{ + Identity: theirIdentityStr, + ID: installationID, + Version: signedPreKey.GetProtocolVersion(), + }) + } + } + + return installations, enabled, nil +} + +// GetBundle retrieves or creates a X3DH bundle, given a private identity key. +func (p *Protocol) GetBundle(myIdentityKey *ecdsa.PrivateKey) (*Bundle, error) { + installations, err := p.multidevice.GetOurActiveInstallations(&myIdentityKey.PublicKey) + if err != nil { + return nil, err + } + + return p.encryptor.CreateBundle(myIdentityKey, installations) +} + +// EnableInstallation enables an installation for multi-device sync. +func (p *Protocol) EnableInstallation(myIdentityKey *ecdsa.PublicKey, installationID string) error { + return p.multidevice.EnableInstallation(myIdentityKey, installationID) +} + +// DisableInstallation disables an installation for multi-device sync. +func (p *Protocol) DisableInstallation(myIdentityKey *ecdsa.PublicKey, installationID string) error { + return p.multidevice.DisableInstallation(myIdentityKey, installationID) +} + +// GetOurInstallations returns all the installations available given an identity +func (p *Protocol) GetOurInstallations(myIdentityKey *ecdsa.PublicKey) ([]*multidevice.Installation, error) { + return p.multidevice.GetOurInstallations(myIdentityKey) +} + +// GetOurActiveInstallations returns all the active installations available given an identity +func (p *Protocol) GetOurActiveInstallations(myIdentityKey *ecdsa.PublicKey) ([]*multidevice.Installation, error) { + return p.multidevice.GetOurActiveInstallations(myIdentityKey) +} + +// SetInstallationMetadata sets the metadata for our own installation +func (p *Protocol) SetInstallationMetadata(myIdentityKey *ecdsa.PublicKey, installationID string, data *multidevice.InstallationMetadata) error { + return p.multidevice.SetInstallationMetadata(myIdentityKey, installationID, data) +} + +// SetInstallationName sets the metadata for our own installation +func (p *Protocol) SetInstallationName(myIdentityKey *ecdsa.PublicKey, installationID string, name string) error { + return p.multidevice.SetInstallationName(myIdentityKey, installationID, name) +} + +// GetPublicBundle retrieves a public bundle given an identity +func (p *Protocol) GetPublicBundle(theirIdentityKey *ecdsa.PublicKey) (*Bundle, error) { + installations, err := p.multidevice.GetActiveInstallations(theirIdentityKey) + if err != nil { + return nil, err + } + return p.encryptor.GetPublicBundle(theirIdentityKey, installations) +} + +// ConfirmMessageProcessed confirms and deletes message keys for the given messages +func (p *Protocol) ConfirmMessageProcessed(messageID []byte) error { + logger := p.logger.With(zap.String("site", "ConfirmMessageProcessed")) + logger.Debug("confirming message", zap.String("messageID", types.EncodeHex(messageID))) + return p.encryptor.ConfirmMessageProcessed(messageID) +} + +type HashRatchetInfo struct { + GroupID []byte + KeyID []byte +} +type DecryptMessageResponse struct { + DecryptedMessage []byte + Installations []*multidevice.Installation + SharedSecrets []*sharedsecret.Secret + HashRatchetInfo []*HashRatchetInfo +} + +func (p *Protocol) HandleHashRatchetKeysPayload(groupID, encodedKeys []byte, myIdentityKey *ecdsa.PrivateKey, theirIdentityKey *ecdsa.PublicKey) ([]*HashRatchetInfo, error) { + keys := &HRKeys{} + err := proto.Unmarshal(encodedKeys, keys) + if err != nil { + return nil, err + } + return p.HandleHashRatchetKeys(groupID, keys, myIdentityKey, theirIdentityKey) +} + +func (p *Protocol) HandleHashRatchetHeadersPayload(encodedHeaders [][]byte) error { + for _, encodedHeader := range encodedHeaders { + header := &HRHeader{} + err := proto.Unmarshal(encodedHeader, header) + if err != nil { + return err + } + _, err = p.HandleHashRatchetKeys(header.GroupId, header.Keys, nil, nil) + if err != nil { + return err + } + } + return nil +} + +func (p *Protocol) HandleHashRatchetKeys(groupID []byte, keys *HRKeys, myIdentityKey *ecdsa.PrivateKey, theirIdentityKey *ecdsa.PublicKey) ([]*HashRatchetInfo, error) { + if keys == nil { + return nil, nil + } + + var info []*HashRatchetInfo + + for _, key := range keys.Keys { + ratchet := &HashRatchetKeyCompatibility{ + GroupID: groupID, + Timestamp: key.Timestamp, + Key: key.Key, + } + + // If there's no timestamp, is coming from an older client + if key.Timestamp == 0 { + ratchet.Timestamp = uint64(key.DeprecatedKeyId) + } + keyID, err := ratchet.GetKeyID() + if err != nil { + return nil, err + } + p.logger.Debug("retrieved keys", zap.String("keyID", types.Bytes2Hex(keyID))) + + // Payload contains hash ratchet key + err = p.encryptor.persistence.SaveHashRatchetKey(ratchet) + if err != nil { + return nil, err + } + info = append(info, &HashRatchetInfo{GroupID: groupID, KeyID: keyID}) + } + + if keys.RekeyGroup != nil { + if keys.RekeyGroup.Timestamp == 0 { + return nil, errors.New("timestamp can't be nil") + } + + encryptionKey, err := decryptGroupRekeyMessage(myIdentityKey, theirIdentityKey, keys.RekeyGroup) + if err != nil { + return nil, err + } + + if len(encryptionKey) != 0 { + + ratchet := &HashRatchetKeyCompatibility{ + GroupID: groupID, + Timestamp: keys.RekeyGroup.Timestamp, + Key: encryptionKey, + } + + keyID, err := ratchet.GetKeyID() + if err != nil { + return nil, err + } + p.logger.Debug("retrieved group keys", zap.String("keyID", types.Bytes2Hex(keyID))) + // Payload contains hash ratchet key + err = p.encryptor.persistence.SaveHashRatchetKey(ratchet) + if err != nil { + return nil, err + } + + info = append(info, &HashRatchetInfo{GroupID: groupID, KeyID: keyID}) + + } + } + + if p.subscriptions != nil { + p.subscriptions.NewHashRatchetKeys <- info + } + + return info, nil +} + +// HandleMessage unmarshals a message and processes it, decrypting it if it is a 1:1 message. +func (p *Protocol) HandleMessage( + myIdentityKey *ecdsa.PrivateKey, + theirPublicKey *ecdsa.PublicKey, + protocolMessage *ProtocolMessage, + messageID []byte, +) (*DecryptMessageResponse, error) { + logger := p.logger.With(zap.String("site", "HandleMessage")) + response := &DecryptMessageResponse{} + + logger.Debug("received a protocol message", + zap.String("sender-public-key", + types.EncodeHex(crypto.FromECDSAPub(theirPublicKey))), + zap.String("my-installation-id", p.encryptor.config.InstallationID), + zap.String("messageID", types.EncodeHex(messageID))) + + if p.encryptor == nil { + return nil, errors.New("encryption service not initialized") + } + + // Process bundles + for _, bundle := range protocolMessage.GetBundles() { + // Should we stop processing if the bundle cannot be verified? + newInstallations, err := p.ProcessPublicBundle(myIdentityKey, bundle) + if err != nil { + return nil, err + } + response.Installations = newInstallations + } + + // Check if it's a public message + if publicMessage := protocolMessage.GetPublicMessage(); publicMessage != nil { + // Nothing to do, as already in cleartext + response.DecryptedMessage = publicMessage + return response, nil + } + + // Decrypt message + if encryptedMessage := protocolMessage.GetEncryptedMessage(); encryptedMessage != nil { + message, err := p.encryptor.DecryptPayload( + myIdentityKey, + theirPublicKey, + protocolMessage.GetInstallationId(), + encryptedMessage, + messageID, + ) + + if err == ErrHashRatchetGroupIDNotFound { + msg := p.encryptor.GetMessage(encryptedMessage) + + if msg != nil { + if header := msg.GetHRHeader(); header != nil { + response.HashRatchetInfo = append(response.HashRatchetInfo, &HashRatchetInfo{GroupID: header.GroupId, KeyID: header.KeyId}) + } + } + return response, err + } + + if err != nil { + return nil, err + } + + dmProtocol := encryptedMessage[p.encryptor.config.InstallationID] + if dmProtocol == nil { + dmProtocol = encryptedMessage[noInstallationID] + } + if dmProtocol != nil { + hrHeader := dmProtocol.HRHeader + if hrHeader != nil && hrHeader.SeqNo == 0 { + var hashRatchetKeys []*HashRatchetInfo + if hrHeader.Keys != nil { + hashRatchetKeys, err = p.HandleHashRatchetKeys(hrHeader.GroupId, hrHeader.Keys, myIdentityKey, theirPublicKey) + if err != nil { + return nil, err + } + + } else { + // For backward compatibility + hashRatchetKeys, err = p.HandleHashRatchetKeysPayload(hrHeader.GroupId, message, myIdentityKey, theirPublicKey) + if err != nil { + return nil, err + } + } + response.HashRatchetInfo = hashRatchetKeys + } + } + + bundles := protocolMessage.GetBundles() + version := getProtocolVersion(bundles, protocolMessage.GetInstallationId()) + if version >= sharedSecretNegotiationVersion { + sharedSecret, err := p.secret.Generate(myIdentityKey, theirPublicKey, protocolMessage.GetInstallationId()) + if err != nil { + return nil, err + } + + response.SharedSecrets = []*sharedsecret.Secret{sharedSecret} + } + response.DecryptedMessage = message + return response, nil + } + + // Return error + return nil, ErrNoPayload +} + +func (p *Protocol) ShouldAdvertiseBundle(publicKey *ecdsa.PublicKey, time int64) (bool, error) { + return p.publisher.ShouldAdvertiseBundle(publicKey, time) +} + +func (p *Protocol) ConfirmBundleAdvertisement(publicKey *ecdsa.PublicKey, time int64) { + p.publisher.SetLastAck(publicKey, time) +} + +func (p *Protocol) BuildBundleAdvertiseMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey) (*ProtocolMessageSpec, error) { + return p.BuildDHMessage(myIdentityKey, publicKey, nil) +} + +func getProtocolVersion(bundles []*Bundle, installationID string) uint32 { + if installationID == "" { + return defaultMinVersion + } + + for _, bundle := range bundles { + if bundle != nil { + signedPreKeys := bundle.GetSignedPreKeys() + if signedPreKeys == nil { + continue + } + + signedPreKey := signedPreKeys[installationID] + if signedPreKey == nil { + return defaultMinVersion + } + + return signedPreKey.GetProtocolVersion() + } + } + + return defaultMinVersion +} + +func (p *Protocol) EncryptWithHashRatchet(groupID []byte, payload []byte) ([]byte, *HashRatchetKeyCompatibility, uint32, error) { + ratchet, err := p.encryptor.persistence.GetCurrentKeyForGroup(groupID) + if err != nil { + return nil, nil, 0, err + } + + encryptedPayload, newSeqNo, err := p.encryptor.EncryptWithHR(ratchet, payload) + if err != nil { + return nil, nil, 0, err + } + + return encryptedPayload, ratchet, newSeqNo, nil +} + +func (p *Protocol) DecryptWithHashRatchet(keyID []byte, seqNo uint32, payload []byte) ([]byte, error) { + ratchet, err := p.encryptor.persistence.GetHashRatchetKeyByID(keyID) + if err != nil { + return nil, err + } + if ratchet == nil { + return nil, ErrNoRatchetKey + } + + return p.encryptor.DecryptWithHR(ratchet, seqNo, payload) +} diff --git a/messaging/layers/encryption/protocol_message.proto b/messaging/layers/encryption/protocol_message.proto new file mode 100644 index 0000000000..893f898c4e --- /dev/null +++ b/messaging/layers/encryption/protocol_message.proto @@ -0,0 +1,111 @@ +syntax = "proto3"; + +option go_package = "./;encryption"; +package encryption; + +message SignedPreKey { + bytes signed_pre_key = 1; + uint32 version = 2; + uint32 protocol_version = 3; +} + +// X3DH prekey bundle +message Bundle { + // Identity key + bytes identity = 1; + // Installation id + map signed_pre_keys = 2; + // Prekey signature + bytes signature = 4; + + // When the bundle was created locally + int64 timestamp = 5; +} + +message BundleContainer { + reserved 3; + // X3DH prekey bundle + Bundle bundle = 1; + // Private signed prekey + bytes private_signed_pre_key = 2; +} + +message DRHeader { + // Current ratchet public key + bytes key = 1; + // Number of the message in the sending chain + uint32 n = 2; + // Length of the previous sending chain + uint32 pn = 3; + // Bundle ID + bytes id = 4; +} + +message DHHeader { + // Compressed ephemeral public key + bytes key = 1; +} + +message X3DHHeader { + reserved 3; + // Ephemeral key used + bytes key = 1; + // Used bundle's signed prekey + bytes id = 4; +} + +// Hash Ratchet Header +message HRHeader { + // deprecated group key ID + uint32 deprecated_key_id = 1; + // group message number for this key_id + uint32 seq_no = 2; + // group ID + bytes group_id = 3; + // group key ID + bytes key_id = 4; + HRKeys keys = 5; +} + +message RekeyGroup { + uint64 timestamp = 2; + + map keys = 4; +} + +message HRKeys { + repeated HRKey keys = 1; + RekeyGroup rekey_group = 2; +} + +message HRKey { + uint32 deprecated_key_id = 1; + bytes key = 2; + uint64 timestamp = 3; +} + +// Direct message value +message EncryptedMessageProtocol { + X3DHHeader X3DH_header = 1; + DRHeader DR_header = 2; + DHHeader DH_header = 101; + HRHeader HR_header = 102; + // Encrypted payload + bytes payload = 3; +} + +// Top-level protocol message +message ProtocolMessage { + // The device id of the sender + string installation_id = 2; + + // List of bundles + repeated Bundle bundles = 3; + + // One to one message, encrypted, indexed by installation_id + // TODO map here is redundant in case of community messages + map encrypted_message = 101; + + // Public chats, not encrypted + bytes public_message = 102; +} diff --git a/messaging/layers/encryption/protocol_test.go b/messaging/layers/encryption/protocol_test.go new file mode 100644 index 0000000000..25763ea2ac --- /dev/null +++ b/messaging/layers/encryption/protocol_test.go @@ -0,0 +1,176 @@ +package encryption + +import ( + "testing" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/protocol/sqlite" + "github.com/status-im/status-go/protocol/tt" + "github.com/status-im/status-go/t/helpers" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/status-im/status-go/crypto" +) + +func TestProtocolServiceTestSuite(t *testing.T) { + suite.Run(t, new(ProtocolServiceTestSuite)) +} + +type ProtocolServiceTestSuite struct { + suite.Suite + alice *Protocol + bob *Protocol + logger *zap.Logger +} + +func (s *ProtocolServiceTestSuite) SetupTest() { + var err error + + s.logger = tt.MustCreateTestLogger() + + db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(db) + s.Require().NoError(err) + s.alice = New( + db, + "1", + s.logger.With(zap.String("user", "alice")), + ) + + db, err = helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(db) + s.Require().NoError(err) + s.bob = New( + db, + "2", + s.logger.With(zap.String("user", "bob")), + ) +} + +func (s *ProtocolServiceTestSuite) TearDownTest() { + _ = s.logger.Sync() +} + +func (s *ProtocolServiceTestSuite) TestBuildPublicMessage() { + aliceKey, err := crypto.GenerateKey() + s.NoError(err) + + payload := []byte("test") + s.NoError(err) + + msg, err := s.alice.BuildPublicMessage(aliceKey, payload) + s.NoError(err) + s.NotNil(msg, "It creates a message") + + s.NotNilf(msg.Message.GetBundles(), "It adds a bundle to the message") +} + +func (s *ProtocolServiceTestSuite) TestBuildEncryptedMessage() { + bobKey, err := crypto.GenerateKey() + s.NoError(err) + aliceKey, err := crypto.GenerateKey() + s.NoError(err) + + payload := []byte("test") + + msgSpec, err := s.alice.BuildEncryptedMessage(aliceKey, &bobKey.PublicKey, payload) + s.NoError(err) + s.NotNil(msgSpec, "It creates a message spec") + + msg := msgSpec.Message + s.NotNil(msg, "It creates a messages") + + s.NotNilf(msg.GetBundles(), "It adds a bundle to the message") + + directMessage := msg.GetEncryptedMessage() + s.NotNilf(directMessage, "It sets the direct message") + + encryptedPayload := directMessage["none"].GetPayload() + s.NotNilf(encryptedPayload, "It sets the payload of the message") + + s.NotEqualf(payload, encryptedPayload, "It encrypts the payload") +} + +func (s *ProtocolServiceTestSuite) TestBuildAndReadEncryptedMessage() { + bobKey, err := crypto.GenerateKey() + s.Require().NoError(err) + aliceKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + payload := []byte("test") + + // Message is sent with DH + msgSpec, err := s.alice.BuildEncryptedMessage(aliceKey, &bobKey.PublicKey, payload) + s.Require().NoError(err) + s.Require().NotNil(msgSpec) + + msg := msgSpec.Message + s.Require().NotNil(msg) + + // Bob is able to decrypt the message + unmarshaledMsg, err := s.bob.HandleMessage(bobKey, &aliceKey.PublicKey, msg, []byte("message-id")) + s.NoError(err) + s.NotNil(unmarshaledMsg) + + recoveredPayload := []byte("test") + s.Equalf(payload, recoveredPayload, "It successfully unmarshal the decrypted message") +} + +func (s *ProtocolServiceTestSuite) TestSecretNegotiation() { + bobKey, err := crypto.GenerateKey() + s.NoError(err) + aliceKey, err := crypto.GenerateKey() + s.NoError(err) + + payload := []byte("test") + + _, err = s.bob.Start(bobKey) + s.Require().NoError(err) + + msgSpec, err := s.alice.BuildEncryptedMessage(aliceKey, &bobKey.PublicKey, payload) + s.NoError(err) + s.NotNil(msgSpec, "It creates a message spec") + s.Require().NotNil(msgSpec.SharedSecret) + + bundle := msgSpec.Message.GetBundles()[0] + s.Require().NotNil(bundle) + + signedPreKeys := bundle.GetSignedPreKeys() + s.Require().NotNil(signedPreKeys) + + signedPreKey := signedPreKeys["1"] + s.Require().NotNil(signedPreKey) + + s.Require().Equal(uint32(1), signedPreKey.GetProtocolVersion()) + + _, err = s.bob.HandleMessage(bobKey, &aliceKey.PublicKey, msgSpec.Message, []byte("message-id")) + s.NoError(err) + + s.Require().NoError(s.bob.Stop()) +} + +func (s *ProtocolServiceTestSuite) TestPropagatingSavedSharedSecretsOnStart() { + aliceKey, err := crypto.GenerateKey() + s.NoError(err) + bobKey, err := crypto.GenerateKey() + s.NoError(err) + + // Generate and save a shared secret. + generatedSecret, err := s.alice.secret.Generate(aliceKey, &bobKey.PublicKey, "installation-1") + s.NoError(err) + + subscriptions, err := s.alice.Start(aliceKey) + s.Require().NoError(err) + + secretResponse := subscriptions.SharedSecrets + + s.Require().NotNil(secretResponse) + s.Require().Len(secretResponse, 1) + s.Equal(crypto.FromECDSAPub(generatedSecret.Identity), crypto.FromECDSAPub(secretResponse[0].Identity)) + s.Equal(generatedSecret.Key, secretResponse[0].Key) + s.Require().NoError(s.alice.Stop()) +} diff --git a/messaging/layers/encryption/publisher/doc.go b/messaging/layers/encryption/publisher/doc.go new file mode 100644 index 0000000000..3d317e4357 --- /dev/null +++ b/messaging/layers/encryption/publisher/doc.go @@ -0,0 +1,6 @@ +// Publisher periodically publishes an info about itself on a known channel. +// This channel is a particular topic calculated from the public key. +// It is required for other peers to start a secure conversation immediately +// using distibuted data through the channel. + +package publisher diff --git a/messaging/layers/encryption/publisher/persistence.go b/messaging/layers/encryption/publisher/persistence.go new file mode 100644 index 0000000000..f55b7d31d0 --- /dev/null +++ b/messaging/layers/encryption/publisher/persistence.go @@ -0,0 +1,38 @@ +package publisher + +import ( + "encoding/hex" + "sync" +) + +type persistence struct { + lastAcksMutex sync.Mutex + lastPublished int64 + lastAcks map[string]int64 +} + +func newPersistence() *persistence { + return &persistence{ + lastAcks: make(map[string]int64), + } +} + +func (s *persistence) getLastPublished() int64 { + return s.lastPublished +} + +func (s *persistence) setLastPublished(lastPublished int64) { + s.lastPublished = lastPublished +} + +func (s *persistence) lastAck(identity []byte) int64 { + s.lastAcksMutex.Lock() + defer s.lastAcksMutex.Unlock() + return s.lastAcks[hex.EncodeToString(identity)] +} + +func (s *persistence) setLastAck(identity []byte, lastAck int64) { + s.lastAcksMutex.Lock() + defer s.lastAcksMutex.Unlock() + s.lastAcks[hex.EncodeToString(identity)] = lastAck +} diff --git a/messaging/layers/encryption/publisher/publisher.go b/messaging/layers/encryption/publisher/publisher.go new file mode 100644 index 0000000000..11fb5e09bd --- /dev/null +++ b/messaging/layers/encryption/publisher/publisher.go @@ -0,0 +1,131 @@ +package publisher + +import ( + "crypto/ecdsa" + "errors" + "time" + + "go.uber.org/zap" + + gocommon "github.com/status-im/status-go/common" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/logutils" +) + +const ( + // How often a ticker fires in seconds. + tickerInterval = 120 + // How often we should publish a contact code in seconds. + publishInterval = 21600 + // Cooldown period on acking messages when not targeting our device. + deviceNotFoundAckInterval = 7200 +) + +var ( + errNotEnoughTimePassed = errors.New("not enough time passed") +) + +type Publisher struct { + persistence *persistence + logger *zap.Logger + notifyCh chan struct{} + quit chan struct{} +} + +func New(logger *zap.Logger) *Publisher { + if logger == nil { + logger = logutils.ZapLogger() + } + + return &Publisher{ + persistence: newPersistence(), + logger: logger.With(zap.Namespace("Publisher")), + } +} + +func (p *Publisher) Start() <-chan struct{} { + logger := p.logger.With(zap.String("site", "Start")) + + logger.Info("starting publisher") + + p.notifyCh = make(chan struct{}, 100) + p.quit = make(chan struct{}) + + go p.tickerLoop() + + return p.notifyCh +} + +func (p *Publisher) Stop() { + // If hasn't started, ignore + if p.quit == nil { + return + } + select { + case _, ok := <-p.quit: + if !ok { + // channel already closed + return + } + default: + close(p.quit) + } +} + +func (p *Publisher) tickerLoop() { + defer gocommon.LogOnPanic() + ticker := time.NewTicker(tickerInterval * time.Second) + + go func() { + defer gocommon.LogOnPanic() + logger := p.logger.With(zap.String("site", "tickerLoop")) + + for { + select { + case <-ticker.C: + err := p.notify() + switch err { + case errNotEnoughTimePassed: + logger.Debug("not enough time passed") + case nil: + // skip + default: + logger.Error("error while sending a contact code", zap.Error(err)) + } + case <-p.quit: + ticker.Stop() + return + } + } + }() +} + +func (p *Publisher) notify() error { + lastPublished := p.persistence.getLastPublished() + + now := time.Now().Unix() + + if now-lastPublished < publishInterval { + return errNotEnoughTimePassed + } + + select { + case p.notifyCh <- struct{}{}: + default: + p.logger.Warn("publisher channel full, dropping message") + } + + p.persistence.setLastPublished(now) + return nil +} + +func (p *Publisher) ShouldAdvertiseBundle(publicKey *ecdsa.PublicKey, now int64) (bool, error) { + identity := crypto.CompressPubkey(publicKey) + lastAcked := p.persistence.lastAck(identity) + return now-lastAcked < deviceNotFoundAckInterval, nil +} + +func (p *Publisher) SetLastAck(publicKey *ecdsa.PublicKey, now int64) { + identity := crypto.CompressPubkey(publicKey) + p.persistence.setLastAck(identity, now) +} diff --git a/messaging/layers/encryption/publisher/publisher_test.go b/messaging/layers/encryption/publisher/publisher_test.go new file mode 100644 index 0000000000..cea70a7a43 --- /dev/null +++ b/messaging/layers/encryption/publisher/publisher_test.go @@ -0,0 +1,31 @@ +package publisher + +import ( + "testing" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/status-im/status-go/protocol/tt" +) + +func TestServiceTestSuite(t *testing.T) { + suite.Run(t, new(PublisherTestSuite)) +} + +type PublisherTestSuite struct { + suite.Suite + publisher *Publisher + logger *zap.Logger +} + +func (p *PublisherTestSuite) SetupTest(installationID string) { + p.logger = tt.MustCreateTestLogger() + p.publisher = New(p.logger) +} + +func (p *PublisherTestSuite) TearDownTest() { + _ = p.logger.Sync() +} + +// TODO(adam): provide more tests diff --git a/messaging/layers/encryption/sharedsecret/persistence.go b/messaging/layers/encryption/sharedsecret/persistence.go new file mode 100644 index 0000000000..1df3885363 --- /dev/null +++ b/messaging/layers/encryption/sharedsecret/persistence.go @@ -0,0 +1,120 @@ +package sharedsecret + +import ( + "database/sql" + "strings" +) + +type Response struct { + secret []byte + installationIDs map[string]bool +} + +type sqlitePersistence struct { + db *sql.DB +} + +func newSQLitePersistence(db *sql.DB) *sqlitePersistence { + return &sqlitePersistence{db: db} +} + +func (s *sqlitePersistence) Add(identity []byte, secret []byte, installationID string) error { + tx, err := s.db.Begin() + if err != nil { + return err + } + + insertSecretStmt, err := tx.Prepare("INSERT INTO secrets(identity, secret) VALUES (?, ?)") + if err != nil { + _ = tx.Rollback() + return err + } + defer insertSecretStmt.Close() + + _, err = insertSecretStmt.Exec(identity, secret) + if err != nil { + _ = tx.Rollback() + return err + } + + insertInstallationIDStmt, err := tx.Prepare("INSERT INTO secret_installation_ids(id, identity_id) VALUES (?, ?)") + if err != nil { + _ = tx.Rollback() + return err + } + defer insertInstallationIDStmt.Close() + + _, err = insertInstallationIDStmt.Exec(installationID, identity) + if err != nil { + _ = tx.Rollback() + return err + } + return tx.Commit() +} + +func (s *sqlitePersistence) Get(identity []byte, installationIDs []string) (*Response, error) { + response := &Response{ + installationIDs: make(map[string]bool), + } + args := make([]interface{}, len(installationIDs)+1) + args[0] = identity + for i, installationID := range installationIDs { + args[i+1] = installationID + } + + /* #nosec */ + query := `SELECT secret, id + FROM secrets t + JOIN + secret_installation_ids tid + ON t.identity = tid.identity_id + WHERE + t.identity = ? + AND + tid.id IN (?` + strings.Repeat(",?", len(installationIDs)-1) + `)` + + rows, err := s.db.Query(query, args...) + if err != nil && err != sql.ErrNoRows { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var installationID string + var secret []byte + err = rows.Scan(&secret, &installationID) + if err != nil { + return nil, err + } + + response.secret = secret + response.installationIDs[installationID] = true + } + + return response, nil +} + +func (s *sqlitePersistence) All() ([][][]byte, error) { + query := "SELECT identity, secret FROM secrets" + + var secrets [][][]byte + + rows, err := s.db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var secret []byte + var identity []byte + err = rows.Scan(&identity, &secret) + if err != nil { + return nil, err + } + + secrets = append(secrets, [][]byte{identity, secret}) + } + + return secrets, nil +} diff --git a/messaging/layers/encryption/sharedsecret/service_test.go b/messaging/layers/encryption/sharedsecret/service_test.go new file mode 100644 index 0000000000..abe70d29ad --- /dev/null +++ b/messaging/layers/encryption/sharedsecret/service_test.go @@ -0,0 +1,117 @@ +package sharedsecret + +import ( + "testing" + + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/protocol/sqlite" + "github.com/status-im/status-go/protocol/tt" + "github.com/status-im/status-go/t/helpers" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/status-im/status-go/crypto" +) + +func TestServiceTestSuite(t *testing.T) { + suite.Run(t, new(SharedSecretTestSuite)) +} + +type SharedSecretTestSuite struct { + suite.Suite + service *SharedSecret + logger *zap.Logger +} + +func (s *SharedSecretTestSuite) SetupTest() { + s.logger = tt.MustCreateTestLogger() + + db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) + s.Require().NoError(err) + err = sqlite.Migrate(db) + s.Require().NoError(err) + + s.service = New(db, s.logger) +} + +func (s *SharedSecretTestSuite) TearDownTest() { + _ = s.logger.Sync() +} + +func (s *SharedSecretTestSuite) TestSingleInstallationID() { + ourInstallationID := "our" + installationID1 := "1" + installationID2 := "2" + + myKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + theirKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + // We receive a message from installationID1 + sharedKey1, err := s.service.Generate(myKey, &theirKey.PublicKey, installationID1) + s.Require().NoError(err) + s.Require().NotNil(sharedKey1, "it generates a shared key") + + // We want to send a message to installationID1 + sharedKey2, agreed2, err := s.service.Agreed(myKey, ourInstallationID, &theirKey.PublicKey, []string{installationID1}) + s.Require().NoError(err) + s.Require().True(agreed2) + s.Require().NotNil(sharedKey2, "We can retrieve a shared secret") + s.Require().Equal(sharedKey1, sharedKey2, "The shared secret is the same as the one stored") + + // We want to send a message to multiple installationIDs, one of which we haven't never communicated with + sharedKey3, agreed3, err := s.service.Agreed(myKey, ourInstallationID, &theirKey.PublicKey, []string{installationID1, installationID2}) + s.Require().NoError(err) + s.Require().NotNil(sharedKey3, "A shared key is returned") + s.Require().False(agreed3) + + // We receive a message from installationID2 + sharedKey4, err := s.service.Generate(myKey, &theirKey.PublicKey, installationID2) + s.Require().NoError(err) + s.Require().NotNil(sharedKey4, "it generates a shared key") + s.Require().Equal(sharedKey1, sharedKey4, "It generates the same key") + + // We want to send a message to installationID 1 & 2, both have been + sharedKey5, agreed5, err := s.service.Agreed(myKey, ourInstallationID, &theirKey.PublicKey, []string{installationID1, installationID2}) + s.Require().NoError(err) + s.Require().NotNil(sharedKey5, "We can retrieve a shared secret") + s.Require().True(agreed5) + s.Require().Equal(sharedKey1, sharedKey5, "The shared secret is the same as the one stored") + +} + +func (s *SharedSecretTestSuite) TestAll() { + installationID1 := "1" + installationID2 := "2" + + myKey, err := crypto.GenerateKey() + s.Require().NoError(err) + + theirKey1, err := crypto.GenerateKey() + s.Require().NoError(err) + + theirKey2, err := crypto.GenerateKey() + s.Require().NoError(err) + + // We receive a message from user 1 + sharedKey1, err := s.service.Generate(myKey, &theirKey1.PublicKey, installationID1) + s.Require().NoError(err) + s.Require().NotNil(sharedKey1, "it generates a shared key") + + // We receive a message from user 2 + sharedKey2, err := s.service.Generate(myKey, &theirKey2.PublicKey, installationID2) + s.Require().NoError(err) + s.Require().NotNil(sharedKey2, "it generates a shared key") + + // All the secrets are there + secrets, err := s.service.All() + s.Require().NoError(err) + expected := []*Secret{ + sharedKey1, + sharedKey2, + } + s.Require().Equal(expected, secrets) +} diff --git a/messaging/layers/encryption/sharedsecret/sharedsecret.go b/messaging/layers/encryption/sharedsecret/sharedsecret.go new file mode 100644 index 0000000000..8797bdfb64 --- /dev/null +++ b/messaging/layers/encryption/sharedsecret/sharedsecret.go @@ -0,0 +1,104 @@ +package sharedsecret + +import ( + "bytes" + "crypto/ecdsa" + "database/sql" + "errors" + + "go.uber.org/zap" + + "github.com/status-im/status-go/crypto" +) + +type Secret struct { + Identity *ecdsa.PublicKey + Key []byte +} + +// SharedSecret generates and manages negotiated secrets. +// Identities (public keys) stored by SharedSecret +// are compressed. +// TODO: make compression of public keys a responsibility of sqlitePersistence instead of SharedSecret. +type SharedSecret struct { + persistence *sqlitePersistence + logger *zap.Logger +} + +func New(db *sql.DB, logger *zap.Logger) *SharedSecret { + if logger == nil { + logger = zap.NewNop() + } + + return &SharedSecret{ + persistence: newSQLitePersistence(db), + logger: logger.With(zap.Namespace("SharedSecret")), + } +} + +func (s *SharedSecret) generate(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) (*Secret, error) { + sharedKey, err := crypto.GenerateSharedKey(myPrivateKey, theirPublicKey) + if err != nil { + return nil, err + } + + theirIdentity := crypto.CompressPubkey(theirPublicKey) + if err = s.persistence.Add(theirIdentity, sharedKey, installationID); err != nil { + return nil, err + } + + return &Secret{Key: sharedKey, Identity: theirPublicKey}, err +} + +// Generate will generate a shared secret for a given identity, and return it. +func (s *SharedSecret) Generate(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) (*Secret, error) { + return s.generate(myPrivateKey, theirPublicKey, installationID) +} + +// Agreed returns true if a secret has been acknowledged by all the installationIDs. +func (s *SharedSecret) Agreed(myPrivateKey *ecdsa.PrivateKey, myInstallationID string, theirPublicKey *ecdsa.PublicKey, theirInstallationIDs []string) (*Secret, bool, error) { + secret, err := s.generate(myPrivateKey, theirPublicKey, myInstallationID) + if err != nil { + return nil, false, err + } + + if len(theirInstallationIDs) == 0 { + return secret, false, nil + } + + theirIdentity := crypto.CompressPubkey(theirPublicKey) + response, err := s.persistence.Get(theirIdentity, theirInstallationIDs) + if err != nil { + return nil, false, err + } + + for _, installationID := range theirInstallationIDs { + if !response.installationIDs[installationID] { + return secret, false, nil + } + } + + if !bytes.Equal(secret.Key, response.secret) { + return nil, false, errors.New("computed and saved secrets are different for a given identity") + } + + return secret, true, nil +} + +func (s *SharedSecret) All() ([]*Secret, error) { + var secrets []*Secret + tuples, err := s.persistence.All() + if err != nil { + return nil, err + } + + for _, tuple := range tuples { + key, err := crypto.DecompressPubkey(tuple[0]) + if err != nil { + return nil, err + } + secrets = append(secrets, &Secret{Identity: key, Key: tuple[1]}) + } + + return secrets, nil +} diff --git a/messaging/layers/encryption/x3dh.go b/messaging/layers/encryption/x3dh.go new file mode 100644 index 0000000000..66612c357d --- /dev/null +++ b/messaging/layers/encryption/x3dh.go @@ -0,0 +1,230 @@ +package encryption + +import ( + "crypto/ecdsa" + "errors" + "sort" + "strconv" + "time" + + "github.com/status-im/status-go/crypto" +) + +const ( + // Shared secret key length + sskLen = 16 +) + +func buildSignatureMaterial(bundle *Bundle) []byte { + signedPreKeys := bundle.GetSignedPreKeys() + timestamp := bundle.GetTimestamp() + var keys []string + + for k := range signedPreKeys { + keys = append(keys, k) + } + var signatureMaterial []byte + + sort.Strings(keys) + + for _, installationID := range keys { + signedPreKey := signedPreKeys[installationID] + signatureMaterial = append(signatureMaterial, []byte(installationID)...) + signatureMaterial = append(signatureMaterial, signedPreKey.SignedPreKey...) + signatureMaterial = append(signatureMaterial, []byte(strconv.FormatUint(uint64(signedPreKey.Version), 10))...) + // We don't use timestamp in the signature if it's 0, for backward compatibility + } + + if timestamp != 0 { + signatureMaterial = append(signatureMaterial, []byte(strconv.FormatInt(timestamp, 10))...) + } + + return signatureMaterial + +} + +// SignBundle signs the bundle and refreshes the timestamps +func SignBundle(identity *ecdsa.PrivateKey, bundleContainer *BundleContainer) error { + bundleContainer.Bundle.Timestamp = time.Now().UnixNano() + signatureMaterial := buildSignatureMaterial(bundleContainer.GetBundle()) + + signature, err := crypto.Sign(crypto.Keccak256(signatureMaterial), identity) + if err != nil { + return err + } + bundleContainer.Bundle.Signature = signature + return nil +} + +// NewBundleContainer creates a new BundleContainer from an identity private key +func NewBundleContainer(identity *ecdsa.PrivateKey, installationID string) (*BundleContainer, error) { + preKey, err := crypto.GenerateKey() + if err != nil { + return nil, err + } + + compressedPreKey := crypto.CompressPubkey(&preKey.PublicKey) + compressedIdentityKey := crypto.CompressPubkey(&identity.PublicKey) + + encodedPreKey := crypto.FromECDSA(preKey) + signedPreKeys := make(map[string]*SignedPreKey) + signedPreKeys[installationID] = &SignedPreKey{ + ProtocolVersion: protocolVersion, + SignedPreKey: compressedPreKey, + } + + bundle := Bundle{ + Timestamp: time.Now().UnixNano(), + Identity: compressedIdentityKey, + SignedPreKeys: signedPreKeys, + } + + return &BundleContainer{ + Bundle: &bundle, + PrivateSignedPreKey: encodedPreKey, + }, nil +} + +// ExtractIdentity extracts the identity key from a given bundle +func ExtractIdentity(bundle *Bundle) (*ecdsa.PublicKey, error) { + bundleIdentityKey, err := crypto.DecompressPubkey(bundle.GetIdentity()) + if err != nil { + return nil, err + } + + signatureMaterial := buildSignatureMaterial(bundle) + + recoveredKey, err := crypto.SigToPub( + crypto.Keccak256(signatureMaterial), + bundle.GetSignature(), + ) + if err != nil { + return nil, err + } + + if crypto.PubkeyToAddress(*recoveredKey) != crypto.PubkeyToAddress(*bundleIdentityKey) { + return nil, errors.New("identity key and signature mismatch") + } + + return recoveredKey, nil +} + +func getSharedSecret(dh1 []byte, dh2 []byte, dh3 []byte) []byte { + secretInput := append(append(dh1, dh2...), dh3...) + + return crypto.Keccak256(secretInput) +} + +// x3dhActive handles initiating an X3DH session +func x3dhActive( + myIdentityKey *ecdsa.PrivateKey, + theirSignedPreKey *ecdsa.PublicKey, + myEphemeralKey *ecdsa.PrivateKey, + theirIdentityKey *ecdsa.PublicKey, +) ([]byte, error) { + var dh1, dh2, dh3 []byte + var err error + + if dh1, err = crypto.GenerateSharedKey(myIdentityKey, theirSignedPreKey); err != nil { + return nil, err + } + + if dh2, err = crypto.GenerateSharedKey(myEphemeralKey, theirIdentityKey); err != nil { + return nil, err + } + + if dh3, err = crypto.GenerateSharedKey(myEphemeralKey, theirSignedPreKey); err != nil { + return nil, err + } + + return getSharedSecret(dh1, dh2, dh3), nil +} + +// x3dhPassive handles the response to an initiated X3DH session +func x3dhPassive( + theirIdentityKey *ecdsa.PublicKey, + mySignedPreKey *ecdsa.PrivateKey, + theirEphemeralKey *ecdsa.PublicKey, + myIdentityKey *ecdsa.PrivateKey, +) ([]byte, error) { + var dh1, dh2, dh3 []byte + var err error + + if dh1, err = crypto.GenerateSharedKey(mySignedPreKey, theirIdentityKey); err != nil { + return nil, err + } + + if dh2, err = crypto.GenerateSharedKey(myIdentityKey, theirEphemeralKey); err != nil { + return nil, err + } + + if dh3, err = crypto.GenerateSharedKey(mySignedPreKey, theirEphemeralKey); err != nil { + return nil, err + } + + return getSharedSecret(dh1, dh2, dh3), nil +} + +// PerformActiveDH performs a Diffie-Hellman exchange using a public key and a generated ephemeral key. +// Returns the key resulting from the DH exchange as well as the ephemeral public key. +func PerformActiveDH(publicKey *ecdsa.PublicKey) ([]byte, *ecdsa.PublicKey, error) { + ephemeralKey, err := crypto.GenerateKey() + if err != nil { + return nil, nil, err + } + + key, err := crypto.GenerateSharedKey(ephemeralKey, publicKey) + if err != nil { + return nil, nil, err + } + + return key, &ephemeralKey.PublicKey, err +} + +// PerformActiveX3DH takes someone else's bundle and calculates shared secret. +// Returns the shared secret and the ephemeral key used. +func PerformActiveX3DH(identity []byte, signedPreKey []byte, prv *ecdsa.PrivateKey) ([]byte, *ecdsa.PublicKey, error) { + bundleIdentityKey, err := crypto.DecompressPubkey(identity) + if err != nil { + return nil, nil, err + } + + bundleSignedPreKey, err := crypto.DecompressPubkey(signedPreKey) + if err != nil { + return nil, nil, err + } + + ephemeralKey, err := crypto.GenerateKey() + if err != nil { + return nil, nil, err + } + + sharedSecret, err := x3dhActive( + prv, + bundleSignedPreKey, + ephemeralKey, + bundleIdentityKey, + ) + if err != nil { + return nil, nil, err + } + + return sharedSecret, &ephemeralKey.PublicKey, nil +} + +// PerformPassiveX3DH handles the part of the protocol where +// our interlocutor used our bundle, with ID of the signedPreKey, +// we loaded our identity key and the correct signedPreKey and we perform X3DH +func PerformPassiveX3DH(theirIdentityKey *ecdsa.PublicKey, mySignedPreKey *ecdsa.PrivateKey, theirEphemeralKey *ecdsa.PublicKey, myPrivateKey *ecdsa.PrivateKey) ([]byte, error) { + sharedSecret, err := x3dhPassive( + theirIdentityKey, + mySignedPreKey, + theirEphemeralKey, + myPrivateKey, + ) + if err != nil { + return nil, err + } + + return sharedSecret, nil +} diff --git a/messaging/layers/encryption/x3dh_test.go b/messaging/layers/encryption/x3dh_test.go new file mode 100644 index 0000000000..5214c7ba23 --- /dev/null +++ b/messaging/layers/encryption/x3dh_test.go @@ -0,0 +1,209 @@ +package encryption + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/status-im/status-go/crypto" +) + +const ( + alicePrivateKey = "00000000000000000000000000000000" + aliceEphemeralKey = "11111111111111111111111111111111" + bobPrivateKey = "22222222222222222222222222222222" + bobSignedPreKey = "33333333333333333333333333333333" +) + +var sharedKey = []byte{0xa4, 0xe9, 0x23, 0xd0, 0xaf, 0x8f, 0xe7, 0x8a, 0x5, 0x63, 0x63, 0xbe, 0x20, 0xe7, 0x1c, 0xa, 0x58, 0xe5, 0x69, 0xea, 0x8f, 0xc1, 0xf7, 0x92, 0x89, 0xec, 0xa1, 0xd, 0x9f, 0x68, 0x13, 0x3a} + +func bobBundle() (*Bundle, error) { + privateKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) + if err != nil { + return nil, err + } + + signedPreKey, err := crypto.ToECDSA([]byte(bobSignedPreKey)) + if err != nil { + return nil, err + } + + compressedPreKey := crypto.CompressPubkey(&signedPreKey.PublicKey) + + signature, err := crypto.Sign(crypto.Keccak256(compressedPreKey), privateKey) + if err != nil { + return nil, err + } + + signedPreKeys := make(map[string]*SignedPreKey) + signedPreKeys[bobInstallationID] = &SignedPreKey{SignedPreKey: compressedPreKey} + + bundle := Bundle{ + Identity: crypto.CompressPubkey(&privateKey.PublicKey), + SignedPreKeys: signedPreKeys, + Signature: signature, + } + + return &bundle, nil +} + +func TestNewBundleContainer(t *testing.T) { + privateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) + require.NoError(t, err, "Private key should be generated without errors") + + bundleContainer, err := NewBundleContainer(privateKey, bobInstallationID) + require.NoError(t, err, "Bundle container should be created successfully") + + err = SignBundle(privateKey, bundleContainer) + require.NoError(t, err, "Bundle container should be signed successfully") + + require.NoError(t, err, "Bundle container should be created successfully") + + bundle := bundleContainer.Bundle + require.NotNil(t, bundle, "Bundle should be generated without errors") + + signatureMaterial := append([]byte(bobInstallationID), bundle.GetSignedPreKeys()[bobInstallationID].GetSignedPreKey()...) + signatureMaterial = append(signatureMaterial, []byte("0")...) + signatureMaterial = append(signatureMaterial, []byte(fmt.Sprint(bundle.GetTimestamp()))...) + recoveredPublicKey, err := crypto.SigToPub( + crypto.Keccak256(signatureMaterial), + bundle.Signature, + ) + + require.NoError(t, err, "Public key should be recovered from the bundle successfully") + + require.Equal( + t, + privateKey.PublicKey, + *recoveredPublicKey, + "The correct public key should be recovered", + ) +} + +func TestSignBundle(t *testing.T) { + privateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) + require.NoError(t, err, "Private key should be generated without errors") + + bundleContainer1, err := NewBundleContainer(privateKey, "1") + require.NoError(t, err, "Bundle container should be created successfully") + + bundle1 := bundleContainer1.Bundle + require.NotNil(t, bundle1, "Bundle should be generated without errors") + + // We add a signed pre key + signedPreKeys := bundle1.GetSignedPreKeys() + signedPreKeys["2"] = &SignedPreKey{SignedPreKey: []byte("key")} + + err = SignBundle(privateKey, bundleContainer1) + require.NoError(t, err) + + signatureMaterial := append([]byte("1"), bundle1.GetSignedPreKeys()["1"].GetSignedPreKey()...) + signatureMaterial = append(signatureMaterial, []byte("0")...) + signatureMaterial = append(signatureMaterial, []byte("2")...) + signatureMaterial = append(signatureMaterial, []byte("key")...) + signatureMaterial = append(signatureMaterial, []byte("0")...) + signatureMaterial = append(signatureMaterial, []byte(fmt.Sprint(bundle1.GetTimestamp()))...) + + recoveredPublicKey, err := crypto.SigToPub( + crypto.Keccak256(signatureMaterial), + bundleContainer1.GetBundle().Signature, + ) + + require.NoError(t, err, "Public key should be recovered from the bundle successfully") + + require.Equal( + t, + privateKey.PublicKey, + *recoveredPublicKey, + "The correct public key should be recovered", + ) +} + +func TestExtractIdentity(t *testing.T) { + privateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) + require.NoError(t, err, "Private key should be generated without errors") + + bundleContainer, err := NewBundleContainer(privateKey, "1") + require.NoError(t, err, "Bundle container should be created successfully") + + err = SignBundle(privateKey, bundleContainer) + require.NoError(t, err, "Bundle container should be signed successfully") + + bundle := bundleContainer.Bundle + require.NotNil(t, bundle, "Bundle should be generated without errors") + + recoveredPublicKey, err := ExtractIdentity(bundle) + + require.NoError(t, err, "Public key should be recovered from the bundle successfully") + + require.Equal( + t, + privateKey.PublicKey, + *recoveredPublicKey, + "The correct public key should be recovered", + ) +} + +// Alice wants to send a message to Bob +func TestX3dhActive(t *testing.T) { + bobIdentityKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) + require.NoError(t, err, "Bundle identity key should be generated without errors") + + bobSignedPreKey, err := crypto.ToECDSA([]byte(bobSignedPreKey)) + require.NoError(t, err, "Bundle signed pre key should be generated without errors") + + aliceIdentityKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) + require.NoError(t, err, "Private key should be generated without errors") + + aliceEphemeralKey, err := crypto.ToECDSA([]byte(aliceEphemeralKey)) + require.NoError(t, err, "Ephemeral key should be generated without errors") + + x3dh, err := x3dhActive( + aliceIdentityKey, + &bobSignedPreKey.PublicKey, + aliceEphemeralKey, + &bobIdentityKey.PublicKey, + ) + require.NoError(t, err, "Shared key should be generated without errors") + require.Equal(t, sharedKey, x3dh, "Should generate the correct key") +} + +// Bob receives a message from Alice +func TestPerformPassiveX3DH(t *testing.T) { + alicePrivateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) + require.NoError(t, err, "Private key should be generated without errors") + + bobSignedPreKey, err := crypto.ToECDSA([]byte(bobSignedPreKey)) + require.NoError(t, err, "Private key should be generated without errors") + + aliceEphemeralKey, err := crypto.ToECDSA([]byte(aliceEphemeralKey)) + require.NoError(t, err, "Ephemeral key should be generated without errors") + + bobPrivateKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) + require.NoError(t, err, "Private key should be generated without errors") + + x3dh, err := PerformPassiveX3DH( + &alicePrivateKey.PublicKey, + bobSignedPreKey, + &aliceEphemeralKey.PublicKey, + bobPrivateKey, + ) + require.NoError(t, err, "Shared key should be generated without errors") + require.Equal(t, sharedKey, x3dh, "Should generate the correct key") +} + +func TestPerformActiveX3DH(t *testing.T) { + bundle, err := bobBundle() + require.NoError(t, err, "Test bundle should be generated without errors") + + privateKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) + require.NoError(t, err, "Private key should be imported without errors") + + signedPreKey := bundle.GetSignedPreKeys()[bobInstallationID].GetSignedPreKey() + + actualSharedSecret, actualEphemeralKey, err := PerformActiveX3DH(bundle.GetIdentity(), signedPreKey, privateKey) + require.NoError(t, err, "No error should be reported") + require.NotNil(t, actualEphemeralKey, "An ephemeral key-pair should be generated") + require.NotNil(t, actualSharedSecret, "A shared key should be generated") +} diff --git a/messaging/types/chat_entity.go b/messaging/types/chat_entity.go new file mode 100644 index 0000000000..fe1c898999 --- /dev/null +++ b/messaging/types/chat_entity.go @@ -0,0 +1,23 @@ +package types + +import ( + "crypto/ecdsa" + + "github.com/golang/protobuf/proto" + + "github.com/status-im/status-go/protocol/protobuf" +) + +// ChatEntity is anything that is sendable in a chat. +// Currently it encompass a Message and EmojiReaction. +type ChatEntity interface { + proto.Message + + GetChatId() string + GetMessageType() protobuf.MessageType + GetSigPubKey() *ecdsa.PublicKey + GetProtobuf() proto.Message + WrapGroupMessage() bool + + SetMessageType(messageType protobuf.MessageType) +} diff --git a/messaging/types/encryption_subscriptions.go b/messaging/types/encryption_subscriptions.go new file mode 100644 index 0000000000..a4634deff0 --- /dev/null +++ b/messaging/types/encryption_subscriptions.go @@ -0,0 +1,8 @@ +package types + +type EncryptionSubscriptions struct { + SharedSecrets []*SharedSecret + SendContactCode <-chan struct{} + NewHashRatchetKeys <-chan []*HashRatchetInfo + Quit chan struct{} +} diff --git a/messaging/types/handle_message_response.go b/messaging/types/handle_message_response.go new file mode 100644 index 0000000000..c80dca24de --- /dev/null +++ b/messaging/types/handle_message_response.go @@ -0,0 +1,17 @@ +package types + +import "crypto/ecdsa" + +type HandleMessageResponse struct { + Hash []byte + StatusMessages []*Message + DatasyncSender *ecdsa.PublicKey + DatasyncAcks [][]byte + DatasyncOffers []DatasyncOffer + DatasyncRequests [][]byte +} + +type DatasyncOffer struct { + GroupID []byte + MessageID []byte +} diff --git a/messaging/types/hash_ratchet.go b/messaging/types/hash_ratchet.go new file mode 100644 index 0000000000..9e87776c1e --- /dev/null +++ b/messaging/types/hash_ratchet.go @@ -0,0 +1,13 @@ +package types + +import "errors" + +var ( + ErrHashRatchetGroupIDNotFound = errors.New("hash ratchet group id not found") + ErrNoRatchetKey = errors.New("no ratchet key for given keyID") +) + +type HashRatchetInfo struct { + GroupID []byte + KeyID []byte +} diff --git a/messaging/types/installation.go b/messaging/types/installation.go new file mode 100644 index 0000000000..e80707b2ef --- /dev/null +++ b/messaging/types/installation.go @@ -0,0 +1,27 @@ +package types + +type InstallationMetadata struct { + // The name of the device + Name string `json:"name"` + // The type of device + DeviceType string `json:"deviceType"` +} + +type Installation struct { + // Identity is the string identity of the owner + Identity string `json:"identity"` + // The installation-id of the device + ID string `json:"id"` + // The last known protocol version of the device + Version uint32 `json:"version"` + // Enabled is whether the installation is enabled + Enabled bool `json:"enabled"` + // Timestamp is the last time we saw this device + Timestamp int64 `json:"timestamp"` + // InstallationMetadata + InstallationMetadata *InstallationMetadata `json:"metadata"` +} + +func (i *Installation) UniqueKey() string { + return i.ID + i.Identity +} diff --git a/messaging/types/message.go b/messaging/types/message.go new file mode 100644 index 0000000000..33ac87f485 --- /dev/null +++ b/messaging/types/message.go @@ -0,0 +1,87 @@ +package types + +import ( + "crypto/ecdsa" + "encoding/json" + + "github.com/jinzhu/copier" + + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/protocol/protobuf" +) + +// TransportLayer is the lowest layer and represents waku message. +type TransportLayer struct { + // Payload as received from the transport layer + Payload []byte `json:"-"` + Hash []byte `json:"-"` + SigPubKey *ecdsa.PublicKey `json:"-"` + Dst *ecdsa.PublicKey + Message *ReceivedMessage `json:"message"` +} + +// EncryptionLayer handles optional encryption. +// It is not mandatory and can be omitted, +// also its presence does not guarantee encryption. +type EncryptionLayer struct { + // Payload after having been processed by the encryption layer + Payload []byte `json:"-"` + Installations []*Installation + SharedSecrets []*SharedSecret + HashRatchetInfo []*HashRatchetInfo +} + +// ApplicationLayer is the topmost layer and represents the application message. +type ApplicationLayer struct { + // Payload after having been unwrapped from the application layer + Payload []byte `json:"-"` + ID types.HexBytes `json:"id"` + SigPubKey *ecdsa.PublicKey `json:"-"` + Type protobuf.ApplicationMetadataMessage_Type `json:"-"` +} + +// Message encapsulates all layers of the protocol +type Message struct { + TransportLayer TransportLayer `json:"transportLayer"` + EncryptionLayer EncryptionLayer `json:"encryptionLayer"` + ApplicationLayer ApplicationLayer `json:"applicationLayer"` +} + +// Temporary JSON marshaling for those messages that are not yet processed +// by the go code +func (m *Message) MarshalJSON() ([]byte, error) { + item := struct { + ID types.HexBytes `json:"id"` + Payload string `json:"payload"` + From types.HexBytes `json:"from"` + Timestamp uint32 `json:"timestamp"` + }{ + ID: m.ApplicationLayer.ID, + Payload: string(m.ApplicationLayer.Payload), + Timestamp: m.TransportLayer.Message.Timestamp, + From: m.TransportLayer.Message.Sig, + } + return json.Marshal(item) +} + +// SigPubKey returns the most important signature, from the application layer to transport +func (m *Message) SigPubKey() *ecdsa.PublicKey { + if m.ApplicationLayer.SigPubKey != nil { + return m.ApplicationLayer.SigPubKey + } + + return m.TransportLayer.SigPubKey +} + +func (m *Message) Clone() (*Message, error) { + copy := &Message{} + + err := copier.Copy(©, m) + return copy, err +} + +func MessageID(author *ecdsa.PublicKey, data []byte) types.HexBytes { + keyBytes := crypto.FromECDSAPub(author) + return types.HexBytes(crypto.Keccak256(append(keyBytes, data...))) +} diff --git a/messaging/types/peers.go b/messaging/types/peers.go new file mode 100644 index 0000000000..7715f5baa9 --- /dev/null +++ b/messaging/types/peers.go @@ -0,0 +1,34 @@ +package types + +import ( + "encoding/json" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/protocol" + "github.com/multiformats/go-multiaddr" +) + +type ConnStatus struct { + IsOnline bool `json:"isOnline"` + Peers PeerStats `json:"peers"` +} + +type PeerStats map[peer.ID]Peer + +func (m PeerStats) MarshalJSON() ([]byte, error) { + tmpMap := make(map[string]Peer) + for k, v := range m { + tmpMap[k.String()] = v + } + return json.Marshal(tmpMap) +} + +type Peer struct { + Protocols []protocol.ID `json:"protocols"` + Addresses []multiaddr.Multiaddr `json:"addresses"` +} + +type PeerList struct { + FullMeshPeers peer.IDSlice `json:"fullMesh"` + AllPeers peer.IDSlice `json:"all"` +} diff --git a/messaging/types/raw_message.go b/messaging/types/raw_message.go new file mode 100644 index 0000000000..af1d344fcb --- /dev/null +++ b/messaging/types/raw_message.go @@ -0,0 +1,102 @@ +package types + +import ( + "crypto/ecdsa" + "errors" + + "github.com/status-im/status-go/protocol/protobuf" +) + +type CommKeyExMsgType uint8 + +const ( + KeyExMsgNone CommKeyExMsgType = 0 + KeyExMsgReuse CommKeyExMsgType = 1 + KeyExMsgRekey CommKeyExMsgType = 2 +) + +// ResendType There are distinct mechanisms for retrying send messages: Datasync supports only direct messages (1-to-1 or private group chats) +// because it requires an acknowledgment (ACK). As implemented, sending a message to a community, where hundreds of +// people receive it, would lead all recipients to attempt sending an ACK, resulting in an excessive number of messages. +// Datasync utilizes ACKs, but community messages do not, to avoid this issue. However, we still aim to retry sending +// community messages if they fail to send or if we are offline. +type ResendType uint8 + +const ( + // ResendTypeNone won't resend + ResendTypeNone ResendType = 0 + // ResendTypeDataSync use DataSync which use MVDS as underlying dependency to resend messages. + // Works only when underlying sending method is MessageSender#SendPrivate. Pls see SendPrivate for more details. + // For usage example, you can find usage with this type value in this project. e.g. Messenger#syncContact + ResendTypeDataSync ResendType = 1 + // ResendTypeRawMessage We have a function, watchExpiredMessages, that monitors the 'raw_messages' table + // and will attempts to resend messages if a previous message sending failed. + ResendTypeRawMessage ResendType = 2 +) + +// ResendMethod defines how to resend a raw message +type ResendMethod uint8 + +const ( + // ResendMethodDynamic determined by logic of Messenger#dispatchMessage, mostly based on chat type + ResendMethodDynamic ResendMethod = 0 + // ResendMethodSendPrivate corresponding function MessageSender#SendPrivate + ResendMethodSendPrivate ResendMethod = 1 + // ResendMethodSendCommunityMessage corresponding function MessageSender#SendCommunityMessage + ResendMethodSendCommunityMessage ResendMethod = 2 +) + +// MessagePriority determines the ordering for publishing message +type MessagePriority = int + +var ( + LowPriority MessagePriority = 0 + NormalPriority MessagePriority = 1 + HighPriority MessagePriority = 2 +) + +// RawMessage represent a sent or received message, kept for being able +// to re-send/propagate +type RawMessage struct { + ID string + LocalChatID string + LastSent uint64 + SendCount int + Sent bool + // don't wrap message into ProtocolMessage. + // when this is true, the message will not be resent via ResendTypeDataSync, but it's possible to + // resend it via ResendTypeRawMessage specified in ResendType + // MVDS only supports sending encrypted message. + SkipEncryptionLayer bool + SendPushNotification bool + MessageType protobuf.ApplicationMetadataMessage_Type + Payload []byte + Sender *ecdsa.PrivateKey + Recipients []*ecdsa.PublicKey + SkipGroupMessageWrap bool + SkipApplicationWrap bool + SendOnPersonalTopic bool + CommunityID []byte + CommunityKeyExMsgType CommKeyExMsgType + Ephemeral bool + BeforeDispatch func(*RawMessage) error + HashRatchetGroupID []byte + ContentTopic string + PubsubTopic string + ResendType ResendType + ResendMethod ResendMethod + Priority *MessagePriority +} + +type RawMessageConfirmation struct { + // DataSyncID is the ID of the datasync message sent + DataSyncID []byte + // MessageID is the message id of the message + MessageID []byte + // PublicKey is the compressed receiver public key + PublicKey []byte + // ConfirmedAt is the unix timestamp in seconds of when the message was confirmed + ConfirmedAt int64 +} + +var ErrModifiedRawMessage = errors.New("modified rawMessage") diff --git a/messaging/types/received_messages.go b/messaging/types/received_messages.go new file mode 100644 index 0000000000..58a31adf29 --- /dev/null +++ b/messaging/types/received_messages.go @@ -0,0 +1,7 @@ +package types + +type ReceivedMessages struct { + Filter ChatFilter + SHHMessage *ReceivedMessage + Messages []*Message +} diff --git a/messaging/types/segment_message.go b/messaging/types/segment_message.go new file mode 100644 index 0000000000..04526c9236 --- /dev/null +++ b/messaging/types/segment_message.go @@ -0,0 +1,30 @@ +package types + +import "github.com/status-im/status-go/protocol/protobuf" + +type SegmentMessage struct { + *protobuf.SegmentMessage +} + +func (s *SegmentMessage) IsValid() bool { + // Check if the hash length is valid (32 bytes for Keccak256) + if len(s.EntireMessageHash) != 32 { + return false + } + + // Check if the segment index is within the valid range + if s.SegmentsCount > 0 && s.Index >= s.SegmentsCount { + return false + } + + // Check if the parity segment index is within the valid range + if s.ParitySegmentsCount > 0 && s.ParitySegmentIndex >= s.ParitySegmentsCount { + return false + } + + return s.SegmentsCount >= 2 || s.ParitySegmentsCount > 0 +} + +func (s *SegmentMessage) IsParityMessage() bool { + return s.SegmentsCount == 0 && s.ParitySegmentsCount > 0 +} diff --git a/messaging/types/shard.go b/messaging/types/shard.go new file mode 100644 index 0000000000..8c6700fc93 --- /dev/null +++ b/messaging/types/shard.go @@ -0,0 +1,103 @@ +package types + +import ( + wakuproto "github.com/waku-org/go-waku/waku/v2/protocol" + + wakuv2 "github.com/status-im/status-go/messaging/waku" + "github.com/status-im/status-go/protocol/protobuf" +) + +type Shard struct { + Cluster uint16 `json:"cluster"` + Index uint16 `json:"index"` +} + +func (s *Shard) Protobuffer() *protobuf.Shard { + if s == nil { + return nil + } + + return &protobuf.Shard{ + Cluster: int32(s.Cluster), + Index: int32(s.Index), + } +} + +func (s *Shard) PubsubTopic() string { + if s == nil { + return "" + } + + wakuv2Shard := wakuv2.Shard{ + Cluster: s.Cluster, + Index: s.Index, + } + + return wakuv2Shard.PubsubTopic() +} + +func FromShardProtobuff(p *protobuf.Shard) *Shard { + if p == nil { + return nil + } + + return &Shard{ + Cluster: uint16(p.Cluster), + Index: uint16(p.Index), + } +} + +const MainStatusShardCluster = 16 +const DefaultShardIndex = 32 +const NonProtectedShardIndex = 64 + +func DefaultShardPubsubTopic() string { + return wakuproto.NewStaticShardingPubsubTopic(MainStatusShardCluster, DefaultShardIndex).String() +} + +func DefaultShard() *Shard { + return &Shard{ + Cluster: MainStatusShardCluster, + Index: DefaultShardIndex, + } +} + +func DefaultNonProtectedShard() *Shard { + return &Shard{ + Cluster: MainStatusShardCluster, + Index: NonProtectedShardIndex, + } +} + +// TODO this is used only for community control messages, we need to stop using it once migration is done +func DefaultNonProtectedPubsubTopic() string { + return DefaultNonProtectedShard().PubsubTopic() +} + +// GlobalCommunityControlShard returns the shard for the global community control messages +// +// Specs: https://github.com/vacp2p/rfc-index/blob/8ee2a6d6b232838d83374c35e2413f84436ecf64/status/56/communities.md?plain=1#L329 +func GlobalCommunityControlShard() *Shard { + return &Shard{ + Cluster: MainStatusShardCluster, + Index: 128, + } +} + +// GlobalCommunityContentShard returns the shard for the global community content messages +// +// Specs: https://github.com/vacp2p/rfc-index/blob/8ee2a6d6b232838d83374c35e2413f84436ecf64/status/56/communities.md?plain=1#L330 +func GlobalCommunityContentShard() *Shard { + return &Shard{ + Cluster: MainStatusShardCluster, + Index: 256, + } +} + +func GlobalCommunityControlPubsubTopic() string { + return GlobalCommunityControlShard().PubsubTopic() +} + +func GlobalCommunityContentPubsubTopic() string { + return GlobalCommunityContentShard().PubsubTopic() +} diff --git a/messaging/types/shared_secret.go b/messaging/types/shared_secret.go new file mode 100644 index 0000000000..805be1c332 --- /dev/null +++ b/messaging/types/shared_secret.go @@ -0,0 +1,8 @@ +package types + +import "crypto/ecdsa" + +type SharedSecret struct { + Identity *ecdsa.PublicKey + Key []byte +} diff --git a/messaging/types/store_node.go b/messaging/types/store_node.go new file mode 100644 index 0000000000..933271e3ce --- /dev/null +++ b/messaging/types/store_node.go @@ -0,0 +1,80 @@ +package types + +import ( + "encoding/json" + "fmt" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + + "github.com/ethereum/go-ethereum/p2p/enode" + + wakutypes "github.com/status-im/status-go/messaging/waku/types" +) + +type StoreNode struct { + ID string `json:"id"` + Name string `json:"name"` + Custom bool `json:"custom"` + ENR *enode.Node `json:"enr"` + Addr *multiaddr.Multiaddr `json:"addr"` +} + +func (m StoreNode) PeerID() (peer.ID, error) { + return wakutypes.Mailserver{ + ID: m.ID, + Name: m.Name, + Custom: m.Custom, + ENR: m.ENR, + Addr: m.Addr, + }.PeerID() +} + +func (m StoreNode) PeerInfo() (peer.AddrInfo, error) { + return wakutypes.Mailserver{ + ID: m.ID, + Name: m.Name, + Custom: m.Custom, + ENR: m.ENR, + Addr: m.Addr, + }.PeerInfo() +} + +// UnmarshalJSON implements the custom JSON unmarshaling logic for Mailserver. +// It supports ENR and Addr being saved as strings. +func (m *StoreNode) UnmarshalJSON(data []byte) error { + type Alias StoreNode // Create an alias type to avoid infinite recursion + aux := struct { + Alias + ENR string `json:"enr"` // Temporary field to handle ENR as a string + Addr string `json:"addr"` // Temporary field to handle Addr as a string + }{} + + // Unmarshal the data into the temporary struct + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + // Set the basic fields + *m = StoreNode(aux.Alias) + + // Decode the ENR if present + if aux.ENR != "" { + decodedENR, err := enode.Parse(enode.ValidSchemes, aux.ENR) + if err != nil { + return fmt.Errorf("invalid ENR: %w", err) + } + m.ENR = decodedENR + } + + // Decode the Multiaddr if present + if aux.Addr != "" { + decodedAddr, err := multiaddr.NewMultiaddr(aux.Addr) + if err != nil { + return fmt.Errorf("invalid Addr: %w", err) + } + m.Addr = &decodedAddr + } + + return nil +} diff --git a/messaging/types/transport_stats.go b/messaging/types/transport_stats.go new file mode 100644 index 0000000000..0842a2738c --- /dev/null +++ b/messaging/types/transport_stats.go @@ -0,0 +1,6 @@ +package types + +type TransportStats struct { + UploadRate uint64 `json:"uploadRate"` + DownloadRate uint64 `json:"downloadRate"` +} diff --git a/wakuv2/README.md b/messaging/waku/README.md similarity index 100% rename from wakuv2/README.md rename to messaging/waku/README.md diff --git a/wakuv2/api.go b/messaging/waku/api.go similarity index 83% rename from wakuv2/api.go rename to messaging/waku/api.go index b5df79bd7a..6abf6d0fe4 100644 --- a/wakuv2/api.go +++ b/messaging/waku/api.go @@ -28,21 +28,20 @@ import ( "go.uber.org/zap" + "google.golang.org/protobuf/proto" + "github.com/waku-org/go-waku/waku/v2/payload" "github.com/waku-org/go-waku/waku/v2/protocol/pb" - ethtypes "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/logutils" - "github.com/status-im/status-go/waku/types" - "github.com/status-im/status-go/wakuv2/common" - + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rpc" - "google.golang.org/protobuf/proto" - gocommon "github.com/status-im/status-go/common" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/logutils" + "github.com/status-im/status-go/messaging/waku/common" + "github.com/status-im/status-go/messaging/waku/types" ) // List of errors @@ -97,48 +96,11 @@ func (api *PublicWakuAPI) NewKeyPair(ctx context.Context) (string, error) { return api.w.NewKeyPair() } -// AddPrivateKey imports the given private key. -func (api *PublicWakuAPI) AddPrivateKey(ctx context.Context, privateKey ethtypes.HexBytes) (string, error) { - key, err := crypto.ToECDSA(privateKey) - if err != nil { - return "", err - } - return api.w.AddKeyPair(key) -} - -// DeleteKeyPair removes the key with the given key if it exists. -func (api *PublicWakuAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) { - if ok := api.w.DeleteKeyPair(key); ok { - return true, nil - } - return false, fmt.Errorf("key pair %s not found", key) -} - // HasKeyPair returns an indication if the node has a key pair that is associated with the given id. func (api *PublicWakuAPI) HasKeyPair(ctx context.Context, id string) bool { return api.w.HasKeyPair(id) } -// GetPublicKey returns the public key associated with the given key. The key is the hex -// encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. -func (api *PublicWakuAPI) GetPublicKey(ctx context.Context, id string) (hexutil.Bytes, error) { - key, err := api.w.GetPrivateKey(id) - if err != nil { - return hexutil.Bytes{}, err - } - return crypto.FromECDSAPub(&key.PublicKey), nil -} - -// GetPrivateKey returns the private key associated with the given key. The key is the hex -// encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. -func (api *PublicWakuAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error) { - key, err := api.w.GetPrivateKey(id) - if err != nil { - return hexutil.Bytes{}, err - } - return crypto.FromECDSA(key), nil -} - // NewSymKey generate a random symmetric key. // It returns an ID that can be used to refer to the key. // Can be used encrypting and decrypting messages where the key is known to both parties. @@ -146,18 +108,6 @@ func (api *PublicWakuAPI) NewSymKey(ctx context.Context) (string, error) { return api.w.GenerateSymKey() } -// AddSymKey import a symmetric key. -// It returns an ID that can be used to refer to the key. -// Can be used encrypting and decrypting messages where the key is known to both parties. -func (api *PublicWakuAPI) AddSymKey(ctx context.Context, key hexutil.Bytes) (string, error) { - return api.w.AddSymKeyDirect([]byte(key)) -} - -// GenerateSymKeyFromPassword derive a key from the given password, stores it, and returns its ID. -func (api *PublicWakuAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) { - return api.w.AddSymKeyFromPassword(passwd) -} - // HasSymKey returns an indication if the node has a symmetric key associated with the given key. func (api *PublicWakuAPI) HasSymKey(ctx context.Context, id string) bool { return api.w.HasSymKey(id) @@ -168,11 +118,6 @@ func (api *PublicWakuAPI) GetSymKey(ctx context.Context, id string) (hexutil.Byt return api.w.GetSymKey(id) } -// DeleteSymKey deletes the symmetric key that is associated with the given id. -func (api *PublicWakuAPI) DeleteSymKey(ctx context.Context, id string) bool { - return api.w.DeleteSymKey(id) -} - // Post posts a message on the Waku network. // returns the hash of the message in case of success. func (api *PublicWakuAPI) Post(ctx context.Context, req types.NewMessage) ([]byte, error) { @@ -316,7 +261,7 @@ func (api *PublicWakuAPI) Messages(ctx context.Context, crit types.Criteria) (*r return nil, ErrInvalidSymmetricKey } filter.KeySym = key - filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym) + filter.SymKeyHash = ethcommon.Hash(crypto.Keccak256Hash(filter.KeySym)) } // listen for messages that are encrypted with the given public key diff --git a/wakuv2/api_test.go b/messaging/waku/api_test.go similarity index 94% rename from wakuv2/api_test.go rename to messaging/waku/api_test.go index 9c55d2fde4..a5ca8c4d12 100644 --- a/wakuv2/api_test.go +++ b/messaging/waku/api_test.go @@ -19,13 +19,12 @@ package wakuv2 import ( + "maps" "testing" "time" - "golang.org/x/exp/maps" - - "github.com/status-im/status-go/waku/types" - "github.com/status-im/status-go/wakuv2/common" + "github.com/status-im/status-go/messaging/waku/common" + "github.com/status-im/status-go/messaging/waku/types" ) func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) { diff --git a/wakuv2/bridge.go b/messaging/waku/bridge.go similarity index 78% rename from wakuv2/bridge.go rename to messaging/waku/bridge.go index a71836915a..1e7beffe4f 100644 --- a/wakuv2/bridge.go +++ b/messaging/waku/bridge.go @@ -2,12 +2,13 @@ package wakuv2 import ( "github.com/ethereum/go-ethereum/event" + cryptotypes "github.com/status-im/status-go/crypto/types" ethtypes "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/waku/types" - "github.com/status-im/status-go/wakuv2/common" + "github.com/status-im/status-go/messaging/waku/common" + "github.com/status-im/status-go/messaging/waku/types" ) -// NewWakuV2EnvelopeEventWrapper returns a wakutypes.EnvelopeEvent object that mimics Geth's EnvelopeEvent +// NewWakuV2EnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent func NewWakuV2EnvelopeEventWrapper(envelopeEvent *common.EnvelopeEvent) *types.EnvelopeEvent { if envelopeEvent == nil { panic("envelopeEvent should not be nil") @@ -23,21 +24,21 @@ func NewWakuV2EnvelopeEventWrapper(envelopeEvent *common.EnvelopeEvent) *types.E } return &types.EnvelopeEvent{ Event: types.EventType(envelopeEvent.Event), - Hash: ethtypes.Hash(envelopeEvent.Hash), - Batch: ethtypes.Hash(envelopeEvent.Batch), + Hash: cryptotypes.Hash(envelopeEvent.Hash), + Batch: cryptotypes.Hash(envelopeEvent.Batch), Peer: ethtypes.EnodeID(envelopeEvent.Peer), Data: wrappedData, } } -// NewWakuEnvelopeErrorWrapper returns a wakutypes.EnvelopeError object that mimics Geth's EnvelopeError +// NewWakuEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError func NewWakuV2EnvelopeErrorWrapper(envelopeError *common.EnvelopeError) *types.EnvelopeError { if envelopeError == nil { panic("envelopeError should not be nil") } return &types.EnvelopeError{ - Hash: ethtypes.Hash(envelopeError.Hash), + Hash: cryptotypes.Hash(envelopeError.Hash), Code: mapGethErrorCode(envelopeError.Code), Description: envelopeError.Description, } diff --git a/wakuv2/common/README.md b/messaging/waku/common/README.md similarity index 100% rename from wakuv2/common/README.md rename to messaging/waku/common/README.md diff --git a/wakuv2/common/const.go b/messaging/waku/common/const.go similarity index 100% rename from wakuv2/common/const.go rename to messaging/waku/common/const.go diff --git a/wakuv2/common/envelope.go b/messaging/waku/common/envelope.go similarity index 99% rename from wakuv2/common/envelope.go rename to messaging/waku/common/envelope.go index f8c4cc570c..bca526da3e 100644 --- a/wakuv2/common/envelope.go +++ b/messaging/waku/common/envelope.go @@ -3,8 +3,9 @@ package common import ( "encoding/json" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/waku-org/go-waku/waku/v2/protocol/pb" + + "github.com/ethereum/go-ethereum/common/hexutil" ) // Envelope contains information about the pubsub topic of a WakuMessage diff --git a/wakuv2/common/envelope_test.go b/messaging/waku/common/envelope_test.go similarity index 99% rename from wakuv2/common/envelope_test.go rename to messaging/waku/common/envelope_test.go index 291a067d72..e7a23226cf 100644 --- a/wakuv2/common/envelope_test.go +++ b/messaging/waku/common/envelope_test.go @@ -6,8 +6,9 @@ import ( "github.com/stretchr/testify/assert" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/waku-org/go-waku/waku/v2/protocol/pb" + + "github.com/ethereum/go-ethereum/common/hexutil" ) func TestNewEnvelope(t *testing.T) { diff --git a/wakuv2/common/events.go b/messaging/waku/common/events.go similarity index 100% rename from wakuv2/common/events.go rename to messaging/waku/common/events.go diff --git a/wakuv2/common/filter.go b/messaging/waku/common/filter.go similarity index 99% rename from wakuv2/common/filter.go rename to messaging/waku/common/filter.go index 4815492d86..5f8eb86994 100644 --- a/wakuv2/common/filter.go +++ b/messaging/waku/common/filter.go @@ -21,10 +21,10 @@ package common import ( "crypto/ecdsa" "fmt" + "maps" "sync" "go.uber.org/zap" - "golang.org/x/exp/maps" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" diff --git a/wakuv2/common/filter_test.go b/messaging/waku/common/filter_test.go similarity index 100% rename from wakuv2/common/filter_test.go rename to messaging/waku/common/filter_test.go diff --git a/wakuv2/common/helpers.go b/messaging/waku/common/helpers.go similarity index 93% rename from wakuv2/common/helpers.go rename to messaging/waku/common/helpers.go index 1c3d0557fb..abdd74216f 100644 --- a/wakuv2/common/helpers.go +++ b/messaging/waku/common/helpers.go @@ -30,25 +30,6 @@ func ValidatePublicKey(k *ecdsa.PublicKey) bool { return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0 } -// BytesToUintLittleEndian converts the slice to 64-bit unsigned integer. -func BytesToUintLittleEndian(b []byte) (res uint64) { - mul := uint64(1) - for i := 0; i < len(b); i++ { - res += uint64(b[i]) * mul - mul *= 256 - } - return res -} - -// BytesToUintBigEndian converts the slice to 64-bit unsigned integer. -func BytesToUintBigEndian(b []byte) (res uint64) { - for i := 0; i < len(b); i++ { - res *= 256 - res += uint64(b[i]) - } - return res -} - // ContainsOnlyZeros checks if the data contain only zeros. func ContainsOnlyZeros(data []byte) bool { for _, b := range data { diff --git a/wakuv2/common/helpers_test.go b/messaging/waku/common/helpers_test.go similarity index 100% rename from wakuv2/common/helpers_test.go rename to messaging/waku/common/helpers_test.go diff --git a/wakuv2/common/message.go b/messaging/waku/common/message.go similarity index 100% rename from wakuv2/common/message.go rename to messaging/waku/common/message.go diff --git a/wakuv2/common/metrics.go b/messaging/waku/common/metrics.go similarity index 100% rename from wakuv2/common/metrics.go rename to messaging/waku/common/metrics.go diff --git a/wakuv2/common/topic.go b/messaging/waku/common/topic.go similarity index 96% rename from wakuv2/common/topic.go rename to messaging/waku/common/topic.go index 2eac3aa0b0..3bd6aa5b55 100644 --- a/wakuv2/common/topic.go +++ b/messaging/waku/common/topic.go @@ -63,11 +63,6 @@ func BytesToTopic(b []byte) (t TopicType) { return t } -func StringToTopic(s string) (t TopicType) { - str, _ := hexutil.Decode(s) - return BytesToTopic(str) -} - // String converts a topic byte array to a string representation. func (t *TopicType) String() string { return hexutil.Encode(t[:]) diff --git a/wakuv2/common/topic_test.go b/messaging/waku/common/topic_test.go similarity index 100% rename from wakuv2/common/topic_test.go rename to messaging/waku/common/topic_test.go diff --git a/wakuv2/config.go b/messaging/waku/config.go similarity index 94% rename from wakuv2/config.go rename to messaging/waku/config.go index ae2801421b..67004511a7 100644 --- a/wakuv2/config.go +++ b/messaging/waku/config.go @@ -27,7 +27,7 @@ import ( bindingscommon "github.com/waku-org/waku-go-bindings/waku/common" - "github.com/status-im/status-go/wakuv2/common" + "github.com/status-im/status-go/messaging/waku/common" ) var ( @@ -56,9 +56,7 @@ type Config struct { EnableStore bool `toml:",omitempty"` StoreCapacity int `toml:",omitempty"` StoreSeconds int `toml:",omitempty"` - TelemetryServerURL string `toml:",omitempty"` - TelemetrySendPeriodMs int `toml:",omitempty"` // Number of milliseconds to wait between sending requests to telemetry service - TelemetryPeerCountSendPeriod int `toml:",omitempty"` // Number of milliseconds to wait between checking peer count + MetricsEnabled bool `toml:",omitempty"` DefaultShardPubsubTopic string `toml:",omitempty"` // Pubsub topic to be used by default for messages that do not have a topic assigned (depending whether sharding is used or not) DefaultShardedPubsubTopics []string `toml:", omitempty"` ClusterID uint16 `toml:",omitempty"` diff --git a/wakuv2/const.go b/messaging/waku/const.go similarity index 100% rename from wakuv2/const.go rename to messaging/waku/const.go diff --git a/wakuv2/gowaku.go b/messaging/waku/gowaku.go similarity index 96% rename from wakuv2/gowaku.go rename to messaging/waku/gowaku.go index 85bf4c89da..e47ad350e0 100644 --- a/wakuv2/gowaku.go +++ b/messaging/waku/gowaku.go @@ -59,7 +59,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/rpc" "github.com/libp2p/go-libp2p" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -85,13 +84,13 @@ import ( gocommon "github.com/status-im/status-go/common" "github.com/status-im/status-go/connection" - ethtypes "github.com/status-im/status-go/eth-node/types" + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/internal/timesource" "github.com/status-im/status-go/logutils" - "github.com/status-im/status-go/timesource" - "github.com/status-im/status-go/wakuv2/common" - "github.com/status-im/status-go/wakuv2/persistence" - - "github.com/status-im/status-go/waku/types" + "github.com/status-im/status-go/messaging/waku/common" + "github.com/status-im/status-go/messaging/waku/persistence" + "github.com/status-im/status-go/messaging/waku/types" + ntptimesource "github.com/status-im/status-go/timesource" "github.com/waku-org/go-waku/waku/v2/node" "github.com/waku-org/go-waku/waku/v2/protocol/pb" @@ -117,7 +116,6 @@ type ErrorSendingEnvelope struct { } type IMetricsHandler interface { - SetDeviceType(deviceType string) PushSentEnvelope(sentEnvelope SentEnvelope) PushErrorSendingEnvelope(errorSendingEnvelope ErrorSendingEnvelope) PushPeerConnFailures(peerConnFailures map[string]int) @@ -126,7 +124,7 @@ type IMetricsHandler interface { PushPeerCountByShard(peerCountByShard map[uint16]uint) PushPeerCountByOrigin(peerCountByOrigin map[wps.Origin]uint) PushDialFailure(dialFailure common.DialError) - PushMissedMessage(envelope *protocol.Envelope) + PushMissedMessage(envelope common.Envelope) PushMissedRelevantMessage(message *common.ReceivedMessage) PushMessageDeliveryConfirmed() PushSentMessageTotal(messageSize uint32, publishMethod string) @@ -190,8 +188,7 @@ type Waku struct { logger *zap.Logger - // NTP Synced timesource - timesource *timesource.NTPTimeSource + timesource timesource.TimeSource // seededBootnodesForDiscV5 indicates whether we manage to retrieve discovery // bootnodes successfully @@ -227,7 +224,7 @@ func newTTLCache() *ttlcache.Cache[gethcommon.Hash, bool] { } // New creates a WakuV2 client ready to communicate through the LibP2P network. -func New(nodeKey *ecdsa.PrivateKey, cfg *Config, logger *zap.Logger, appDB *sql.DB, ts *timesource.NTPTimeSource, onHistoricMessagesRequestFailed func([]byte, peer.AddrInfo, error), onPeerStats func(types.ConnStatus)) (*Waku, error) { +func New(nodeKey *ecdsa.PrivateKey, cfg *Config, logger *zap.Logger, appDB *sql.DB, ts timesource.TimeSource, onHistoricMessagesRequestFailed func([]byte, peer.AddrInfo, error), onPeerStats func(types.ConnStatus)) (*Waku, error) { var err error if logger == nil { logger, err = zap.NewDevelopment() @@ -237,7 +234,7 @@ func New(nodeKey *ecdsa.PrivateKey, cfg *Config, logger *zap.Logger, appDB *sql. } if ts == nil { - ts = timesource.Default() + ts = ntptimesource.Default() } cfg = setDefaults(cfg) @@ -245,7 +242,7 @@ func New(nodeKey *ecdsa.PrivateKey, cfg *Config, logger *zap.Logger, appDB *sql. return nil, err } - logger.Info("starting wakuv2 with config", zap.Any("config", cfg)) + logger.Info("starting wakuv2") ctx, cancel := context.WithCancel(context.Background()) @@ -607,31 +604,6 @@ func (w *Waku) connect(peerInfo peer.AddrInfo, enr *enode.Node, origin wps.Origi w.node.AddDiscoveredPeer(peerInfo.ID, peerInfo.Addrs, origin, w.cfg.DefaultShardedPubsubTopics, enr, true) } -func (w *Waku) telemetryBandwidthStats(telemetryServerURL string) { - defer gocommon.LogOnPanic() - defer w.wg.Done() - - if telemetryServerURL == "" { - return - } - - telemetry := NewBandwidthTelemetryClient(w.logger, telemetryServerURL) - - ticker := time.NewTicker(time.Second * 20) - defer ticker.Stop() - - for { - select { - case <-w.ctx.Done(): - return - case <-ticker.C: - bandwidthPerProtocol := w.bandwidthCounter.GetBandwidthByProtocol() - w.bandwidthCounter.Reset() - go telemetry.PushProtocolStats(bandwidthPerProtocol) - } - } -} - func (w *Waku) GetStats() types.StatsSummary { stats := w.bandwidthCounter.GetBandwidthTotals() return types.StatsSummary{ @@ -768,18 +740,6 @@ func (w *Waku) CurrentTime() time.Time { return w.timesource.Now() } -// APIs returns the RPC descriptors the Waku implementation offers -func (w *Waku) APIs() []rpc.API { - return []rpc.API{ - { - Namespace: Name, - Version: VersionStr, - Service: NewPublicWakuAPI(w), - Public: false, - }, - } -} - func (w *Waku) SendEnvelopeEvent(event common.EnvelopeEvent) int { return w.envelopeFeed.Send(event) } @@ -1106,10 +1066,9 @@ func (w *Waku) OnNewEnvelope(env *protocol.Envelope) error { return w.OnNewEnvelopes(env, common.RelayedMessageType, false) } -// Start implements node.Service, starting the background data propagation thread -// of the Waku protocol. +// Starts the background data propagation thread of the Waku protocol. func (w *Waku) Start() error { - if w.ctx == nil { + if w.cancel == nil { w.ctx, w.cancel = context.WithCancel(context.Background()) } @@ -1160,15 +1119,12 @@ func (w *Waku) Start() error { } }() - if w.cfg.TelemetryServerURL != "" { + if w.cfg.MetricsEnabled { w.wg.Add(1) go func() { defer gocommon.LogOnPanic() defer w.wg.Done() - peerTelemetryTickerInterval := time.Duration(w.cfg.TelemetryPeerCountSendPeriod) * time.Millisecond - if peerTelemetryTickerInterval == 0 { - peerTelemetryTickerInterval = 10 * time.Second - } + peerTelemetryTickerInterval := 10 * time.Second peerTelemetryTicker := time.NewTicker(peerTelemetryTickerInterval) defer peerTelemetryTicker.Stop() @@ -1208,11 +1164,6 @@ func (w *Waku) Start() error { }() } - w.wg.Add(1) - go w.telemetryBandwidthStats(w.cfg.TelemetryServerURL) - //TODO: commenting for now so that only fleet nodes are used. - //Need to uncomment once filter peer scoring etc is implemented. - w.wg.Add(1) go w.runPeerExchangeLoop() @@ -1372,7 +1323,7 @@ func (w *Waku) startMessageSender() error { return err } - if w.cfg.TelemetryServerURL != "" { + if w.cfg.MetricsEnabled { sender.WithMessageSentEmitter(w.node.Host()) } @@ -1465,10 +1416,17 @@ func (w *Waku) setupRelaySubscriptions() error { return nil } -// Stop implements node.Service, stopping the background data propagation thread -// of the Waku protocol. +// Stops the background data propagation thread of the Waku protocol. func (w *Waku) Stop() error { + // never started || already stopped + if w.node == nil || w.cancel == nil { + return nil + } + w.cancel() + defer func() { + w.cancel = nil + }() w.envelopeCache.Stop() @@ -1484,8 +1442,7 @@ func (w *Waku) Stop() error { close(w.goingOnline) w.wg.Wait() - w.ctx = nil - w.cancel = nil + _ = w.logger.Sync() return nil } @@ -1502,7 +1459,8 @@ func (w *Waku) OnNewEnvelopes(envelope *protocol.Envelope, msgType common.Messag if w.metricsHandler != nil { if msgType == common.MissingMessageType { - w.metricsHandler.PushMissedMessage(envelope) + commonEnv := common.NewWakuEnvelope(envelope.Message(), envelope.PubsubTopic(), envelope.Hash()) + w.metricsHandler.PushMissedMessage(commonEnv) } } @@ -1587,9 +1545,6 @@ func (w *Waku) postEvent(envelope *common.ReceivedMessage) { func (w *Waku) processQueueLoop() { defer gocommon.LogOnPanic() defer w.wg.Done() - if w.ctx == nil { - return - } for { select { case <-w.ctx.Done(): @@ -1640,7 +1595,7 @@ func (w *Waku) processMessage(e *common.ReceivedMessage) { } // HasEnvelope returns true if the envelope with the given hash is present in the cache. -func (w *Waku) HasEnvelope(hash ethtypes.Hash) bool { +func (w *Waku) HasEnvelope(hash cryptotypes.Hash) bool { w.poolMu.RLock() defer w.poolMu.RUnlock() @@ -2176,3 +2131,9 @@ func (w *Waku) Subscribe(opts *types.SubscriptionOptions) (string, error) { func (w *Waku) Version() uint { return 2 } + +// This function is needed for nwaku, adding here for compatibility +func (w *Waku) Metrics() string { + + return "" +} diff --git a/wakuv2/gowaku_test.go b/messaging/waku/gowaku_test.go similarity index 100% rename from wakuv2/gowaku_test.go rename to messaging/waku/gowaku_test.go diff --git a/wakuv2/history_processor_wrapper.go b/messaging/waku/history_processor_wrapper.go similarity index 92% rename from wakuv2/history_processor_wrapper.go rename to messaging/waku/history_processor_wrapper.go index 5f67ea8623..39d675b030 100644 --- a/wakuv2/history_processor_wrapper.go +++ b/messaging/waku/history_processor_wrapper.go @@ -6,7 +6,7 @@ import ( "github.com/waku-org/go-waku/waku/v2/api/history" "github.com/waku-org/go-waku/waku/v2/protocol" - "github.com/status-im/status-go/wakuv2/common" + "github.com/status-im/status-go/messaging/waku/common" ) type HistoryProcessorWrapper struct { diff --git a/wakuv2/message_publishing.go b/messaging/waku/message_publishing.go similarity index 98% rename from wakuv2/message_publishing.go rename to messaging/waku/message_publishing.go index c242adb4df..300520620a 100644 --- a/wakuv2/message_publishing.go +++ b/messaging/waku/message_publishing.go @@ -12,7 +12,7 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" gocommon "github.com/status-im/status-go/common" - "github.com/status-im/status-go/wakuv2/common" + "github.com/status-im/status-go/messaging/waku/common" ) // Send injects a message into the waku send queue, to be distributed in the diff --git a/wakuv2/nwaku.go b/messaging/waku/nwaku.go similarity index 66% rename from wakuv2/nwaku.go rename to messaging/waku/nwaku.go index 54148967a4..6b29fcf4ad 100644 --- a/wakuv2/nwaku.go +++ b/messaging/waku/nwaku.go @@ -13,6 +13,7 @@ import ( "encoding/hex" "errors" "fmt" + "math" "net" "runtime" "strings" @@ -49,20 +50,20 @@ import ( "github.com/waku-org/go-waku/waku/v2/peermanager" wps "github.com/waku-org/go-waku/waku/v2/peerstore" "github.com/waku-org/go-waku/waku/v2/protocol" + gowakutimesource "github.com/waku-org/go-waku/waku/v2/timesource" - "github.com/waku-org/go-waku/waku/v2/protocol/legacy_store" "github.com/waku-org/go-waku/waku/v2/protocol/relay" "github.com/waku-org/go-waku/waku/v2/protocol/store" - "github.com/waku-org/go-waku/waku/v2/utils" gocommon "github.com/status-im/status-go/common" "github.com/status-im/status-go/connection" - ethtypes "github.com/status-im/status-go/eth-node/types" + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/internal/timesource" "github.com/status-im/status-go/logutils" - "github.com/status-im/status-go/timesource" - "github.com/status-im/status-go/waku/types" - "github.com/status-im/status-go/wakuv2/common" - "github.com/status-im/status-go/wakuv2/persistence" + "github.com/status-im/status-go/messaging/waku/common" + "github.com/status-im/status-go/messaging/waku/persistence" + "github.com/status-im/status-go/messaging/waku/types" + ntptimesource "github.com/status-im/status-go/timesource" "github.com/waku-org/waku-go-bindings/waku" bindingscommon "github.com/waku-org/waku-go-bindings/waku/common" @@ -90,20 +91,15 @@ type ErrorSendingEnvelope struct { SentEnvelope SentEnvelope } +// Waku node metrics will be collected by the node and not by status-go type IMetricsHandler interface { - SetDeviceType(deviceType string) PushSentEnvelope(sentEnvelope SentEnvelope) PushErrorSendingEnvelope(errorSendingEnvelope ErrorSendingEnvelope) - PushPeerConnFailures(peerConnFailures map[string]int) PushMessageCheckSuccess() PushMessageCheckFailure() - PushPeerCountByShard(peerCountByShard map[uint16]uint) - PushPeerCountByOrigin(peerCountByOrigin map[wps.Origin]uint) - PushDialFailure(dialFailure common.DialError) - PushMissedMessage(envelope *protocol.Envelope) + PushMissedMessage(envelope common.Envelope) PushMissedRelevantMessage(message *common.ReceivedMessage) PushMessageDeliveryConfirmed() - PushSentMessageTotal(messageSize uint32, publishMethod string) PushRawMessageByType(pubsubTopic string, contentTopic string, messageType string, messageSize uint32) } @@ -166,8 +162,7 @@ type Waku struct { logger *zap.Logger - // NTP Synced timesource - timesource *timesource.NTPTimeSource + timesource gowakutimesource.Timesource // seededBootnodesForDiscV5 indicates whether we manage to retrieve discovery // bootnodes successfully @@ -187,6 +182,15 @@ type Waku struct { defaultShardInfo protocol.RelayShards } +// timesource provided in constructor is managed by status-go; go-waku must not invoke Start or Stop. +// The adapter only fulfills the required interface; Start and Stop are no-ops. +type timesourceAdapter struct { + timesource.TimeSource +} + +func (t timesourceAdapter) Start(ctx context.Context) error { return nil } +func (t timesourceAdapter) Stop() {} + var _ types.Waku = (*Waku)(nil) func (w *Waku) SetMetricsHandler(client IMetricsHandler) { @@ -203,132 +207,88 @@ func newTTLCache() *ttlcache.Cache[gethcommon.Hash, bool] { } // New creates a WakuV2 client ready to communicate through the LibP2P network. -func New(nodeKey *ecdsa.PrivateKey, cfg *Config, logger *zap.Logger, appDB *sql.DB, ts *timesource.NTPTimeSource, onHistoricMessagesRequestFailed func([]byte, peer.AddrInfo, error), onPeerStats func(types.ConnStatus)) (*Waku, error) { - node, err := wakuNew(nodeKey, - cfg, - logger, appDB, ts, onHistoricMessagesRequestFailed, - onPeerStats) - if err != nil { - return nil, err - } - - return node, nil - - // TODO-nwaku - /* - cfg = setDefaults(cfg) - if err = cfg.Validate(logger); err != nil { +func New(nodeKey *ecdsa.PrivateKey, cfg *Config, logger *zap.Logger, appDB *sql.DB, ts timesource.TimeSource, onHistoricMessagesRequestFailed func([]byte, peer.AddrInfo, error), onPeerStats func(types.ConnStatus)) (*Waku, error) { + var err error + if logger == nil { + logger, err = zap.NewDevelopment() + if err != nil { return nil, err } + } - logger.Info("starting wakuv2 with config", zap.Any("config", cfg)) - - ctx, cancel := context.WithCancel(context.Background()) - - waku := &Waku{ - appDB: appDB, - cfg: cfg, - privateKeys: make(map[string]*ecdsa.PrivateKey), - symKeys: make(map[string][]byte), - envelopeCache: newTTLCache(), - msgQueue: make(chan *common.ReceivedMessage, messageQueueLimit), - topicHealthStatusChan: make(chan peermanager.TopicHealthStatus, 100), - connectionNotifChan: make(chan node.PeerConnection, 20), - connStatusSubscriptions: make(map[string]*types.ConnStatusSubscription), - ctx: ctx, - cancel: cancel, - wg: sync.WaitGroup{}, - dnsAddressCache: make(map[string][]dnsdisc.DiscoveredNode), - dnsAddressCacheLock: &sync.RWMutex{}, - dnsDiscAsyncRetrievedSignal: make(chan struct{}), - storeMsgIDs: make(map[gethcommon.Hash]bool), - timesource: ts, - storeMsgIDsMu: sync.RWMutex{}, - logger: logger, - discV5BootstrapNodes: cfg.DiscV5BootstrapNodes, - onHistoricMessagesRequestFailed: onHistoricMessagesRequestFailed, - onPeerStats: onPeerStats, - onlineChecker: onlinechecker.NewDefaultOnlineChecker(false).(*onlinechecker.DefaultOnlineChecker), - sendQueue: publish.NewMessageQueue(1000, cfg.UseThrottledPublish), - } + var timesource gowakutimesource.Timesource + if ts != nil { + timesource = timesourceAdapter{ts} + } else { + timesource = ntptimesource.Default() + } - waku.bandwidthCounter = metrics.NewBandwidthCounter() - - libp2pOpts := node.DefaultLibP2POptions - libp2pOpts = append(libp2pOpts, libp2p.BandwidthReporter(waku.bandwidthCounter)) - libp2pOpts = append(libp2pOpts, libp2p.NATPortMap()) - - opts := []node.WakuNodeOption{ - node.WithLibP2POptions(libp2pOpts...), - node.WithPrivateKey(nodeKey), - node.WithHostAddress(hostAddr), - node.WithConnectionNotification(waku.connectionNotifChan), - node.WithTopicHealthStatusChannel(waku.topicHealthStatusChan), - node.WithKeepAlive(randomPeersKeepAliveInterval, allPeersKeepAliveInterval), - node.WithLogger(logger), - node.WithLogLevel(logger.Level()), - node.WithClusterID(cfg.ClusterID), - node.WithMaxMsgSize(1024 * 1024), - node.WithPrometheusRegisterer(prometheus.DefaultRegisterer), - } + cfg = setDefaults(cfg) + if err = cfg.Validate(logger); err != nil { + return nil, err + } - if cfg.EnableDiscV5 { - bootnodes, err := waku.getDiscV5BootstrapNodes(waku.ctx, cfg.DiscV5BootstrapNodes, false) - if err != nil { - logger.Error("failed to get bootstrap nodes", zap.Error(err)) - return nil, err - } - opts = append(opts, node.WithDiscoveryV5(uint(cfg.UDPPort), bootnodes, cfg.AutoUpdate)) - } - shards, err := protocol.TopicsToRelayShards(cfg.DefaultShardPubsubTopic) + if nodeKey == nil { + // No nodekey is provided, create an ephemeral key + nodeKey, err = crypto.GenerateKey() if err != nil { - logger.Error("FATAL ERROR: failed to parse relay shards", zap.Error(err)) - return nil, errors.New("failed to parse relay shard, invalid pubsubTopic configuration") - } - if len(shards) == 0 { //Hack so that tests don't fail. TODO: Need to remove this once tests are changed to use proper cluster and shard. - shardInfo := protocol.RelayShards{ClusterID: 0, ShardIDs: []uint16{0}} - shards = append(shards, shardInfo) + return nil, fmt.Errorf("failed to generate a random go-waku private key: %v", err) } - waku.defaultShardInfo = shards[0] - if cfg.LightClient { - opts = append(opts, node.WithWakuFilterLightNode()) - waku.defaultShardInfo = shards[0] - opts = append(opts, node.WithMaxPeerConnections(cfg.DiscoveryLimit)) - cfg.EnableStoreConfirmationForMessagesSent = false - //TODO: temporary work-around to improve lightClient connectivity, need to be removed once community sharding is implemented - opts = append(opts, node.WithShards(waku.defaultShardInfo.ShardIDs)) - } else { - relayOpts := []pubsub.Option{ - pubsub.WithMaxMessageSize(int(waku.cfg.MaxMessageSize)), - } + } - if testing.Testing() { - relayOpts = append(relayOpts, pubsub.WithEventTracer(waku)) - } + // TODO: once we remove go-waku, get rid of the conversion + nwakuCfg := gowakuToNwakuConfig(cfg, logger) + nwakuCfg.Nodekey = hex.EncodeToString(crypto.FromECDSA(nodeKey)) - opts = append(opts, node.WithWakuRelayAndMinPeers(waku.cfg.MinPeersForRelay, relayOpts...)) - opts = append(opts, node.WithMaxPeerConnections(maxRelayPeers)) - cfg.EnablePeerExchangeClient = true //Enabling this until discv5 issues are resolved. This will enable more peers to be connected for relay mesh. - cfg.EnableStoreConfirmationForMessagesSent = true - } + nwakuCfg.TcpPort, nwakuCfg.Discv5UdpPort, err = getFreePortIfNeeded(nwakuCfg.TcpPort, nwakuCfg.Discv5UdpPort, logger) + if err != nil { + return nil, err + } - if cfg.EnableStore { - if appDB == nil { - return nil, errors.New("appDB is required for store") - } - opts = append(opts, node.WithWakuStore()) - dbStore, err := persistence.NewDBStore(logger, persistence.WithDB(appDB), persistence.WithRetentionPolicy(cfg.StoreCapacity, time.Duration(cfg.StoreSeconds)*time.Second)) - if err != nil { - return nil, err - } - opts = append(opts, node.WithMessageProvider(dbStore)) - } + logger.Info("starting wakuv2") + + ctx, cancel := context.WithCancel(context.Background()) + + wakunode, err := waku.NewWakuNode(nwakuCfg, "nwaku") + if err != nil { + cancel() + return nil, err + } + + waku := &Waku{ + node: wakunode, + appDB: appDB, + cfg: cfg, + privateKeys: make(map[string]*ecdsa.PrivateKey), + symKeys: make(map[string][]byte), + envelopeCache: newTTLCache(), + msgQueue: make(chan *common.ReceivedMessage, messageQueueLimit), + topicHealthStatusChan: make(chan peermanager.TopicHealthStatus, 100), + connectionNotifChan: make(chan node.PeerConnection, 20), + connStatusSubscriptions: make(map[string]*types.ConnStatusSubscription), + ctx: ctx, + cancel: cancel, + wg: sync.WaitGroup{}, + dnsAddressCache: make(map[string][]dnsdisc.DiscoveredNode), + dnsAddressCacheLock: &sync.RWMutex{}, + dnsDiscAsyncRetrievedSignal: make(chan struct{}), + storeMsgIDs: make(map[gethcommon.Hash]bool), + timesource: timesource, + storeMsgIDsMu: sync.RWMutex{}, + logger: logger, + discV5BootstrapNodes: cfg.DiscV5BootstrapNodes, + onHistoricMessagesRequestFailed: onHistoricMessagesRequestFailed, + onPeerStats: onPeerStats, + onlineChecker: onlinechecker.NewDefaultOnlineChecker(false).(*onlinechecker.DefaultOnlineChecker), + sendQueue: publish.NewMessageQueue(1000, cfg.UseThrottledPublish), + } - waku.options = opts + waku.filters = common.NewFilters(waku.cfg.DefaultShardPubsubTopic, waku.logger) + waku.bandwidthCounter = metrics.NewBandwidthCounter() - waku.logger.Info("setup the go-waku node successfully") + cfg.EnableStoreConfirmationForMessagesSent = !cfg.LightClient - return waku, nil*/ + return waku, nil } func (w *Waku) SubscribeToConnStatusChanges() (*types.ConnStatusSubscription, error) { @@ -353,143 +313,7 @@ func (w *Waku) GetNodeENRString() (string, error) { return enr.String(), nil } -/* TODO-nwaku* (this logic should be directly in nwaku?) -func (w *Waku) getDiscV5BootstrapNodes(ctx context.Context, addresses []string, useOnlyDnsDiscCache bool) ([]*enode.Node, error) { - wg := sync.WaitGroup{} - mu := sync.Mutex{} - var result []*enode.Node - - w.seededBootnodesForDiscV5 = true - - retrieveENR := func(d dnsdisc.DiscoveredNode, wg *sync.WaitGroup) { - mu.Lock() - defer mu.Unlock() - defer wg.Done() - if d.ENR != nil { - result = append(result, d.ENR) - } - } - - for _, addrString := range addresses { - if addrString == "" { - continue - } - - if strings.HasPrefix(addrString, "enrtree://") { - // Use DNS Discovery - wg.Add(1) - go func(addr string) { - defer gocommon.LogOnPanic() - defer wg.Done() - if err := w.dnsDiscover(ctx, addr, retrieveENR, useOnlyDnsDiscCache); err != nil { - // prevent w.ctx in retryDnsDiscoveryWithBackoff from set to nil when w.Stop() is called - w.wg.Add(1) - go func() { - defer gocommon.LogOnPanic() - defer w.wg.Done() - w.retryDnsDiscoveryWithBackoff(ctx, addr, w.dnsDiscAsyncRetrievedSignal) - }() - } - }(addrString) - } else { - // It's a normal enr - bootnode, err := enode.Parse(enode.ValidSchemes, addrString) - if err != nil { - return nil, err - } - mu.Lock() - result = append(result, bootnode) - mu.Unlock() - } - } - wg.Wait() - - if len(result) == 0 { - w.seededBootnodesForDiscV5 = false - } - - return result, nil -} - -type fnApplyToEachPeer func(d dnsdisc.DiscoveredNode, wg *sync.WaitGroup) - -func (w *Waku) dnsDiscover(ctx context.Context, enrtreeAddress string, apply fnApplyToEachPeer, useOnlyCache bool) error { - w.logger.Info("retrieving nodes", zap.String("enr", enrtreeAddress)) - ctx, cancel := context.WithTimeout(ctx, requestTimeout) - defer cancel() - - w.dnsAddressCacheLock.Lock() - defer w.dnsAddressCacheLock.Unlock() - - discNodes, ok := w.dnsAddressCache[enrtreeAddress] - if !ok && !useOnlyCache { - nameserver := w.cfg.Nameserver - resolver := w.cfg.Resolver - - var opts []dnsdisc.DNSDiscoveryOption - if nameserver != "" { - opts = append(opts, dnsdisc.WithNameserver(nameserver)) - } - if resolver != nil { - opts = append(opts, dnsdisc.WithResolver(resolver)) - } - - discoveredNodes, err := dnsdisc.RetrieveNodes(ctx, enrtreeAddress, opts...) - if err != nil { - w.logger.Warn("dns discovery error ", zap.Error(err)) - return err - } - - if len(discoveredNodes) != 0 { - w.dnsAddressCache[enrtreeAddress] = append(w.dnsAddressCache[enrtreeAddress], discoveredNodes...) - discNodes = w.dnsAddressCache[enrtreeAddress] - } - } - - wg := &sync.WaitGroup{} - wg.Add(len(discNodes)) - for _, d := range discNodes { - apply(d, wg) - } - wg.Wait() - - return nil -} - -func (w *Waku) retryDnsDiscoveryWithBackoff(ctx context.Context, addr string, successChan chan<- struct{}) { - retries := 0 - applyFn := func(_ dnsdisc.DiscoveredNode, wg *sync.WaitGroup) { - wg.Done() - } - for { - err := w.dnsDiscover(ctx, addr, applyFn, false) - if err == nil { - select { - case successChan <- struct{}{}: - default: - } - - break - } - - retries++ - backoff := time.Second * time.Duration(math.Exp2(float64(retries))) - if backoff > time.Minute { - backoff = time.Minute - } - - t := time.NewTimer(backoff) - select { - case <-w.ctx.Done(): - t.Stop() - return - case <-t.C: - t.Stop() - } - } -} -*/ - +// TODO-nwaku maybe eventually remove as nwaku should do it func (w *Waku) discoverAndConnectPeers() { var addrsToConnect []multiaddr.Multiaddr nameserver := w.cfg.Nameserver @@ -536,11 +360,6 @@ func (w *Waku) connect(peerInfo peer.AddrInfo, enr *enode.Node, origin wps.Origi // Connection will be prunned eventually by the connection manager if needed // The peer connector in go-waku uses Connect, so it will execute identify as part of its - // TODO-nwaku - // TODO: is enr and origin required? - // TODO: this function is meant to add a node to a peer store so it can be picked up by the peer manager - // so probably we shouldn't connect directly but expose an AddPeer function in libwaku - ctx, cancel := context.WithTimeout(w.ctx, requestTimeout) defer cancel() @@ -551,97 +370,13 @@ func (w *Waku) connect(peerInfo peer.AddrInfo, enr *enode.Node, origin wps.Origi } } -/* TODO-nwaku - implement when metrics are supported -func (w *Waku) telemetryBandwidthStats(telemetryServerURL string) { - defer gocommon.LogOnPanic() - defer w.wg.Done() - - if telemetryServerURL == "" { - return - } - - telemetry := NewBandwidthTelemetryClient(w.logger, telemetryServerURL) - - ticker := time.NewTicker(time.Second * 20) - defer ticker.Stop() - - for { - select { - case <-w.ctx.Done(): - return - case <-ticker.C: - bandwidthPerProtocol := w.bandwidthCounter.GetBandwidthByProtocol() - w.bandwidthCounter.Reset() - go telemetry.PushProtocolStats(bandwidthPerProtocol) - } - } -} -*/ - -// TODO-nwaku - implement when metrics are supported func (w *Waku) GetStats() types.StatsSummary { - return types.StatsSummary{ - UploadRate: uint64(1), - DownloadRate: uint64(1), - } - /* TODO-nwaku stats := w.bandwidthCounter.GetBandwidthTotals() return types.StatsSummary{ UploadRate: uint64(stats.RateOut), DownloadRate: uint64(stats.RateIn), - } */ -} - -/* TODO-nwaku* (this logic should be directly in nwaku?) -func (w *Waku) runPeerExchangeLoop() { - defer gocommon.LogOnPanic() - defer w.wg.Done() - - if !w.cfg.EnablePeerExchangeClient { - // Currently peer exchange client is only used for light nodes - return - } - - ticker := time.NewTicker(time.Second * 5) - defer ticker.Stop() - - for { - select { - case <-w.ctx.Done(): - w.logger.Debug("Peer exchange loop stopped") - return - case <-ticker.C: - w.logger.Info("Running peer exchange loop") - - // We select only the nodes discovered via DNS Discovery that support peer exchange - // We assume that those peers are running peer exchange according to infra config, - // If not, the peer selection process in go-waku will filter them out anyway - w.dnsAddressCacheLock.RLock() - var peers peer.IDSlice - for _, record := range w.dnsAddressCache { - for _, discoveredNode := range record { - if len(discoveredNode.PeerInfo.Addrs) == 0 { - continue - } - // Attempt to connect to the peers. - // Peers will be added to the libp2p peer store thanks to identify - go w.connect(discoveredNode.PeerInfo, discoveredNode.ENR, wps.DNSDiscovery) - peers = append(peers, discoveredNode.PeerID) - } - } - w.dnsAddressCacheLock.RUnlock() - - if len(peers) != 0 { - err := w.node.PeerExchange().Request(w.ctx, w.cfg.DiscoveryLimit, peer_exchange.WithAutomaticPeerSelection(peers...), - peer_exchange.FilterByShard(int(w.defaultShardInfo.ClusterID), int(w.defaultShardInfo.ShardIDs[0]))) - if err != nil { - w.logger.Error("couldnt request peers via peer exchange", zap.Error(err)) - } - } - } } } -*/ func (w *Waku) GetPubsubTopic(topic string) string { if topic == "" { @@ -1077,9 +812,8 @@ func (w *Waku) Start() error { w.ctx, w.cancel = context.WithCancel(context.Background()) } - /* TODO-nwaku w.goingOnline = make(chan struct{}) - */ + w.StorenodeCycle = history.NewStorenodeCycle(w.logger, newPinger(w.node)) w.HistoryRetriever = history.NewHistoryRetriever(newStorenodeRequestor(w.node, w.logger), NewHistoryProcessorWrapper(w), w.logger) w.StorenodeCycle.Start(w.ctx) @@ -1091,15 +825,8 @@ func (w *Waku) Start() error { w.logger.Info("WakuV2 PeerID", zap.Stringer("id", peerID)) - /* TODO-nwaku - w.discoverAndConnectPeers() - - if w.cfg.EnableDiscV5 { - err := w.node.DiscV5().Start(w.ctx) - if err != nil { - return err - } - } + w.discoverAndConnectPeers() // TODO-nwaku: maybe eventually remove? we can pass cfg.WakuNodes as static nodes to nwaku config + // but we need to support in nwaku enrtree resolution for staticnodes and not only multiaddresses w.wg.Add(1) go func() { @@ -1113,71 +840,14 @@ func (w *Waku) Start() error { return case <-ticker.C: w.checkForConnectionChanges() - case <-w.topicHealthStatusChan: + case <-w.node.TopicHealthChan: // TODO: https://github.com/status-im/status-go/issues/4628 - case <-w.connectionNotifChan: + case <-w.node.ConnectionChangeChan: w.checkForConnectionChanges() } } }() - if w.cfg.TelemetryServerURL != "" { - w.wg.Add(1) - go func() { - defer gocommon.LogOnPanic() - defer w.wg.Done() - peerTelemetryTickerInterval := time.Duration(w.cfg.TelemetryPeerCountSendPeriod) * time.Millisecond - if peerTelemetryTickerInterval == 0 { - peerTelemetryTickerInterval = 10 * time.Second - } - peerTelemetryTicker := time.NewTicker(peerTelemetryTickerInterval) - defer peerTelemetryTicker.Stop() - - dialErrSub, err := w.node.Host().EventBus().Subscribe(new(utils.DialError)) - if err != nil { - w.logger.Error("failed to subscribe to dial errors", zap.Error(err)) - return - } - defer dialErrSub.Close() - - messageSentSub, err := w.node.Host().EventBus().Subscribe(new(publish.MessageSent)) - if err != nil { - w.logger.Error("failed to subscribe to message sent events", zap.Error(err)) - return - } - - publishMethod := "relay" - if w.cfg.LightClient { - publishMethod = "lightpush" - } - - for { - select { - case <-w.ctx.Done(): - return - case <-peerTelemetryTicker.C: - w.reportPeerMetrics() - case dialErr := <-dialErrSub.Out(): - errors := common.ParseDialErrors(dialErr.(utils.DialError).Err.Error()) - for _, dialError := range errors { - w.metricsHandler.PushDialFailure(common.DialError{ErrType: dialError.ErrType, ErrMsg: dialError.ErrMsg, Protocols: dialError.Protocols}) - } - case messageSent := <-messageSentSub.Out(): - w.metricsHandler.PushSentMessageTotal(messageSent.(publish.MessageSent).Size, publishMethod) - } - } - }() - } - - w.wg.Add(1) - go w.telemetryBandwidthStats(w.cfg.TelemetryServerURL) - //TODO: commenting for now so that only fleet nodes are used. - //Need to uncomment once filter peer scoring etc is implemented. - - w.wg.Add(1) - go w.runPeerExchangeLoop() - */ - if w.cfg.EnableMissingMessageVerification { w.missingMsgVerifier = missing.NewMissingMessageVerifier( newStorenodeRequestor(w.node, w.logger), @@ -1243,25 +913,28 @@ func (w *Waku) Start() error { return err } - /* TODO-nwaku - // we should wait `seedBootnodesForDiscV5` shutdown smoothly before set w.ctx to nil within `w.Stop()` - w.wg.Add(1) - go w.seedBootnodesForDiscV5() - */ - return nil } func (w *Waku) checkForConnectionChanges() { - /* TODO-nwaku - isOnline := len(w.node.Host().Network().Peers()) > 0 + isOnline, err := w.node.IsOnline() + + if err != nil { + panic(err) + } w.connStatusMu.Lock() + peerStats, err := FormatPeerStats(w.node) + + if err != nil { + panic(err) + } + latestConnStatus := types.ConnStatus{ IsOnline: isOnline, - Peers: FormatPeerStats(w.node), + Peers: peerStats, } w.logger.Debug("peer stats", @@ -1282,51 +955,8 @@ func (w *Waku) checkForConnectionChanges() { w.ConnectionChanged(connection.State{ Type: w.state.Type, //setting state type as previous one since there won't be a change here Offline: !latestConnStatus.IsOnline, - }) */ -} - -/* TODO-nwaku - implement when metrics are supported -func (w *Waku) reportPeerMetrics() { - if w.metricsHandler != nil { - connFailures := FormatPeerConnFailures(w.node) - w.metricsHandler.PushPeerConnFailures(connFailures) - - peerCountByOrigin := make(map[wps.Origin]uint) - peerCountByShard := make(map[uint16]uint) - wakuPeerStore := w.node.Host().Peerstore().(wps.WakuPeerstore) - - for _, peerID := range w.node.Host().Network().Peers() { - origin, err := wakuPeerStore.Origin(peerID) - if err != nil { - origin = wps.Unknown - } - - peerCountByOrigin[origin]++ - pubsubTopics, err := wakuPeerStore.PubSubTopics(peerID) - if err != nil { - continue - } - - keys := make([]string, 0, len(pubsubTopics)) - for k := range pubsubTopics { - keys = append(keys, k) - } - relayShards, err := protocol.TopicsToRelayShards(keys...) - if err != nil { - continue - } - - for _, shards := range relayShards { - for _, shard := range shards.ShardIDs { - peerCountByShard[shard]++ - } - } - } - w.metricsHandler.PushPeerCountByShard(peerCountByShard) - w.metricsHandler.PushPeerCountByOrigin(peerCountByOrigin) - } + }) } -*/ func (w *Waku) startMessageSender() error { publishMethod := publish.Relay @@ -1340,11 +970,6 @@ func (w *Waku) startMessageSender() error { return err } - /* TODO-nwaku - check what WithMessageSentEmitter does - if w.cfg.TelemetryServerURL != "" { - sender.WithMessageSentEmitter(w.node.Host()) - } */ - if w.cfg.EnableStoreConfirmationForMessagesSent { msgStoredChan := make(chan gethcommon.Hash, 1000) msgExpiredChan := make(chan gethcommon.Hash, 1000) @@ -1454,8 +1079,7 @@ func (w *Waku) Stop() error { } } - /* TODO-nwaku - close(w.goingOnline)*/ + close(w.goingOnline) w.wg.Wait() @@ -1475,13 +1099,11 @@ func (w *Waku) OnNewEnvelopes(envelope common.Envelope, msgType common.MessageTy return nil } - /* TODO-nwaku - implement when metrics are supported if w.metricsHandler != nil { if msgType == common.MissingMessageType { w.metricsHandler.PushMissedMessage(envelope) } } - */ logger := w.logger.With( zap.String("messageType", msgType), @@ -1617,7 +1239,7 @@ func (w *Waku) processMessage(e *common.ReceivedMessage) { } // HasEnvelope returns true if the envelope with the given hash is present in the cache. -func (w *Waku) HasEnvelope(hash ethtypes.Hash) bool { +func (w *Waku) HasEnvelope(hash cryptotypes.Hash) bool { w.poolMu.RLock() defer w.poolMu.RUnlock() @@ -1648,23 +1270,38 @@ func (w *Waku) PeerCount() int { return numPeers } -// TODO-nwaku func (w *Waku) Peers() types.PeerStats { - return nil - // return FormatPeerStats(w.node) + peerStats, err := FormatPeerStats(w.node) + + if err != nil { + panic(err) + } + + return peerStats } func (w *Waku) RelayPeersByTopic(topic string) (*types.PeerList, error) { - /* TODO-nwaku + if w.cfg.LightClient { return nil, errors.New("only available in relay mode") } + allPeers, err := w.node.GetConnectedRelayPeers(topic) + + if err != nil { + return nil, err + } + + fullMeshPeers, err := w.node.GetPeersInMesh(topic) + + if err != nil { + return nil, err + } + return &types.PeerList{ - FullMeshPeers: w.node.Relay().PubSub().MeshPeers(topic), - AllPeers: w.node.Relay().PubSub().ListPeers(topic), + FullMeshPeers: allPeers, + AllPeers: fullMeshPeers, }, nil - */ - return &types.PeerList{}, nil + } func (w *Waku) ENR() (*enode.Node, error) { @@ -1731,21 +1368,37 @@ func (w *Waku) StopDiscV5() error { } func (w *Waku) handleNetworkChangeFromApp(state connection.State) { - // TODO-nwaku - /* - //If connection state is reported by something other than peerCount becoming 0 e.g from mobile app, disconnect all peers - if (state.Offline && len(w.node.Host().Network().Peers()) > 0) || - (w.state.Type != state.Type && !w.state.Offline && !state.Offline) { // network switched between wifi and cellular - w.logger.Info("connection switched or offline detected via mobile, disconnecting all peers") - w.node.DisconnectAllPeers() - if w.cfg.LightClient { - w.filterManager.NetworkChange() - } - } - */ + + networkChange := false + + //If connection state is reported by something other than peerCount becoming 0 e.g from mobile app, disconnect all peers + if state.Offline && w.PeerCount() > 0 { + networkChange = true + w.logger.Info("offline detected via mobile, disconnecting all peers") + } + + // network switched between wifi and cellular + if w.state.Type != state.Type && !w.state.Offline && !state.Offline { + networkChange = true + w.logger.Info("connection switched, disconnecting all peers") + } + + if !networkChange { + return + } + + err := w.node.DisconnectAllPeers() + + if err != nil { + panic(err) + } + + if w.cfg.LightClient { + w.filterManager.NetworkChange() + } + } -/* TODO-nwaku func (w *Waku) isGoingOnline(state connection.State) bool { return !state.Offline && !w.onlineChecker.IsOnline() } @@ -1753,10 +1406,8 @@ func (w *Waku) isGoingOnline(state connection.State) bool { func (w *Waku) isGoingOffline(state connection.State) bool { return state.Offline && w.onlineChecker.IsOnline() } -*/ func (w *Waku) ConnectionChanged(state connection.State) { - /* TODO-nwaku if w.isGoingOnline(state) { w.discoverAndConnectPeers() if w.cfg.EnableMissingMessageVerification { @@ -1789,139 +1440,8 @@ func (w *Waku) ConnectionChanged(state connection.State) { // update state w.onlineChecker.SetOnline(isOnline) w.state = state - */ -} - -/* TODO-nwaku -// seedBootnodesForDiscV5 tries to fetch bootnodes -// from an ENR periodically. -// It backs off exponentially until maxRetries, at which point it restarts from 0 -// It also restarts if there's a connection change signalled from the client -func (w *Waku) seedBootnodesForDiscV5() { - defer gocommon.LogOnPanic() - defer w.wg.Done() - - if !w.cfg.EnableDiscV5 || w.node.DiscV5() == nil { - return - } - - ticker := time.NewTicker(500 * time.Millisecond) - defer ticker.Stop() - var retries = 0 - - now := func() int64 { - return time.Now().UnixNano() / int64(time.Millisecond) - - } - - var lastTry = now() - - canQuery := func() bool { - backoff := bootnodesQueryBackoffMs * int64(math.Exp2(float64(retries))) - - return lastTry+backoff < now() - } - - for { - select { - case <-w.dnsDiscAsyncRetrievedSignal: - if !canQuery() { - continue - } - - err := w.restartDiscV5(true) - if err != nil { - w.logger.Warn("failed to restart discv5", zap.Error(err)) - } - retries = 0 - lastTry = now() - case <-ticker.C: - if w.seededBootnodesForDiscV5 && len(w.node.Host().Network().Peers()) > 3 { - w.logger.Debug("not querying bootnodes", zap.Bool("seeded", w.seededBootnodesForDiscV5), zap.Int("peer-count", len(w.node.Host().Network().Peers()))) - continue - } - - if !canQuery() { - w.logger.Info("can't query bootnodes", - zap.Int("peer-count", len(w.node.Host().Network().Peers())), - zap.Int64("lastTry", lastTry), zap.Int64("now", now()), - zap.Int64("backoff", bootnodesQueryBackoffMs*int64(math.Exp2(float64(retries)))), - zap.Int("retries", retries), - ) - continue - } - - w.logger.Info("querying bootnodes to restore connectivity", zap.Int("peer-count", len(w.node.Host().Network().Peers()))) - err := w.restartDiscV5(false) - if err != nil { - w.logger.Warn("failed to restart discv5", zap.Error(err)) - } - - lastTry = now() - retries++ - // We reset the retries after a while and restart - if retries > bootnodesMaxRetries { - retries = 0 - } - - // If we go online, trigger immediately - case <-w.goingOnline: - if !canQuery() { - continue - } - err := w.restartDiscV5(false) - if err != nil { - w.logger.Warn("failed to restart discv5", zap.Error(err)) - } - retries = 0 - lastTry = now() - - case <-w.ctx.Done(): - w.logger.Debug("bootnode seeding stopped") - return - } - } -} - -// Restart discv5, re-retrieving bootstrap nodes -func (w *Waku) restartDiscV5(useOnlyDNSDiscCache bool) error { - ctx, cancel := context.WithTimeout(w.ctx, 30*time.Second) - defer cancel() - bootnodes, err := w.getDiscV5BootstrapNodes(ctx, w.discV5BootstrapNodes, useOnlyDNSDiscCache) - if err != nil { - return err - } - if len(bootnodes) == 0 { - return errors.New("failed to fetch bootnodes") - } - - if w.node.DiscV5().ErrOnNotRunning() != nil { - w.logger.Info("is not started restarting") - err := w.node.DiscV5().Start(w.ctx) - if err != nil { - w.logger.Error("Could not start DiscV5", zap.Error(err)) - } - } else { - w.node.DiscV5().Stop() - w.logger.Info("is started restarting") - - select { - case <-w.ctx.Done(): // Don't start discv5 if we are stopping waku - return nil - default: - } - - err := w.node.DiscV5().Start(w.ctx) - if err != nil { - w.logger.Error("Could not start DiscV5", zap.Error(err)) - } - } - - w.logger.Info("restarting discv5 with nodes", zap.Any("nodes", bootnodes)) - return w.node.SetDiscV5Bootnodes(bootnodes) } -*/ func (w *Waku) timestamp() int64 { return w.timesource.Now().UnixNano() @@ -2015,39 +1535,23 @@ func toDeterministicID(id string, expectedLen int) (string, error) { return id, nil } -func FormatPeerStats(wakuNode *node.WakuNode) types.PeerStats { - p := make(types.PeerStats) - for k, v := range wakuNode.PeerStats() { - p[k] = types.WakuV2Peer{ - Addresses: utils.EncapsulatePeerID(k, wakuNode.Host().Peerstore().PeerInfo(k).Addrs...), - Protocols: v, - } +func convertPeersDataToPeerStats(peersData bindingscommon.PeersData) types.PeerStats { + result := make(types.PeerStats) + for peerID, peerInfo := range peersData { + result[peerID] = types.WakuV2Peer(peerInfo) } - return p + return result } -// TODO-nwaku -func (w *Waku) StoreNode() *store.WakuStore { - // return w.node.Store() - return nil -} +func FormatPeerStats(wakuNode *waku.WakuNode) (types.PeerStats, error) { -func FormatPeerConnFailures(wakuNode *node.WakuNode) map[string]int { - p := make(map[string]int) - for _, peerID := range wakuNode.Host().Network().Peers() { - peerInfo := wakuNode.Host().Peerstore().PeerInfo(peerID) - connFailures := wakuNode.Host().Peerstore().(wps.WakuPeerstore).ConnFailures(peerInfo.ID) - if connFailures > 0 { - p[peerID.String()] = connFailures - } + peersData, err := wakuNode.GetConnectedPeersInfo() + + if err != nil { + return nil, err } - return p -} -// TODO-nwaku -func (w *Waku) LegacyStoreNode() legacy_store.Store { - // return w.node.LegacyStore() - return nil + return convertPeersDataToPeerStats(peersData), nil } // GetCurrentTime returns current time. @@ -2057,8 +1561,7 @@ func (w *Waku) GetCurrentTime() uint64 { } func (w *Waku) GetActiveStorenode() peer.AddrInfo { - // TODO-nwaku - return peer.AddrInfo{} + return w.StorenodeCycle.GetActiveStorenodePeerInfo() } func (w *Waku) OnStorenodeChanged() <-chan peer.ID { @@ -2113,8 +1616,13 @@ func (w *Waku) PerformStorenodeTask(fn func() error, opts ...history.StorenodeTa } func (w *Waku) DisconnectActiveStorenode(ctx context.Context, backoff time.Duration, shouldCycle bool) { - // TODO-nwaku - return + w.StorenodeCycle.Lock() + defer w.StorenodeCycle.Unlock() + + w.StorenodeCycle.DisconnectActiveStorenode(backoff) + if shouldCycle { + w.StorenodeCycle.Cycle(ctx) + } } func (w *Waku) PublicWakuAPI() types.PublicWakuAPI { @@ -2180,49 +1688,51 @@ func printStackTrace() { fmt.Printf("Current stack trace:\n%s\n", buf[:n]) } -func wakuNew(nodeKey *ecdsa.PrivateKey, - cfg *Config, - logger *zap.Logger, - appDB *sql.DB, - ts *timesource.NTPTimeSource, - onHistoricMessagesRequestFailed func([]byte, peer.AddrInfo, error), onPeerStats func(types.ConnStatus)) (*Waku, error) { +func gowakuToNwakuConfig(cfg *Config, logger *zap.Logger) *bindingscommon.WakuConfig { - var err error - if logger == nil { - logger, err = zap.NewDevelopment() + nwakuCfg := bindingscommon.WakuConfig{} + nwakuCfg.MaxMessageSize = fmt.Sprintf("%dB", cfg.MaxMessageSize) + nwakuCfg.TcpPort = cfg.Port + nwakuCfg.PeerExchange = cfg.EnablePeerExchangeServer || cfg.EnablePeerExchangeClient // no distinction between client and server in nwaku + nwakuCfg.Discv5BootstrapNodes = cfg.DiscV5BootstrapNodes + nwakuCfg.Discv5Discovery = cfg.EnableDiscV5 + nwakuCfg.Discv5EnrAutoUpdate = cfg.AutoUpdate + nwakuCfg.Discv5UdpPort = cfg.UDPPort + nwakuCfg.Store = cfg.EnableStore + + if cfg.Nameserver != "" { + nwakuCfg.DnsAddrsNameServers = []string{cfg.Nameserver} + } + + nwakuCfg.ClusterID = cfg.ClusterID + nwakuCfg.Shards = []uint16{DefaultShardIndex, NonProtectedShardIndex} + + for _, topic := range cfg.DefaultShardedPubsubTopics { + wakuTopic, err := protocol.ToWakuPubsubTopic(topic) if err != nil { - return nil, err + continue } - } - if ts == nil { - ts = timesource.Default() - } - if nodeKey == nil { - // No nodekey is provided, create an ephemeral key - nodeKey, err = crypto.GenerateKey() + sharded, err := protocol.ToShardPubsubTopic(wakuTopic) if err != nil { - return nil, fmt.Errorf("failed to generate a random private key: %v", err) + continue } - } - nwakuCfg := cfg.NwakuConfig - nwakuCfg.Nodekey = hex.EncodeToString(crypto.FromECDSA(nodeKey)) + if sharded.Cluster() != cfg.ClusterID { + logger.Warn("ClusterId in provided pubsub topic doesn't match configured cluster", + zap.Uint16("configured cluster", cfg.ClusterID), + zap.Uint16("topic's cluster", sharded.Cluster())) + continue + } - nwakuCfg.TcpPort, nwakuCfg.Discv5UdpPort, err = getFreePortIfNeeded(nwakuCfg.TcpPort, nwakuCfg.Discv5UdpPort, logger) - if err != nil { - return nil, err + nwakuCfg.Shards = append(nwakuCfg.Shards, sharded.Shard()) } - // TODO-nwaku - // TODO: merge Config and WakuConfig - cfg = setDefaults(cfg) - if err = cfg.Validate(logger); err != nil { - return nil, err + if cfg.StoreCapacity > 0 { + nwakuCfg.StoreMessageRetentionPolicy = fmt.Sprintf("capacity:%d", cfg.StoreCapacity) + } else if cfg.StoreSeconds > 0 { + nwakuCfg.StoreMessageRetentionPolicy = fmt.Sprintf("time:%d", cfg.StoreSeconds) } - logger.Info("starting wakuv2 with config", zap.Any("nwakuCfg", nwakuCfg), zap.Any("wakuCfg", cfg)) - - ctx, cancel := context.WithCancel(context.Background()) if !cfg.LightClient { nwakuCfg.Discv5Discovery = true @@ -2232,58 +1742,20 @@ func wakuNew(nodeKey *ecdsa.PrivateKey, nwakuCfg.Lightpush = true nwakuCfg.RateLimits.Filter = &bindingscommon.RateLimit{Volume: 100, Period: 1, TimeUnit: bindingscommon.Second} nwakuCfg.RateLimits.Lightpush = &bindingscommon.RateLimit{Volume: 5, Period: 1, TimeUnit: bindingscommon.Second} + nwakuCfg.MaxConnections = int(math.Ceil(maxRelayPeers * 1.67)) // 60% will be allocated to relay, 40% to service peers. maxConnections = maxRelayPeers/0.6 = ~1.67*maxRelayPeers + nwakuCfg.PeerExchange = true //Enabling this until discv5 issues are resolved. This will enable more peers to be connected for relay mesh. + } else { + nwakuCfg.MaxConnections = cfg.DiscoveryLimit } if cfg.EnablePeerExchangeServer { nwakuCfg.PeerExchange = true - nwakuCfg.RateLimits.PeerExchange = &bindingscommon.RateLimit{Volume: 5, Period: 1, TimeUnit: bindingscommon.Second} + nwakuCfg.RateLimits.PeerExchange = &bindingscommon.RateLimit{Volume: 1, Period: 1, TimeUnit: bindingscommon.Second} } - wakunode, err := waku.NewWakuNode(nwakuCfg, "nwaku") - if err != nil { - cancel() - return nil, err - } + nwakuCfg.LogLevel = "DEBUG" // TODO-nwaku - allow dynamic log level configuration - var protectedTopicStore *persistence.ProtectedTopicsStore - if appDB != nil { - protectedTopicStore, err = persistence.NewProtectedTopicsStore(logger, appDB) - if err != nil { - cancel() - return nil, err - } - } - - // Notice that the events for self node are handled by the 'MyEventCallback' method - - return &Waku{ - node: wakunode, - cfg: cfg, - privateKeys: make(map[string]*ecdsa.PrivateKey), - symKeys: make(map[string][]byte), - envelopeCache: newTTLCache(), - msgQueue: make(chan *common.ReceivedMessage, messageQueueLimit), - topicHealthStatusChan: make(chan peermanager.TopicHealthStatus, 100), - connectionNotifChan: make(chan node.PeerConnection, 20), - connStatusSubscriptions: make(map[string]*types.ConnStatusSubscription), - ctx: ctx, - cancel: cancel, - wg: sync.WaitGroup{}, - dnsAddressCache: make(map[string][]dnsdisc.DiscoveredNode), - dnsAddressCacheLock: &sync.RWMutex{}, - dnsDiscAsyncRetrievedSignal: make(chan struct{}), - storeMsgIDs: make(map[gethcommon.Hash]bool), - timesource: ts, - storeMsgIDsMu: sync.RWMutex{}, - logger: logger, - discV5BootstrapNodes: nwakuCfg.Discv5BootstrapNodes, - onHistoricMessagesRequestFailed: onHistoricMessagesRequestFailed, - onPeerStats: onPeerStats, - onlineChecker: onlinechecker.NewDefaultOnlineChecker(false).(*onlinechecker.DefaultOnlineChecker), - sendQueue: publish.NewMessageQueue(1000, cfg.UseThrottledPublish), - filters: common.NewFilters(cfg.DefaultShardPubsubTopic, logger), - protectedTopicStore: protectedTopicStore, - }, nil + return &nwakuCfg } @@ -2334,3 +1806,12 @@ func getFreePortIfNeeded(tcpPort int, discV5UDPPort int, logger *zap.Logger) (in return tcpPort, discV5UDPPort, nil } + +func (w *Waku) Metrics() string { + metrics, err := w.node.GetMetrics() + + if err != nil { + panic(err) + } + return metrics +} diff --git a/wakuv2/nwaku_test.go b/messaging/waku/nwaku_test.go similarity index 100% rename from wakuv2/nwaku_test.go rename to messaging/waku/nwaku_test.go diff --git a/wakuv2/nwaku_test_utils.go b/messaging/waku/nwaku_test_utils.go similarity index 100% rename from wakuv2/nwaku_test_utils.go rename to messaging/waku/nwaku_test_utils.go diff --git a/wakuv2/nwaku_utils.go b/messaging/waku/nwaku_utils.go similarity index 98% rename from wakuv2/nwaku_utils.go rename to messaging/waku/nwaku_utils.go index 0a88e7a336..eccf300ded 100644 --- a/wakuv2/nwaku_utils.go +++ b/messaging/waku/nwaku_utils.go @@ -7,9 +7,10 @@ package wakuv2 import ( bindings "github.com/waku-org/waku-go-bindings/waku/common" - "github.com/status-im/status-go/wakuv2/common" "github.com/waku-org/go-waku/waku/v2/protocol/pb" storepb "github.com/waku-org/go-waku/waku/v2/protocol/store/pb" + + "github.com/status-im/status-go/messaging/waku/common" ) func HexToPbHash(hexHash bindings.MessageHash) (pb.MessageHash, error) { diff --git a/wakuv2/persistence/dbkey.go b/messaging/waku/persistence/dbkey.go similarity index 100% rename from wakuv2/persistence/dbkey.go rename to messaging/waku/persistence/dbkey.go diff --git a/wakuv2/persistence/dbstore.go b/messaging/waku/persistence/dbstore.go similarity index 100% rename from wakuv2/persistence/dbstore.go rename to messaging/waku/persistence/dbstore.go diff --git a/wakuv2/persistence/signed_messages.go b/messaging/waku/persistence/signed_messages.go similarity index 98% rename from wakuv2/persistence/signed_messages.go rename to messaging/waku/persistence/signed_messages.go index aad6d812a4..8a1061105c 100644 --- a/wakuv2/persistence/signed_messages.go +++ b/messaging/waku/persistence/signed_messages.go @@ -7,7 +7,7 @@ import ( "go.uber.org/zap" - "github.com/ethereum/go-ethereum/crypto" + "github.com/status-im/status-go/crypto" ) // DBStore is a MessageProvider that has a *sql.DB connection diff --git a/wakuv2/pinger.go b/messaging/waku/pinger.go similarity index 100% rename from wakuv2/pinger.go rename to messaging/waku/pinger.go diff --git a/wakuv2/publisher.go b/messaging/waku/publisher.go similarity index 100% rename from wakuv2/publisher.go rename to messaging/waku/publisher.go diff --git a/wakuv2/result.go b/messaging/waku/result.go similarity index 100% rename from wakuv2/result.go rename to messaging/waku/result.go diff --git a/wakuv2/shard.go b/messaging/waku/shard.go similarity index 93% rename from wakuv2/shard.go rename to messaging/waku/shard.go index 5a38211df3..9016e4858c 100644 --- a/wakuv2/shard.go +++ b/messaging/waku/shard.go @@ -11,17 +11,6 @@ type Shard struct { Index uint16 `json:"index"` } -func FromProtobuff(p *protobuf.Shard) *Shard { - if p == nil { - return nil - } - - return &Shard{ - Cluster: uint16(p.Cluster), - Index: uint16(p.Index), - } -} - func (s *Shard) Protobuffer() *protobuf.Shard { if s == nil { return nil diff --git a/wakuv2/store_message_verifier.go b/messaging/waku/store_message_verifier.go similarity index 100% rename from wakuv2/store_message_verifier.go rename to messaging/waku/store_message_verifier.go diff --git a/wakuv2/storenode_requestor.go b/messaging/waku/storenode_requestor.go similarity index 100% rename from wakuv2/storenode_requestor.go rename to messaging/waku/storenode_requestor.go diff --git a/wakuv2/tracer.go b/messaging/waku/tracer.go similarity index 100% rename from wakuv2/tracer.go rename to messaging/waku/tracer.go diff --git a/waku/types/envelopes.go b/messaging/waku/types/envelopes.go similarity index 92% rename from waku/types/envelopes.go rename to messaging/waku/types/envelopes.go index fad28b8c39..ea5f88e62f 100644 --- a/waku/types/envelopes.go +++ b/messaging/waku/types/envelopes.go @@ -1,13 +1,16 @@ package types -import "github.com/status-im/status-go/eth-node/types" +import ( + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/eth-node/types" +) // Envelope represents a clear-text data packet to transmit through the Whisper // network. Its contents may or may not be encrypted and signed. type Envelope interface { Wrapped - Hash() types.Hash // cached hash of the envelope to avoid rehashing every time + Hash() cryptotypes.Hash // cached hash of the envelope to avoid rehashing every time Bloom() []byte PoW() float64 Expiry() uint32 @@ -58,15 +61,15 @@ const ( type EnvelopeEvent struct { Event EventType Topic TopicType - Hash types.Hash - Batch types.Hash + Hash cryptotypes.Hash + Batch cryptotypes.Hash Peer types.EnodeID Data interface{} } // EnvelopeError code and optional description of the error. type EnvelopeError struct { - Hash types.Hash + Hash cryptotypes.Hash Code uint Description string } diff --git a/waku/types/filter.go b/messaging/waku/types/filter.go similarity index 100% rename from waku/types/filter.go rename to messaging/waku/types/filter.go diff --git a/waku/types/mailserver.go b/messaging/waku/types/mailserver.go similarity index 56% rename from waku/types/mailserver.go rename to messaging/waku/types/mailserver.go index 83ebed3f85..be1690ab91 100644 --- a/waku/types/mailserver.go +++ b/messaging/waku/types/mailserver.go @@ -1,10 +1,7 @@ package types import ( - "database/sql" - "encoding/json" "errors" - "fmt" "github.com/ethereum/go-ethereum/p2p/enode" @@ -15,7 +12,7 @@ import ( "github.com/waku-org/go-waku/waku/v2/protocol/enr" "github.com/waku-org/go-waku/waku/v2/utils" - "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/crypto/types" ) // MailServerResponse is the response payload sent by the mailserver. @@ -47,22 +44,6 @@ type SyncEventResponse struct { Error string } -func MustDecodeENR(enrStr string) *enode.Node { - node, err := enode.Parse(enode.ValidSchemes, enrStr) - if err != nil || node == nil { - panic("could not decode enr: " + enrStr) - } - return node -} - -func MustDecodeMultiaddress(multiaddrsStr string) *multiaddr.Multiaddr { - maddr, err := multiaddr.NewMultiaddr(multiaddrsStr) - if err != nil || maddr == nil { - panic("could not decode multiaddr: " + multiaddrsStr) - } - return &maddr -} - type Mailserver struct { ID string `json:"id"` Name string `json:"name"` @@ -111,50 +92,3 @@ func (m Mailserver) PeerID() (peer.ID, error) { } return p.ID, nil } - -func (m Mailserver) NullablePassword() (val sql.NullString) { - if m.Password != "" { - val.String = m.Password - val.Valid = true - } - return -} - -// UnmarshalJSON implements the custom JSON unmarshaling logic for Mailserver. -// It supports ENR and Addr being saved as strings. -func (m *Mailserver) UnmarshalJSON(data []byte) error { - type Alias Mailserver // Create an alias type to avoid infinite recursion - aux := struct { - Alias - ENR string `json:"enr"` // Temporary field to handle ENR as a string - Addr string `json:"addr"` // Temporary field to handle Addr as a string - }{} - - // Unmarshal the data into the temporary struct - if err := json.Unmarshal(data, &aux); err != nil { - return err - } - - // Set the basic fields - *m = Mailserver(aux.Alias) - - // Decode the ENR if present - if aux.ENR != "" { - decodedENR, err := enode.Parse(enode.ValidSchemes, aux.ENR) - if err != nil { - return fmt.Errorf("invalid ENR: %w", err) - } - m.ENR = decodedENR - } - - // Decode the Multiaddr if present - if aux.Addr != "" { - decodedAddr, err := multiaddr.NewMultiaddr(aux.Addr) - if err != nil { - return fmt.Errorf("invalid Addr: %w", err) - } - m.Addr = &decodedAddr - } - - return nil -} diff --git a/waku/types/rpc.go b/messaging/waku/types/rpc.go similarity index 73% rename from waku/types/rpc.go rename to messaging/waku/types/rpc.go index 535d8c04a6..f68b2aff0d 100644 --- a/waku/types/rpc.go +++ b/messaging/waku/types/rpc.go @@ -2,8 +2,6 @@ package types import ( "context" - - "github.com/status-im/status-go/eth-node/types" ) // NewMessage represents a new whisper message that is posted through the RPC. @@ -44,20 +42,10 @@ type Criteria struct { // PublicWakuAPI provides the waku RPC service that can be // use publicly without security implications. type PublicWakuAPI interface { - // AddPrivateKey imports the given private key. - AddPrivateKey(ctx context.Context, privateKey types.HexBytes) (string, error) - // GenerateSymKeyFromPassword derives a key from the given password, stores it, and returns its ID. - GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) - // DeleteKeyPair removes the key with the given key if it exists. - DeleteKeyPair(ctx context.Context, key string) (bool, error) - // Post posts a message on the Whisper network. // returns the hash of the message in case of success. Post(ctx context.Context, req NewMessage) ([]byte, error) - // NewMessageFilter creates a new filter that can be used to poll for - // (new) messages that satisfy the given criteria. - NewMessageFilter(req Criteria) (string, error) // GetFilterMessages returns the messages that match the filter criteria and // are received between the last poll and now. GetFilterMessages(id string) ([]*Message, error) diff --git a/waku/types/stats.go b/messaging/waku/types/stats.go similarity index 100% rename from waku/types/stats.go rename to messaging/waku/types/stats.go diff --git a/waku/types/subscribe.go b/messaging/waku/types/subscribe.go similarity index 100% rename from waku/types/subscribe.go rename to messaging/waku/types/subscribe.go diff --git a/waku/types/topic.go b/messaging/waku/types/topic.go similarity index 94% rename from waku/types/topic.go rename to messaging/waku/types/topic.go index b6c041bdc3..4e71cde9dd 100644 --- a/waku/types/topic.go +++ b/messaging/waku/types/topic.go @@ -1,7 +1,7 @@ package types import ( - "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/crypto/types" ) const ( diff --git a/waku/types/waku.go b/messaging/waku/types/waku.go similarity index 96% rename from waku/types/waku.go rename to messaging/waku/types/waku.go index eab75591ed..473290f5d0 100644 --- a/waku/types/waku.go +++ b/messaging/waku/types/waku.go @@ -89,13 +89,8 @@ type WakuKeyManager interface { GetPrivateKey(id string) (*ecdsa.PrivateKey, error) // AddKeyPair imports a asymmetric private key and returns a deterministic identifier. AddKeyPair(key *ecdsa.PrivateKey) (string, error) - // DeleteKeyPair deletes the key with the specified ID if it exists. - DeleteKeyPair(keyID string) bool // DeleteKeyPairs deletes all the keys DeleteKeyPairs() error - AddSymKeyDirect(key []byte) (string, error) - AddSymKeyFromPassword(password string) (string, error) - DeleteSymKey(id string) bool GetSymKey(id string) ([]byte, error) } diff --git a/waku/types/wrapped.go b/messaging/waku/types/wrapped.go similarity index 100% rename from waku/types/wrapped.go rename to messaging/waku/types/wrapped.go diff --git a/wakuv2/waku_test.go b/messaging/waku/waku_test.go similarity index 64% rename from wakuv2/waku_test.go rename to messaging/waku/waku_test.go index ea5aaf2f46..d6e5ab6a4d 100644 --- a/wakuv2/waku_test.go +++ b/messaging/waku/waku_test.go @@ -6,7 +6,6 @@ package wakuv2 import ( "context" "crypto/rand" - "encoding/json" "errors" "math/big" "os" @@ -15,9 +14,6 @@ import ( "time" "github.com/cenkalti/backoff/v3" - "github.com/libp2p/go-libp2p/core/metrics" - "github.com/libp2p/go-libp2p/core/peer" - libp2pprotocol "github.com/libp2p/go-libp2p/core/protocol" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -29,21 +25,14 @@ import ( "google.golang.org/protobuf/proto" "github.com/waku-org/go-waku/waku/v2/dnsdisc" - wps "github.com/waku-org/go-waku/waku/v2/peerstore" "github.com/waku-org/go-waku/waku/v2/protocol" "github.com/waku-org/go-waku/waku/v2/protocol/filter" - "github.com/waku-org/go-waku/waku/v2/protocol/legacy_store" - "github.com/waku-org/go-waku/waku/v2/protocol/lightpush" "github.com/waku-org/go-waku/waku/v2/protocol/pb" - "github.com/waku-org/go-waku/waku/v2/protocol/relay" "github.com/waku-org/go-waku/waku/v2/protocol/store" - "github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/connection" + "github.com/status-im/status-go/messaging/waku/common" "github.com/status-im/status-go/protocol/tt" - "github.com/status-im/status-go/t/helpers" - wakutypes "github.com/status-im/status-go/waku/types" - "github.com/status-im/status-go/wakuv2/common" ) var testStoreENRBootstrap = "enrtree://AI4W5N5IFEUIHF5LESUAOSMV6TKWF2MB6GU2YK7PU4TYUGUNOCEPW@store.staging.status.nodes.status.im" @@ -496,148 +485,6 @@ func TestWakuV2Filter(t *testing.T) { require.NoError(t, w.Stop()) } -func TestWakuV2Store(t *testing.T) { - t.Skip("deprecated. Storenode must use nwaku") - - // Configuration for the first Waku node - config1 := &Config{ - Port: 0, - ClusterID: 16, - EnableDiscV5: false, - DiscoveryLimit: 20, - EnableStore: false, - StoreCapacity: 100, - StoreSeconds: 3600, - EnableMissingMessageVerification: true, - } - w1PeersCh := make(chan peer.IDSlice, 100) // buffered not to block on the send side - - // Start the first Waku node - w1, err := New(nil, config1, nil, nil, nil, nil, func(cs wakutypes.ConnStatus) { - w1PeersCh <- maps.Keys(cs.Peers) - }) - require.NoError(t, err) - require.NoError(t, w1.Start()) - defer func() { - require.NoError(t, w1.Stop()) - close(w1PeersCh) - }() - - // Configuration for the second Waku node - sql2, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) - require.NoError(t, err) - config2 := &Config{ - Port: 0, - ClusterID: 16, - EnableDiscV5: false, - DiscoveryLimit: 20, - EnableStore: true, - StoreCapacity: 100, - StoreSeconds: 3600, - } - - // Start the second Waku node - w2, err := New(nil, config2, nil, sql2, nil, nil, nil) - require.NoError(t, err) - require.NoError(t, w2.Start()) - w2EnvelopeCh := make(chan common.EnvelopeEvent, 100) - w2.subscribeEnvelopeEvents(w2EnvelopeCh) - defer func() { - require.NoError(t, w2.Stop()) - close(w2EnvelopeCh) - }() - - // Connect the two nodes directly - peer2Addr, err := w2.ListenAddresses() - require.NoError(t, err) - err = w1.node.DialPeer(context.Background(), peer2Addr[0].String()) - require.NoError(t, err) - - waitForPeerConnection(t, w2.node.Host().ID(), w1PeersCh) - - // Create a filter for the second node to catch messages - filter := &common.Filter{ - Messages: common.NewMemoryMessageStore(), - PubsubTopic: config2.DefaultShardPubsubTopic, - ContentTopics: common.NewTopicSetFromBytes([][]byte{{1, 2, 3, 4}}), - } - - _, err = w2.subscribe(filter) - require.NoError(t, err) - - time.Sleep(2 * time.Second) - - // Send a message from the first node - msgTimestamp := w1.CurrentTime().UnixNano() - contentTopic := maps.Keys(filter.ContentTopics)[0] - _, err = w1.Send(config1.DefaultShardPubsubTopic, &pb.WakuMessage{ - Payload: []byte{1, 2, 3, 4, 5}, - ContentTopic: contentTopic.ContentTopic(), - Version: proto.Uint32(0), - Timestamp: &msgTimestamp, - }, nil) - require.NoError(t, err) - - waitForEnvelope(t, contentTopic.ContentTopic(), w2EnvelopeCh) - - // Retrieve the message from the second node's filter - messages := filter.Retrieve() - require.Len(t, messages, 1) - - timestampInSeconds := msgTimestamp / int64(time.Second) - marginInSeconds := 5 - // Query the second node's store for the message - result, err := w1.node.Store().Query( - context.Background(), - store.FilterCriteria{ - TimeStart: proto.Int64((timestampInSeconds - int64(marginInSeconds)) * int64(time.Second)), - TimeEnd: proto.Int64((timestampInSeconds + int64(marginInSeconds)) * int64(time.Second)), - ContentFilter: protocol.NewContentFilter(config1.DefaultShardPubsubTopic, contentTopic.ContentTopic()), - }, - store.WithPeer(w2.node.Host().ID()), - ) - require.NoError(t, err) - require.True(t, len(result.Messages()) > 0, "no messages received from store node") -} - -func waitForPeerConnection(t *testing.T, peerID peer.ID, peerCh chan peer.IDSlice) { - waitForPeerConnectionWithTimeout(t, peerID, peerCh, 3*time.Second) -} - -func waitForPeerConnectionWithTimeout(t *testing.T, peerID peer.ID, peerCh chan peer.IDSlice, timeout time.Duration) { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - for { - select { - case peers := <-peerCh: - for _, p := range peers { - if p == peerID { - return - } - } - case <-ctx.Done(): - require.Fail(t, "timed out waiting for peer "+peerID.String()) - return - } - } -} - -func waitForEnvelope(t *testing.T, contentTopic string, envCh chan common.EnvelopeEvent) { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - for { - select { - case env := <-envCh: - if env.Topic.ContentTopic() == contentTopic { - return - } - case <-ctx.Done(): - require.Fail(t, "timed out waiting for envelope's topic "+contentTopic) - return - } - } -} - func TestOnlineChecker(t *testing.T) { w, err := New(nil, nil, nil, nil, nil, nil, nil) require.NoError(t, w.Start()) @@ -676,132 +523,3 @@ func TestOnlineChecker(t *testing.T) { lightNode.filterManager.SubscribeFilter("test", protocol.NewContentFilter(f.PubsubTopic, f.ContentTopics.ContentTopics()...)) } - -func TestLightpushRateLimit(t *testing.T) { - t.Skip("flaky as it is hard to simulate rate-limits as execution time varies in environments") - logger := tt.MustCreateTestLogger() - - config0 := &Config{} - setDefaultConfig(config0, false) - w0PeersCh := make(chan peer.IDSlice, 5) // buffered not to block on the send side - - // Start the relayu node - w0, err := New(nil, config0, logger.Named("relayNode"), nil, nil, nil, func(cs wakutypes.ConnStatus) { - w0PeersCh <- maps.Keys(cs.Peers) - }) - require.NoError(t, err) - require.NoError(t, w0.Start()) - defer func() { - require.NoError(t, w0.Stop()) - close(w0PeersCh) - }() - - contentTopics := common.NewTopicSetFromBytes([][]byte{{1, 2, 3, 4}}) - filter := &common.Filter{ - PubsubTopic: config0.DefaultShardPubsubTopic, - Messages: common.NewMemoryMessageStore(), - ContentTopics: contentTopics, - } - - _, err = w0.subscribe(filter) - require.NoError(t, err) - - config1 := &Config{} - setDefaultConfig(config1, false) - w1PeersCh := make(chan peer.IDSlice, 5) // buffered not to block on the send side - - // Start the full node - w1, err := New(nil, config1, logger.Named("fullNode"), nil, nil, nil, func(cs wakutypes.ConnStatus) { - w1PeersCh <- maps.Keys(cs.Peers) - }) - require.NoError(t, err) - require.NoError(t, w1.Start()) - defer func() { - require.NoError(t, w1.Stop()) - close(w1PeersCh) - }() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - //Connect the relay peer and full node - peerAddr, err := w0.ListenAddresses() - - require.NoError(t, err) - err = w1.node.DialPeer(ctx, peerAddr[0].String()) - require.NoError(t, err) - - err = tt.RetryWithBackOff(func() error { - if len(w1.Peers()) == 0 { - return errors.New("no peers discovered") - } - return nil - }) - require.NoError(t, err) - - config2 := &Config{} - setDefaultConfig(config2, true) - w2PeersCh := make(chan peer.IDSlice, 5) // buffered not to block on the send side - - // Start the light node - w2, err := New(nil, config2, logger.Named("lightNode"), nil, nil, nil, func(cs wakutypes.ConnStatus) { - w2PeersCh <- maps.Keys(cs.Peers) - }) - require.NoError(t, err) - require.NoError(t, w2.Start()) - defer func() { - require.NoError(t, w2.Stop()) - close(w2PeersCh) - }() - - //Use this instead of DialPeer to make sure the peer is added to PeerStore and can be selected for Lighpush - addresses, err := w1.ListenAddresses() - require.NoError(t, err) - peerID := w1.PeerID() - w2.node.AddDiscoveredPeer(peerID, addresses, wps.Static, w1.cfg.DefaultShardedPubsubTopics, w1.node.ENR(), true) - - waitForPeerConnectionWithTimeout(t, w2.node.Host().ID(), w1PeersCh, 5*time.Second) - - event := make(chan common.EnvelopeEvent, 10) - w2.subscribeEnvelopeEvents(event) - - for i := range [15]int{} { - msgTimestamp := w2.timestamp() - _, err := w2.Send(config2.DefaultShardPubsubTopic, &pb.WakuMessage{ - Payload: []byte{1, 2, 3, 4, 5, 6, byte(i)}, - ContentTopic: maps.Keys(contentTopics)[0].ContentTopic(), - Version: proto.Uint32(0), - Timestamp: &msgTimestamp, - }, nil) - - require.NoError(t, err) - - time.Sleep(20 * time.Millisecond) - - } - - messages := filter.Retrieve() - require.Len(t, messages, 10) - -} - -func TestTelemetryFormat(t *testing.T) { - tc := NewBandwidthTelemetryClient(tt.MustCreateTestLogger(), "#") - - s := metrics.Stats{ - TotalIn: 10, - TotalOut: 20, - RateIn: 30, - RateOut: 40, - } - - m := make(map[libp2pprotocol.ID]metrics.Stats) - m[relay.WakuRelayID_v200] = s - m[filter.FilterPushID_v20beta1] = s - m[filter.FilterSubscribeID_v20beta1] = s - m[legacy_store.StoreID_v20beta4] = s - m[lightpush.LightPushID_v20beta1] = s - - requestBody := tc.getTelemetryRequestBody(m) - _, err := json.Marshal(requestBody) - require.NoError(t, err) -} diff --git a/wakuv2/waku_unsupported.go b/messaging/waku/waku_unsupported.go similarity index 100% rename from wakuv2/waku_unsupported.go rename to messaging/waku/waku_unsupported.go diff --git a/messaging/wakumetrics/client.go b/messaging/wakumetrics/client.go new file mode 100644 index 0000000000..63adc4d30d --- /dev/null +++ b/messaging/wakumetrics/client.go @@ -0,0 +1,165 @@ +package wakumetrics + +import ( + "fmt" + "strconv" + + messagingtypes "github.com/status-im/status-go/messaging/types" + + wakuv2 "github.com/status-im/status-go/messaging/waku" + + wps "github.com/waku-org/go-waku/waku/v2/peerstore" + + v2common "github.com/status-im/status-go/messaging/waku/common" +) + +type ReceivedMessages struct { + Filter messagingtypes.ChatFilter + SHHMessage *messagingtypes.ReceivedMessage + Messages []*messagingtypes.Message +} + +type Client struct { + peerId string + lastPeerConnFailures map[string]int +} + +type TelemetryClientOption func(*Client) + +func WithPeerID(peerId string) TelemetryClientOption { + return func(c *Client) { + c.peerId = peerId + metrics.NodePeerId.WithLabelValues(peerId).Set(1) + } +} + +func NewClient(opts ...TelemetryClientOption) (*Client, error) { + client := &Client{ + lastPeerConnFailures: make(map[string]int), + } + + for _, opt := range opts { + opt(client) + } + + return client, nil +} + +// RegisterWithRegistry registers all metrics with the provided registry +func (c *Client) RegisterWithRegistry() error { + if err := RegisterMetrics(); err != nil { + return fmt.Errorf("failed to register metrics: %v", err) + } + return nil +} + +func (c *Client) PushReceivedMessages(receivedMessages ReceivedMessages) { + metrics.MessagesReceivedTotal.WithLabelValues( + receivedMessages.Filter.PubsubTopic(), + receivedMessages.Filter.ContentTopic().String(), + receivedMessages.Filter.ChatID(), + ).Add(float64(len(receivedMessages.Messages))) +} + +func (c *Client) PushSentEnvelope(sentEnvelope wakuv2.SentEnvelope) { + metrics.EnvelopeSentTotal.WithLabelValues( + sentEnvelope.Envelope.PubsubTopic(), + sentEnvelope.Envelope.Message().ContentTopic, + sentEnvelope.PublishMethod.String(), + ).Inc() +} + +func (c *Client) PushErrorSendingEnvelope(errorSendingEnvelope wakuv2.ErrorSendingEnvelope) { + metrics.EnvelopeSentErrors.WithLabelValues( + errorSendingEnvelope.SentEnvelope.Envelope.PubsubTopic(), + errorSendingEnvelope.SentEnvelope.Envelope.Message().ContentTopic, + ).Inc() +} + +func (c *Client) PushPeerConnFailures(peerConnFailures map[string]int) { + for peerID, failures := range peerConnFailures { + if lastFailures, exists := c.lastPeerConnFailures[peerID]; exists { + if failures == lastFailures { + continue + } + } + c.lastPeerConnFailures[peerID] = failures + metrics.PeerConnectionFailures.Add(float64(failures)) + } +} + +func (c *Client) PushMessageCheckSuccess() { + metrics.StoreQuerySuccesses.Inc() +} + +func (c *Client) PushMessageCheckFailure() { + metrics.StoreQueryFailures.Inc() +} + +func (c *Client) PushPeerCountByShard(peerCountByShard map[uint16]uint) { + for shard, count := range peerCountByShard { + metrics.PeersByShard.WithLabelValues(strconv.FormatUint(uint64(shard), 10)).Set(float64(count)) + } +} + +func (c *Client) PushPeerCountByOrigin(peerCountByOrigin map[wps.Origin]uint) { + for origin, count := range peerCountByOrigin { + metrics.PeersByOrigin.WithLabelValues(getOriginString(origin)).Set(float64(count)) + } +} + +func (c *Client) PushDialFailure(dialFailure v2common.DialError) { + metrics.PeerDialFailures.WithLabelValues( + dialFailure.ErrType.String(), + dialFailure.Protocols, + ).Inc() +} + +func (c *Client) PushMissedMessage(envelope v2common.Envelope) { + metrics.MissedMessages.WithLabelValues( + envelope.PubsubTopic(), + envelope.Message().ContentTopic, + ).Inc() +} + +func (c *Client) PushMissedRelevantMessage(receivedMessage *v2common.ReceivedMessage) { + metrics.MissedMessages.WithLabelValues( + receivedMessage.PubsubTopic, + receivedMessage.ContentTopic.String(), + ).Inc() +} + +func (c *Client) PushMessageDeliveryConfirmed() { + metrics.MessageDeliveryConfirmations.Inc() +} + +func (c *Client) PushSentMessageTotal(messageSize uint32, publishMethod string) { + metrics.WakuMessagesSizeBytes.WithLabelValues(publishMethod).Add(float64(messageSize)) + metrics.MessagesSentTotal.WithLabelValues(publishMethod).Inc() +} + +func (c *Client) PushRawMessageByType(pubsubTopic string, contentTopic string, messageType string, messageSize uint32) { + metrics.RawMessagesSizeBytes.WithLabelValues(messageType, pubsubTopic, contentTopic).Add(float64(messageSize)) + metrics.RawMessagesSentTotal.WithLabelValues(messageType, pubsubTopic, contentTopic).Inc() +} + +func getOriginString(origin wps.Origin) string { + switch origin { + case wps.Unknown: + return "unknown" + case wps.Discv5: + return "discv5" + case wps.Static: + return "static" + case wps.PeerExchange: + return "peer_exchange" + case wps.DNSDiscovery: + return "dns_discovery" + case wps.Rendezvous: + return "rendezvous" + case wps.PeerManager: + return "peer_manager" + default: + return "unknown" + } +} diff --git a/messaging/wakumetrics/client_test.go b/messaging/wakumetrics/client_test.go new file mode 100644 index 0000000000..76eb88f4bc --- /dev/null +++ b/messaging/wakumetrics/client_test.go @@ -0,0 +1,178 @@ +package wakumetrics + +import ( + "errors" + "strconv" + "testing" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/require" + + "github.com/waku-org/go-waku/waku/v2/api/publish" + wps "github.com/waku-org/go-waku/waku/v2/peerstore" + v2protocol "github.com/waku-org/go-waku/waku/v2/protocol" + "github.com/waku-org/go-waku/waku/v2/protocol/pb" + + messagingtypes "github.com/status-im/status-go/messaging/types" + wakuv2 "github.com/status-im/status-go/messaging/waku" +) + +var ( + errTest = errors.New("test error") +) + +func createTestClient(t *testing.T) *Client { + client, err := NewClient(WithPeerID("test-key")) + require.NoError(t, err) + require.NoError(t, client.RegisterWithRegistry()) + + t.Cleanup(func() { + require.NoError(t, UnregisterMetrics()) + }) + + return client +} + +func createTestMessage(pubsubTopic string, contentTopic messagingtypes.ContentTopic, payload []byte) *messagingtypes.ReceivedMessage { + return &messagingtypes.ReceivedMessage{ + Topic: contentTopic, + Payload: payload, + } +} + +func getCounterValue(metric *prometheus.CounterVec, labels ...string) float64 { + m := metric.WithLabelValues(labels...) + pb := &dto.Metric{} + err := m.(prometheus.Metric).Write(pb) + if err != nil { + return 0 + } + return pb.Counter.GetValue() +} + +func getGaugeVecValue(metric *prometheus.GaugeVec, labels ...string) float64 { + m := metric.WithLabelValues(labels...) + pb := &dto.Metric{} + err := m.(prometheus.Metric).Write(pb) + if err != nil { + return 0 + } + return pb.Gauge.GetValue() +} + +func TestClient_DoubleRegister(t *testing.T) { + client := createTestClient(t) + require.Error(t, client.RegisterWithRegistry()) +} + +func TestClient_PushReceivedMessages(t *testing.T) { + client := createTestClient(t) + + filter := *messagingtypes.NewChatFilter( + &messagingtypes.ChatFilterConfig{ + PubsubTopic: "test-pubsub", + ContentTopic: messagingtypes.StringToContentTopic("test-content"), + ChatID: "test-chat", + }, + ) + + shhMessage := createTestMessage("test-pubsub", messagingtypes.StringToContentTopic("test-content"), []byte("test-payload")) + + receivedMessages := ReceivedMessages{ + Filter: filter, + SHHMessage: shhMessage, + Messages: []*messagingtypes.Message{{}}, + } + + client.PushReceivedMessages(receivedMessages) + + // Verify MessagesReceivedTotal metric + value := getCounterValue(metrics.MessagesReceivedTotal, + filter.PubsubTopic(), + filter.ContentTopic().String(), + filter.ChatID(), + ) + require.Equal(t, float64(1), value) +} + +func TestClient_PushPeerCountByOrigin(t *testing.T) { + client := createTestClient(t) + + peerCountByOrigin := map[wps.Origin]uint{ + wps.Discv5: 5, + wps.Static: 3, + wps.PeerExchange: 2, + wps.Unknown: 1, + wps.DNSDiscovery: 1, + wps.Rendezvous: 1, + wps.PeerManager: 1, + } + + client.PushPeerCountByOrigin(peerCountByOrigin) + + // Verify metrics for each origin + for origin, expectedCount := range peerCountByOrigin { + value := getGaugeVecValue(metrics.PeersByOrigin, getOriginString(origin)) + require.Equal(t, float64(expectedCount), value) + } +} + +func TestClient_PushPeerCountByShard(t *testing.T) { + client := createTestClient(t) + + peerCountByShard := map[uint16]uint{ + 1: 5, + 2: 3, + 3: 2, + } + + client.PushPeerCountByShard(peerCountByShard) + + // Verify metrics for each shard + for shard, expectedCount := range peerCountByShard { + value := getGaugeVecValue(metrics.PeersByShard, strconv.FormatUint(uint64(shard), 10)) + require.Equal(t, float64(expectedCount), value) + } +} + +func TestClient_PushErrorSendingEnvelope(t *testing.T) { + client := createTestClient(t) + + msg := &pb.WakuMessage{ + Payload: []byte("test-payload"), + ContentTopic: "test-content", + } + envelope := v2protocol.NewEnvelope(msg, 0, "") + + errorSendingEnvelope := wakuv2.ErrorSendingEnvelope{ + SentEnvelope: wakuv2.SentEnvelope{ + Envelope: envelope, + PublishMethod: publish.LightPush, + }, + Error: errTest, + } + + client.PushErrorSendingEnvelope(errorSendingEnvelope) + + value := getCounterValue(metrics.EnvelopeSentErrors, + envelope.PubsubTopic(), + envelope.Message().ContentTopic, + ) + require.Equal(t, float64(1), value) +} + +func TestClient_PushRawMessageByType(t *testing.T) { + client := createTestClient(t) + + pubsubTopic := "test-pubsub-topic" + contentTopic := "test-content-topic" + messageType := "test-message-type" + client.PushRawMessageByType(pubsubTopic, contentTopic, messageType, 10) + + value := getCounterValue(metrics.RawMessagesSentTotal, messageType, pubsubTopic, contentTopic) + require.Equal(t, float64(1), value) + + valueBytes := getCounterValue(metrics.RawMessagesSizeBytes, messageType, pubsubTopic, contentTopic) + require.Equal(t, float64(10), valueBytes) +} diff --git a/messaging/wakumetrics/metrics.go b/messaging/wakumetrics/metrics.go new file mode 100644 index 0000000000..a47db9f176 --- /dev/null +++ b/messaging/wakumetrics/metrics.go @@ -0,0 +1,187 @@ +package wakumetrics + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type MetricsCollection struct { + MessagesSentTotal *prometheus.CounterVec + EnvelopeSentTotal *prometheus.CounterVec + MessagesReceivedTotal *prometheus.CounterVec + WakuMessagesSizeBytes *prometheus.CounterVec + EnvelopeSentErrors *prometheus.CounterVec + PeerDialFailures *prometheus.CounterVec + MissedMessages *prometheus.CounterVec + NodePeerId *prometheus.GaugeVec + MessageDeliveryConfirmations prometheus.Counter + PeerConnectionFailures prometheus.Counter + StoreQuerySuccesses prometheus.Counter + StoreQueryFailures prometheus.Counter + PeersByOrigin *prometheus.GaugeVec + PeersByShard *prometheus.GaugeVec + RawMessagesSizeBytes *prometheus.CounterVec + RawMessagesSentTotal *prometheus.CounterVec +} + +var metrics = MetricsCollection{ + MessagesSentTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_messages_sent_total", + Help: "Frequency of Waku messages sent by this node", + }, + []string{"publish_method"}, + ), + + EnvelopeSentTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_envelope_sent_total", + Help: "Total number of envelopes sent by this node", + }, + []string{"pubsub_topic", "content_topic", "publish_method"}, + ), + + MessagesReceivedTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_messages_received_total", + Help: "Frequency of Status messages received", + }, + []string{"pubsub_topic", "content_topic", "chat_id"}, + ), + + WakuMessagesSizeBytes: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_message_size_bytes", + Help: "Size of each Waku message in bytes sent by this node", + }, + []string{"publish_method"}, + ), + + EnvelopeSentErrors: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_envelope_sent_errors_total", + Help: "Frequency of errors occurred when sending an envelope", + }, + []string{"pubsub_topic", "content_topic"}, + ), + + MessageDeliveryConfirmations: prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "waku_message_delivery_confirmations_total", + Help: "Frequency of message delivery confirmations", + }, + ), + + PeersByOrigin: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "waku_peers_by_origin", + Help: "Number of peers by discovery origin", + }, + []string{"origin"}, + ), + + PeersByShard: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "waku_peers_by_shard", + Help: "Number of peers by shard", + }, + []string{"shard"}, + ), + + PeerConnectionFailures: prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "waku_peer_connection_failures_total", + Help: "Total number of peer connection failures", + }, + ), + + PeerDialFailures: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_peer_dial_failures_total", + Help: "Total number of peer dial failures by error type", + }, + []string{"error_type", "protocols"}, + ), + + StoreQuerySuccesses: prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "waku_store_query_successes_total", + Help: "Frequency of successful store confirmation queries", + }, + ), + + StoreQueryFailures: prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "waku_store_query_failures_total", + Help: "Frequency of failed store confirmation queries", + }, + ), + + MissedMessages: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_missed_messages_total", + Help: "Frequency of missed messages detected by store query", + }, + []string{"pubsub_topic", "content_topic"}, + ), + + NodePeerId: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "waku_peer_id", + Help: "Peer ID", + }, + []string{"peer_id"}, + ), + + RawMessagesSizeBytes: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_raw_message_size_bytes", + Help: "Size of each raw message in bytes sent by this node", + }, + []string{"message_type", "pubsub_topic", "content_topic"}, + ), + + RawMessagesSentTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "waku_raw_message_sent_total", + Help: "Total number of raw messages sent by this node", + }, + []string{"message_type", "pubsub_topic", "content_topic"}, + ), +} + +var collectors = []prometheus.Collector{ + metrics.MessagesSentTotal, + metrics.MessagesReceivedTotal, + metrics.WakuMessagesSizeBytes, + metrics.EnvelopeSentErrors, + metrics.MessageDeliveryConfirmations, + metrics.PeersByOrigin, + metrics.PeersByShard, + metrics.PeerConnectionFailures, + metrics.PeerDialFailures, + metrics.StoreQuerySuccesses, + metrics.StoreQueryFailures, + metrics.MissedMessages, + metrics.NodePeerId, + metrics.RawMessagesSizeBytes, + metrics.RawMessagesSentTotal, +} + +// RegisterMetrics registers all metrics with the provided registry +func RegisterMetrics() error { + for _, collector := range collectors { + if err := prometheus.Register(collector); err != nil { + return err + } + } + + return nil +} + +func UnregisterMetrics() error { + for _, collector := range collectors { + prometheus.Unregister(collector) + } + + return nil +} diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go new file mode 100644 index 0000000000..e3583ae80f --- /dev/null +++ b/metrics/metrics_test.go @@ -0,0 +1,119 @@ +package metrics + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/metrics" +) + +func createTestServer(t *testing.T) *Server { + server := NewMetricsServer(":8080", nil) + require.NotNil(t, server) + return server +} + +func TestNewMetricsServer(t *testing.T) { + server := NewMetricsServer(":8080", nil) + require.NotNil(t, server) + require.Equal(t, ":8080", server.server.Addr) +} + +func TestNewMetricsServer_WithRegistry(t *testing.T) { + registry := metrics.NewRegistry() + server := NewMetricsServer(":8080", registry) + require.NotNil(t, server) + + // Check that geth handler was registered + _, exists := server.handlers.Load("geth") + require.True(t, exists) +} + +func TestServer_RegisterHandler(t *testing.T) { + server := createTestServer(t) + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write([]byte("test")) + require.NoError(t, err) + }) + + server.RegisterHandler("test", handler) + + _, exists := server.handlers.Load("test") + require.True(t, exists) +} + +func TestServer_RegisterHandler_Nil(t *testing.T) { + server := createTestServer(t) + + // Register nil handler - should be ignored + server.RegisterHandler("nil-test", nil) + + _, exists := server.handlers.Load("nil-test") + require.False(t, exists) +} + +func TestServer_UnregisterHandler(t *testing.T) { + server := createTestServer(t) + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) + server.RegisterHandler("test", handler) + + // Verify it exists + _, exists := server.handlers.Load("test") + require.True(t, exists) + + // Unregister + server.UnregisterHandler("test") + + // Verify it's gone + _, exists = server.handlers.Load("test") + require.False(t, exists) +} + +func TestServer_MetricsHandler(t *testing.T) { + server := createTestServer(t) + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write([]byte("test-metrics")) + require.NoError(t, err) + }) + server.RegisterHandler("test", handler) + + req := httptest.NewRequest("GET", "/metrics", nil) + w := httptest.NewRecorder() + + metricsHandler := server.metricsHandler() + metricsHandler.ServeHTTP(w, req) + + require.Contains(t, w.Body.String(), "test-metrics") +} + +func TestHealthHandler(t *testing.T) { + handler := healthHandler() + + req := httptest.NewRequest("GET", "/health", nil) + w := httptest.NewRecorder() + + handler.ServeHTTP(w, req) + + require.Equal(t, http.StatusOK, w.Code) + require.Equal(t, "OK", w.Body.String()) +} + +func TestServer_Stop(t *testing.T) { + server := createTestServer(t) + + err := server.Stop() + require.NoError(t, err) +} + +func TestServer_Stop_NilServer(t *testing.T) { + server := &Server{server: nil} + + err := server.Stop() + require.NoError(t, err) +} diff --git a/multiaccounts/accounts/accounts_manager_adapter.go b/multiaccounts/accounts/accounts_manager_adapter.go new file mode 100644 index 0000000000..8b0a3b37de --- /dev/null +++ b/multiaccounts/accounts/accounts_manager_adapter.go @@ -0,0 +1,104 @@ +package accounts + +import ( + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +type AccountsManagerPersistenceAdapter struct { + db *Database +} + +func NewAccountsManagerPersistenceAdapter(db *Database) *AccountsManagerPersistenceAdapter { + return &AccountsManagerPersistenceAdapter{db: db} +} + +func (a *AccountsManagerPersistenceAdapter) AddressExists(address cryptotypes.Address) (bool, error) { + return a.db.AddressExists(address) +} + +func (a *AccountsManagerPersistenceAdapter) GetPath(address cryptotypes.Address) (string, error) { + return a.db.GetPath(address) +} + +func (a *AccountsManagerPersistenceAdapter) GetWalletRootAddress() (cryptotypes.Address, error) { + address, err := a.db.GetWalletRootAddress() + if err != nil { + return cryptotypes.ZeroAddress(), err + } + return address, nil +} + +func (a *AccountsManagerPersistenceAdapter) GetProfileKeypair() (*types.Keypair, error) { + dbKeypair, err := a.db.GetProfileKeypair() + if err != nil { + return nil, err + } + return KeypairToAccountsManagerKeypair(dbKeypair), nil +} + +func (a *AccountsManagerPersistenceAdapter) GetKeypairByKeyUID(keyUID string) (*types.Keypair, error) { + dbKeypair, err := a.db.GetKeypairByKeyUID(keyUID) + if err != nil { + if err == ErrDbKeypairNotFound { + return nil, types.ErrDbKeypairNotFound + } + return nil, err + } + return KeypairToAccountsManagerKeypair(dbKeypair), nil +} + +func (a *AccountsManagerPersistenceAdapter) GetActiveKeypairs() ([]*types.Keypair, error) { + dbKeypairs, err := a.db.GetActiveKeypairs() + if err != nil { + return nil, err + } + return KeypairsToAccountsManagerKeypairs(dbKeypairs), nil +} + +func (a *AccountsManagerPersistenceAdapter) SaveOrUpdateKeypair(keypair *types.Keypair) error { + dbKeypair := AccountsManagerKeypairToKeypair(keypair) + return a.db.SaveOrUpdateKeypair(dbKeypair) +} + +func (a *AccountsManagerPersistenceAdapter) SaveOrUpdateKeycard(keycard *types.Keycard, clock uint64, updateKeypairClock bool) error { + dbKeycard := AccountsManagerKeycardToKeycard(keycard) + return a.db.SaveOrUpdateKeycard(*dbKeycard, clock, updateKeypairClock) +} + +func (a *AccountsManagerPersistenceAdapter) MarkKeypairFullyOperable(keyUID string, clock uint64, updateKeypairClock bool) (err error) { + return a.db.MarkKeypairFullyOperable(keyUID, clock, updateKeypairClock) +} + +func (a *AccountsManagerPersistenceAdapter) MarkAccountFullyOperable(address cryptotypes.Address) (err error) { + return a.db.MarkAccountFullyOperable(address) +} + +func (a *AccountsManagerPersistenceAdapter) DeleteAllKeycardsWithKeyUID(keyUID string, clock uint64) (err error) { + return a.db.DeleteAllKeycardsWithKeyUID(keyUID, clock) +} + +func (a *AccountsManagerPersistenceAdapter) SaveOrUpdateAccounts(accounts []*types.Account, updateKeypairClock bool) error { + dbAccounts := AccountsManagerAccountsToAccounts(accounts) + return a.db.SaveOrUpdateAccounts(dbAccounts, updateKeypairClock) +} + +func (a *AccountsManagerPersistenceAdapter) GetPositionForNextNewAccount() (int64, error) { + return a.db.GetPositionForNextNewAccount() +} + +func (a *AccountsManagerPersistenceAdapter) GetAccountByAddress(address cryptotypes.Address) (*types.Account, error) { + dbAccount, err := a.db.GetAccountByAddress(address) + if err != nil { + return nil, err + } + return AccountToAccountsManagerAccount(dbAccount), nil +} + +func (a *AccountsManagerPersistenceAdapter) RemoveAccount(address cryptotypes.Address, clock uint64) error { + return a.db.RemoveAccount(address, clock) +} + +func (a *AccountsManagerPersistenceAdapter) RemoveKeypair(keyUID string, clock uint64) error { + return a.db.RemoveKeypair(keyUID, clock) +} diff --git a/multiaccounts/accounts/accounts_manager_types_mapper.go b/multiaccounts/accounts/accounts_manager_types_mapper.go new file mode 100644 index 0000000000..56516b850e --- /dev/null +++ b/multiaccounts/accounts/accounts_manager_types_mapper.go @@ -0,0 +1,163 @@ +package accounts + +import ( + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/multiaccounts/common" +) + +func KeypairToAccountsManagerKeypair(keypair *Keypair) *types.Keypair { + accountsManagerKeypair := &types.Keypair{ + KeyUID: keypair.KeyUID, + Name: keypair.Name, + Type: types.KeypairType(keypair.Type), + DerivedFrom: keypair.DerivedFrom, + LastUsedDerivationIndex: keypair.LastUsedDerivationIndex, + SyncedFrom: keypair.SyncedFrom, + Clock: keypair.Clock, + Removed: keypair.Removed, + } + + accountsManagerKeypair.Accounts = make([]*types.Account, len(keypair.Accounts)) + for i, account := range keypair.Accounts { + accountsManagerKeypair.Accounts[i] = AccountToAccountsManagerAccount(account) + } + + accountsManagerKeypair.Keycards = make([]*types.Keycard, len(keypair.Keycards)) + for i, keycard := range keypair.Keycards { + accountsManagerKeypair.Keycards[i] = KeycardToAccountsManagerKeycard(keycard) + } + + return accountsManagerKeypair +} + +func KeypairsToAccountsManagerKeypairs(keypairs []*Keypair) []*types.Keypair { + accountsManagerKeypairs := make([]*types.Keypair, len(keypairs)) + for i, keypair := range keypairs { + accountsManagerKeypairs[i] = KeypairToAccountsManagerKeypair(keypair) + } + return accountsManagerKeypairs +} + +func AccountsManagerKeypairToKeypair(keypair *types.Keypair) *Keypair { + dbKeypair := &Keypair{ + KeyUID: keypair.KeyUID, + Name: keypair.Name, + Type: KeypairType(keypair.Type), + DerivedFrom: keypair.DerivedFrom, + LastUsedDerivationIndex: keypair.LastUsedDerivationIndex, + SyncedFrom: keypair.SyncedFrom, + Clock: keypair.Clock, + Removed: keypair.Removed, + } + + dbKeypair.Accounts = make([]*Account, len(keypair.Accounts)) + for i, account := range keypair.Accounts { + dbKeypair.Accounts[i] = AccountsManagerAccountToAccount(account) + } + + dbKeypair.Keycards = make([]*Keycard, len(keypair.Keycards)) + for i, keycard := range keypair.Keycards { + dbKeypair.Keycards[i] = AccountsManagerKeycardToKeycard(keycard) + } + + return dbKeypair +} + +func AccountToAccountsManagerAccount(account *Account) *types.Account { + return &types.Account{ + Address: account.Address, + KeyUID: account.KeyUID, + Wallet: account.Wallet, + AddressWasNotShown: account.AddressWasNotShown, + Chat: account.Chat, + Type: types.AccountType(account.Type), + Path: account.Path, + PublicKey: account.PublicKey, + Name: account.Name, + Emoji: account.Emoji, + ColorID: string(account.ColorID), + Hidden: account.Hidden, + Clock: account.Clock, + Removed: account.Removed, + Operable: types.AccountOperable(account.Operable), + CreatedAt: account.CreatedAt, + Position: account.Position, + ProdPreferredChainIDs: account.ProdPreferredChainIDs, + TestPreferredChainIDs: account.TestPreferredChainIDs, + } +} + +func AccountsManagerAccountToAccount(account *types.Account) *Account { + return &Account{ + Address: account.Address, + KeyUID: account.KeyUID, + Wallet: account.Wallet, + AddressWasNotShown: account.AddressWasNotShown, + Chat: account.Chat, + Type: AccountType(account.Type), + Path: account.Path, + PublicKey: account.PublicKey, + Name: account.Name, + Emoji: account.Emoji, + ColorID: common.CustomizationColor(account.ColorID), + Hidden: account.Hidden, + Clock: account.Clock, + Removed: account.Removed, + Operable: AccountOperable(account.Operable), + CreatedAt: account.CreatedAt, + Position: account.Position, + ProdPreferredChainIDs: account.ProdPreferredChainIDs, + TestPreferredChainIDs: account.TestPreferredChainIDs, + } +} + +func AccountsManagerAccountsToAccounts(accounts []*types.Account) []*Account { + dbAccounts := make([]*Account, len(accounts)) + for i, account := range accounts { + dbAccounts[i] = AccountsManagerAccountToAccount(account) + } + return dbAccounts +} + +func AccountsToAccountsManagerAccounts(accounts []*Account) []*types.Account { + accountsManagerAccounts := make([]*types.Account, len(accounts)) + for i, account := range accounts { + accountsManagerAccounts[i] = AccountToAccountsManagerAccount(account) + } + return accountsManagerAccounts +} + +func KeycardToAccountsManagerKeycard(keycard *Keycard) *types.Keycard { + accountsManagerKeycard := &types.Keycard{ + KeycardUID: keycard.KeycardUID, + KeycardName: keycard.KeycardName, + KeyUID: keycard.KeyUID, + Position: keycard.Position, + KeycardLocked: keycard.KeycardLocked, + } + + accountsManagerKeycard.AccountsAddresses = make([]cryptotypes.Address, len(keycard.AccountsAddresses)) + for i, accountAddress := range keycard.AccountsAddresses { + accountsManagerKeycard.AccountsAddresses[i] = cryptotypes.HexToAddress(accountAddress.Hex()) + } + + return accountsManagerKeycard +} + +func AccountsManagerKeycardToKeycard(keycard *types.Keycard) *Keycard { + dbKeycard := &Keycard{ + KeycardUID: keycard.KeycardUID, + KeycardName: keycard.KeycardName, + KeyUID: keycard.KeyUID, + Position: keycard.Position, + KeycardLocked: keycard.KeycardLocked, + } + + dbKeycard.AccountsAddresses = make([]cryptotypes.Address, len(keycard.AccountsAddresses)) + for i, accountAddress := range keycard.AccountsAddresses { + dbKeycard.AccountsAddresses[i] = cryptotypes.HexToAddress(accountAddress.Hex()) + } + + return dbKeycard +} diff --git a/multiaccounts/settings/events.go b/multiaccounts/settings/events.go new file mode 100644 index 0000000000..79b59d3ad2 --- /dev/null +++ b/multiaccounts/settings/events.go @@ -0,0 +1,6 @@ +package settings + +type EventSettingChanged struct { + Setting SettingField + Value any +} diff --git a/node/backup/controller.go b/node/backup/controller.go new file mode 100644 index 0000000000..551a7dbefb --- /dev/null +++ b/node/backup/controller.go @@ -0,0 +1,144 @@ +package backup + +import ( + "errors" + "os" + "path/filepath" + "sync" + "time" + + "go.uber.org/zap" + + "github.com/status-im/status-go/common" +) + +type BackupConfig struct { + PrivateKey []byte + FileNameGetter func() (string, error) + BackupEnabled bool + Interval time.Duration +} + +type BackupProvider interface { + ExportBackup() ([]byte, error) + ImportBackup(data []byte) error +} + +type Controller struct { + config BackupConfig + core *core + logger *zap.Logger + quit chan struct{} + mutex sync.Mutex + wg *sync.WaitGroup +} + +func NewController(config BackupConfig, logger *zap.Logger) (*Controller, error) { + if len(config.PrivateKey) == 0 { + return nil, errors.New("private key must be provided") + } + if config.FileNameGetter == nil { + return nil, errors.New("filename getter must be provided") + } + + return &Controller{ + config: config, + core: newCore(), + logger: logger, + wg: &sync.WaitGroup{}, + quit: make(chan struct{}), + }, nil +} + +func (c *Controller) Register(componentName string, provider BackupProvider) { + c.mutex.Lock() + defer c.mutex.Unlock() + + c.core.Register(componentName, provider) +} + +func (c *Controller) Start() { + if !c.config.BackupEnabled { + return + } + c.wg.Add(1) + + go func() { + defer common.LogOnPanic() + ticker := time.NewTicker(c.config.Interval) + defer ticker.Stop() + defer c.wg.Done() + for { + select { + case <-ticker.C: + _, err := c.PerformBackup() + if err != nil { + c.logger.Error("Error performing backup: %v\n", zap.Error(err)) + } + case <-c.quit: + return + } + } + }() +} + +func (c *Controller) Stop() { + close(c.quit) + c.wg.Wait() +} + +func (c *Controller) PerformBackup() (string, error) { + c.mutex.Lock() + defer c.mutex.Unlock() + + backupData, err := c.core.Create(c.config.PrivateKey) + if err != nil { + return "", err + } + + fileName, err := c.config.FileNameGetter() + if err != nil { + return "", err + } + + if err := os.MkdirAll(filepath.Dir(fileName), 0700); err != nil { + return "", err + } + + file, err := os.Create(fileName) + if err != nil { + return "", err + } + defer file.Close() + + _, err = file.Write(backupData) + if err != nil { + return "", err + } + + return fileName, nil +} + +func (c *Controller) LoadBackup(filePath string) error { + c.mutex.Lock() + defer c.mutex.Unlock() + + file, err := os.Open(filePath) + if err != nil { + return err + } + defer file.Close() + + fileInfo, err := file.Stat() + if err != nil { + return err + } + + backupData := make([]byte, fileInfo.Size()) + _, err = file.Read(backupData) + if err != nil { + return err + } + + return c.core.Restore(c.config.PrivateKey, backupData) +} diff --git a/node/backup/controller_test.go b/node/backup/controller_test.go new file mode 100644 index 0000000000..7fd0ae4bde --- /dev/null +++ b/node/backup/controller_test.go @@ -0,0 +1,94 @@ +package backup + +import ( + "encoding/json" + "encoding/xml" + "reflect" + "testing" + + "github.com/brianvoe/gofakeit/v6" + + "go.uber.org/zap" + + "github.com/stretchr/testify/require" +) + +type Foo struct { + Value int + PreciseValue float64 +} + +type Bar struct { + Names []string + Surname string +} + +type FooProvider struct { + foo Foo +} + +func (f FooProvider) ExportBackup() ([]byte, error) { + return json.Marshal(f.foo) +} + +var fooFromBackup Foo + +func (b FooProvider) ImportBackup(data []byte) error { + return json.Unmarshal(data, &fooFromBackup) +} + +type BarProvider struct { + bar Bar +} + +func (b BarProvider) ExportBackup() ([]byte, error) { + return xml.Marshal(b.bar) +} + +var barFromBackup Bar + +func (b BarProvider) ImportBackup(data []byte) error { + return xml.Unmarshal(data, &barFromBackup) +} + +func TestController(t *testing.T) { + logger, err := zap.NewDevelopment() + require.NoError(t, err) + filename := t.TempDir() + "/test_backup.bak" + controller, err := NewController(BackupConfig{ + FileNameGetter: func() (string, error) { return filename, nil }, + PrivateKey: []byte("0123456789abcdef0123456789abcdef"), + }, logger) + require.NoError(t, err) + + foo := Foo{} + bar := Bar{} + err = gofakeit.Struct(&foo) + require.NoError(t, err) + err = gofakeit.Struct(&bar) + require.NoError(t, err) + + fooProvider := FooProvider{ + foo: foo, + } + + barProvider := BarProvider{ + bar: bar, + } + + controller.Register("foo", fooProvider) + controller.Register("bar", barProvider) + + filename, err = controller.PerformBackup() + require.NoError(t, err) + require.Equal(t, filename, filename) + + require.False(t, reflect.DeepEqual(barProvider.bar, barFromBackup)) + require.False(t, reflect.DeepEqual(fooProvider.foo, fooFromBackup)) + + err = controller.LoadBackup(filename) + require.NoError(t, err) + + require.True(t, reflect.DeepEqual(barProvider.bar, barFromBackup)) + require.True(t, reflect.DeepEqual(fooProvider.foo, fooFromBackup)) +} diff --git a/node/backup/core.go b/node/backup/core.go new file mode 100644 index 0000000000..5ce6d33c1c --- /dev/null +++ b/node/backup/core.go @@ -0,0 +1,115 @@ +package backup + +import ( + "bytes" + "encoding/gob" + "errors" + "fmt" + + "github.com/status-im/status-go/crypto" +) + +type core struct { + backupProviders map[string]BackupProvider +} + +func newCore() *core { + return &core{ + backupProviders: make(map[string]BackupProvider), + } +} + +func (c *core) Register( + componentName string, + provider BackupProvider, +) { + c.backupProviders[componentName] = provider +} + +func (b *core) Create(privateKey []byte) ([]byte, error) { + backup, err := b.exportBackup() + if err != nil { + return nil, fmt.Errorf("exportBackup failed: %w", err) + } + + data, err := marshal(backup) + if err != nil { + return nil, fmt.Errorf("marshal failed: %w", err) + } + + encryptedData, err := crypto.EncryptSymmetric(privateKey, data) + if err != nil { + return nil, fmt.Errorf("encrypt failed: %w", err) + } + + return encryptedData, nil +} + +func (b *core) Restore(privateKey []byte, encrypted []byte) error { + decrypted, err := crypto.DecryptSymmetric(privateKey, encrypted) + if err != nil { + return fmt.Errorf("decrypt failed: %w", err) + } + + data, err := unmarshal(decrypted) + if err != nil { + return fmt.Errorf("unmarshal failed: %w", err) + } + + err = b.importBackup(data) + if err != nil { + return fmt.Errorf("importBackup failed: %w", err) + } + + return nil +} + +func (b *core) exportBackup() (map[string][]byte, error) { + result := make(map[string][]byte, len(b.backupProviders)) + + for name, provider := range b.backupProviders { + raw, err := provider.ExportBackup() + if err != nil { + return nil, err + } + result[name] = raw + } + + return result, nil +} + +func (b *core) importBackup(data map[string][]byte) error { + var errs []error + for name, provider := range b.backupProviders { + raw, ok := data[name] + if !ok { + continue + } + if err := provider.ImportBackup(raw); err != nil { + errs = append(errs, fmt.Errorf("importBackup %q failed: %w", name, err)) + } + } + + return errors.Join(errs...) +} + +func marshal(data map[string][]byte) ([]byte, error) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(data) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func unmarshal(data []byte) (map[string][]byte, error) { + buf := bytes.NewReader(data) + dec := gob.NewDecoder(buf) + var result map[string][]byte + err := dec.Decode(&result) + if err != nil { + return nil, err + } + return result, nil +} diff --git a/params/storenode_test.go b/params/storenode_test.go new file mode 100644 index 0000000000..30ce46b2ec --- /dev/null +++ b/params/storenode_test.go @@ -0,0 +1,28 @@ +package params_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + messagingtypes "github.com/status-im/status-go/messaging/types" + "github.com/status-im/status-go/params" +) + +func TestStoreNode_UnmarshalJSON(t *testing.T) { + fleets := params.GetSupportedFleets() + + for _, fleet := range fleets { + for _, storeNode := range fleet.StoreNodes { + jsonData, err := json.Marshal(storeNode) + require.NoError(t, err) + + var unmarshalled messagingtypes.StoreNode + err = json.Unmarshal(jsonData, &unmarshalled) + require.NoError(t, err) + + require.Equal(t, storeNode, unmarshalled) + } + } +} diff --git a/pkg/pubsub/README.md b/pkg/pubsub/README.md new file mode 100644 index 0000000000..6cab1677d1 --- /dev/null +++ b/pkg/pubsub/README.md @@ -0,0 +1,224 @@ +# pubsub + +A type-safe, generic publish-subscribe pattern implementation for Go. + +## Overview + +The `pubsub` package provides a thread-safe, type-safe implementation of the publish-subscribe pattern using Go generics. It allows different parts of your application to communicate through typed events without direct coupling. + +## Key Features + +- **Type Safety**: Uses Go generics to ensure type safety at compile time +- **Thread Safe**: All operations are protected by appropriate mutexes +- **Non-blocking**: Publishers never block, events are dropped if subscribers can't keep up +- **Automatic Cleanup**: Channels are automatically closed when unsubscribing +- **Multiple Event Types**: Single publisher can handle multiple different event types +- **Buffer Control**: Configurable buffer sizes for subscriber channels + +## API Reference + +### Core Functions + +#### `NewPublisher() *Publisher` +Creates a new publisher instance that can handle multiple event types. + +#### `Publish[T any](p *Publisher, val T)` +Publishes a value of type `T` to all subscribers of that type. This operation is non-blocking. + +#### `Subscribe[T any](p *Publisher, bufferSize uint) (chan T, UnsubFn)` +Subscribes to events of type `T` and returns a channel to receive events and an unsubscribe function. + +### Publisher Methods + +#### `Close()` +Closes the publisher and all its subscriptions, cleaning up resources. + +## Usage Examples + +### Basic Usage + +```go +package main + +import ( + "fmt" + "time" + "github.com/status-im/status-go/pkg/pubsub" +) + +func main() { + // Create a publisher + publisher := pubsub.NewPublisher() + defer publisher.Close() + + // Define event types + type UserEvent struct { + UserID string + Action string + Timestamp time.Time + } + + type SystemEvent struct { + Level string + Message string + } + + // Subscribe to UserEvent + userCh, unsubUser := pubsub.Subscribe[UserEvent](publisher, 10) + defer unsubUser() + + // Subscribe to SystemEvent + systemCh, unsubSystem := pubsub.Subscribe[SystemEvent](publisher, 5) + defer unsubSystem() + + // Start listening for events + go func() { + for event := range userCh { + fmt.Printf("User event: %+v\n", event) + } + }() + + go func() { + for event := range systemCh { + fmt.Printf("System event: %+v\n", event) + } + }() + + // Publish events + pubsub.Publish(publisher, UserEvent{ + UserID: "user123", + Action: "login", + Timestamp: time.Now(), + }) + + pubsub.Publish(publisher, SystemEvent{ + Level: "info", + Message: "Server started", + }) +} +``` + +### Working with Different Types + +```go +// Integer events +intCh, unsubInt := pubsub.Subscribe[int](publisher, 100) +defer unsubInt() + +// String events +stringCh, unsubString := pubsub.Subscribe[string](publisher, 50) +defer unsubString() + +// Custom struct events +type CustomEvent struct { + ID int + Data string +} + +customCh, unsubCustom := pubsub.Subscribe[CustomEvent](publisher, 25) +defer unsubCustom() + +// Publish different types +pubsub.Publish(publisher, 42) +pubsub.Publish(publisher, "hello world") +pubsub.Publish(publisher, CustomEvent{ID: 1, Data: "test"}) +``` + +### Multiple Subscribers + +```go +// Multiple subscribers for the same event type +ch1, unsub1 := pubsub.Subscribe[UserEvent](publisher, 10) +ch2, unsub2 := pubsub.Subscribe[UserEvent](publisher, 10) +ch3, unsub3 := pubsub.Subscribe[UserEvent](publisher, 10) + +defer unsub1() +defer unsub2() +defer unsub3() + +// All three subscribers will receive the same event +pubsub.Publish(publisher, UserEvent{UserID: "user1", Action: "login"}) +``` + +### Buffer Management + +```go +// Unbuffered channel (bufferSize = 0) +// Events will be dropped if subscriber can't keep up +ch, unsub := pubsub.Subscribe[UserEvent](publisher, 0) +defer unsub() + +// Large buffer for high-throughput scenarios +highThroughputCh, unsubHigh := pubsub.Subscribe[UserEvent](publisher, 1000) +defer unsubHigh() +``` + +## Best Practices + +### 1. Always Clean Up +Always call the unsubscribe function returned by `Subscribe` to prevent memory leaks: + +```go +ch, unsub := pubsub.Subscribe[MyEvent](publisher, 10) +defer unsub() // Important! +``` + +### 2. Choose Appropriate Buffer Sizes +- Use smaller buffers for low-frequency events or events that are processed quickly +- Use larger buffers for high-frequency events or events that take longer to process +- Use unbuffered channels (0) when you want to drop events if subscribers can't keep up +- For events that require heavy processing, consider doing the work in a separate goroutine to release the channel quickly: + +```go +ch, unsub := pubsub.Subscribe[HeavyEvent](publisher, 10) +defer unsub() + +for event := range ch { + // Process the event in a separate goroutine to avoid blocking the channel + go func(e HeavyEvent) { + // Do heavy processing here + processHeavyEvent(e) + }(event) +} +``` + +### 3. Handle Channel Closure +Always check if channels are closed in your event processing loops: + +```go +for event := range ch { + // Process event +} +// Channel is closed when loop exits +``` + +### 4. Publisher Lifecycle +Always close the publisher when you're done with it: + +```go +publisher := pubsub.NewPublisher() +defer publisher.Close() +``` + +## Thread Safety + +All operations in the pubsub package are thread-safe: +- Multiple goroutines can publish events simultaneously +- Multiple goroutines can subscribe/unsubscribe simultaneously +- Event delivery is safe across concurrent operations + +## Error Handling + +The pubsub package is designed to be robust: +- Publishing to a closed publisher is safe (events are ignored) +- Subscribing to a closed publisher is safe (returns closed channel) +- Unsubscribing multiple times is safe (idempotent) +- Events are dropped if subscriber channels are full (non-blocking behavior) + +## Examples in Tests + +For more comprehensive examples, see the test file `pubsub_test.go` which demonstrates: +- Working with different data types (int, string, struct, slice, map, channel, function, interface) +- Multiple subscribers +- Unsubscription behavior +- Concurrent operations \ No newline at end of file diff --git a/pkg/pubsub/publisher.go b/pkg/pubsub/publisher.go new file mode 100644 index 0000000000..86e4ec9c51 --- /dev/null +++ b/pkg/pubsub/publisher.go @@ -0,0 +1,35 @@ +package pubsub + +import ( + "reflect" + "sync" +) + +// Publisher manages subscriptions to events of different types. +type Publisher struct { + subsPerType *sync.Map // map[reflect.Type]*TypePublisher[T] +} + +func NewPublisher() *Publisher { + return &Publisher{ + subsPerType: &sync.Map{}, + } +} + +type closeable interface { + Close() +} + +func (p *Publisher) Close() { + p.subsPerType.Range(func(key any, value any) bool { + value.(closeable).Close() + return true + }) + p.subsPerType = &sync.Map{} +} + +func getTypePublisher[T any](p *Publisher) *TypePublisher[T] { + typeOfT := reflect.TypeFor[T]() + subs, _ := p.subsPerType.LoadOrStore(typeOfT, NewTypePublisher[T]()) + return subs.(*TypePublisher[T]) +} diff --git a/pkg/pubsub/pubsub.go b/pkg/pubsub/pubsub.go new file mode 100644 index 0000000000..b8abe0636c --- /dev/null +++ b/pkg/pubsub/pubsub.go @@ -0,0 +1,24 @@ +package pubsub + +// Publish will send the value val of type T on the specified Publisher in a +// non-blocking manner. Subscribers for which the channel buffer is full will +// not receive the event. +func Publish[T any](p *Publisher, val T) { + subs := getTypePublisher[T](p) + subs.Publish(val) +} + +// Subscribe creates a channel with the specified buffer size to listen for events of +// type T published by the Publisher. +// The returned channel will be closed by the Publisher. +// UnsubFn must be called by the subscriber before it becomes unable to process events. +func Subscribe[T any](p *Publisher, bufferSize uint) (chan T, UnsubFn) { + subs := getTypePublisher[T](p) + ch := subs.Subscribe(bufferSize) + + unsub := func() { + subs.Unsubscribe(ch) + } + + return ch, unsub +} diff --git a/pkg/pubsub/pubsub_test.go b/pkg/pubsub/pubsub_test.go new file mode 100644 index 0000000000..31d1774587 --- /dev/null +++ b/pkg/pubsub/pubsub_test.go @@ -0,0 +1,300 @@ +package pubsub_test + +import ( + "testing" + "time" + + "github.com/status-im/status-go/pkg/pubsub" + + "github.com/brianvoe/gofakeit/v7" + + "github.com/stretchr/testify/assert" +) + +func TestPubSub_Int(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + testingCh, unsub := pubsub.Subscribe[int](publisher, 10) + defer unsub() + + val := gofakeit.Int() + pubsub.Publish(publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Ptr(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + testingCh, unsub := pubsub.Subscribe[*string](publisher, 10) + defer unsub() + + str := gofakeit.Word() + val := &str + pubsub.Publish(publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Struct(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + type testStruct struct { + Foo int + Bar string + } + + testingCh, unsub := pubsub.Subscribe[testStruct](publisher, 10) + defer unsub() + + var val testStruct + err := gofakeit.Struct(&val) + assert.NoError(t, err) + + pubsub.Publish(publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Slice(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + type testSlice []int + + testingCh, unsub := pubsub.Subscribe[testSlice](publisher, 10) + defer unsub() + + val := make(testSlice, 5) + gofakeit.Slice(&val) + + pubsub.Publish(publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Map(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + type testMap map[string]int + + testingCh, unsub := pubsub.Subscribe[testMap](publisher, 10) + defer unsub() + + val := make(testMap, 5) + for range 5 { + val[gofakeit.Word()] = gofakeit.Int() + } + + pubsub.Publish(publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Chan(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + type testChan chan any + + testingCh, unsub := pubsub.Subscribe[testChan](publisher, 10) + defer unsub() + + val := make(testChan) + + pubsub.Publish(publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Fn(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + type testFunc func() int + + testingCh, unsub := pubsub.Subscribe[testFunc](publisher, 10) + defer unsub() + + count := 0 + val := func() int { + count++ + return count + } + + countVal := val() + assert.Equal(t, 1, countVal) + assert.Equal(t, count, countVal) + + pubsub.Publish[testFunc](publisher, val) + + incVal, ok := <-testingCh + + assert.True(t, ok) + countVal = incVal() + assert.Equal(t, 2, countVal) + assert.Equal(t, count, countVal) +} + +type testInterface interface { + Testing() +} + +type testImpl struct { +} + +func (t testImpl) Testing() {} + +func TestPubSub_Intf(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + testingCh, unsub := pubsub.Subscribe[testInterface](publisher, 10) + defer unsub() + + val := testImpl{} + pubsub.Publish[testInterface](publisher, val) + + incVal, ok := <-testingCh + assert.True(t, ok) + assert.Equal(t, val, incVal) +} + +func TestPubSub_Unsub(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + testingCh, unsub := pubsub.Subscribe[int](publisher, 10) + + unsub() + + _, ok := <-testingCh + assert.False(t, ok) +} + +// This test only fails if it panics +func TestPubSub_NoSub(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + assert.NotPanics(t, func() { + pubsub.Publish(publisher, gofakeit.Int()) + }) +} + +func TestPubSub_Multi(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + const pubIntCount = 50 + sentInt := make([]int, pubIntCount) + gofakeit.Slice(&sentInt) + const pubStringCount = 20 + sentString := make([]string, pubStringCount) + gofakeit.Slice(&sentString) + + chInt1, unsubInt1 := pubsub.Subscribe[int](publisher, pubIntCount) + recvInt1 := make([]int, 0, pubIntCount) + go func() { + for val := range chInt1 { + recvInt1 = append(recvInt1, val) + } + }() + defer unsubInt1() + + chInt2, unsubInt2 := pubsub.Subscribe[int](publisher, pubIntCount) + recvInt2 := make([]int, 0, pubIntCount) + go func() { + for val := range chInt2 { + recvInt2 = append(recvInt2, val) + } + }() + defer unsubInt2() + + chString1, unsubString1 := pubsub.Subscribe[string](publisher, pubStringCount) + recvString1 := make([]string, 0, pubStringCount) + go func() { + for val := range chString1 { + recvString1 = append(recvString1, val) + } + }() + defer unsubString1() + + for _, val := range sentInt { + pubsub.Publish(publisher, val) + } + for _, val := range sentString { + pubsub.Publish(publisher, val) + } + + assert.EventuallyWithT(t, func(collect *assert.CollectT) { + assert.Equal(collect, sentInt, recvInt1) + assert.Equal(collect, sentInt, recvInt2) + assert.Equal(collect, sentString, recvString1) + }, 1*time.Second, 100*time.Millisecond) +} + +func TestPubSub_Buffer(t *testing.T) { + publisher := pubsub.NewPublisher() + defer publisher.Close() + + const pubIntCount = 10 + sentInt := make([]int, pubIntCount) + gofakeit.Slice(&sentInt) + + chInt, unsubInt := pubsub.Subscribe[int](publisher, 0) // Unbuffered channel + recvInt1 := make([]int, 0, pubIntCount) + + // Channel not ready to receive, so the events are dropped. + for _, val := range sentInt { + pubsub.Publish(publisher, val) + } + + quitCh := make(chan struct{}) + defer close(quitCh) + + const sendDelay = 50 * time.Millisecond + go func() { + for { + select { + case <-quitCh: + return + case val := <-chInt: + recvInt1 = append(recvInt1, val) + // Keep channel busy + time.Sleep(2 * sendDelay) // Take twice as long to process as the events are sent, about half events will be dropped. + } + } + }() + defer unsubInt() + + for _, val := range sentInt { + pubsub.Publish(publisher, val) + time.Sleep(sendDelay) + } + + assert.Subset(t, sentInt, recvInt1) + assert.Less(t, len(recvInt1), len(sentInt)) +} diff --git a/pkg/pubsub/type_publisher.go b/pkg/pubsub/type_publisher.go new file mode 100644 index 0000000000..7fa89d78ab --- /dev/null +++ b/pkg/pubsub/type_publisher.go @@ -0,0 +1,112 @@ +package pubsub + +import ( + "sync" +) + +// subscription represents a subscription to a publisher. +type subscription[T any] struct { + mu sync.RWMutex // protects the channel from being closed while a value is being published to it + ch chan T +} + +func newSubscription[T any](bufferSize uint) *subscription[T] { + return &subscription[T]{ + ch: make(chan T, bufferSize), + } +} + +// Send the value val to the channel if it is not full. If the channel is busy, +// the event is dropped and the subscriber won't be notified. +// The channel is protected from being closed while a value is being sent to it. +func (s *subscription[T]) Send(val T) { + s.mu.RLock() + defer s.mu.RUnlock() + + select { + case s.ch <- val: + default: + // Drop event if buffer is full + } +} + +// Close the channel, ensuring no value is being sent to it +func (s *subscription[T]) Close() { + s.mu.Lock() + defer s.mu.Unlock() + + close(s.ch) +} + +type UnsubFn = func() + +// TypePublisher manages subscriptions to events of a single type. +type TypePublisher[T any] struct { + mu sync.RWMutex // protects the subs map and closed flag + subs map[chan T]*subscription[T] + closed bool +} + +func NewTypePublisher[T any]() *TypePublisher[T] { + return &TypePublisher[T]{ + subs: make(map[chan T]*subscription[T]), + closed: false, + } +} + +func (p *TypePublisher[T]) Publish(val T) { + p.mu.RLock() + defer p.mu.RUnlock() + + if p.closed { + return + } + + for _, sub := range p.subs { + sub.Send(val) + } +} + +func (p *TypePublisher[T]) Subscribe(bufferSize uint) chan T { + p.mu.Lock() + defer p.mu.Unlock() + + sub := newSubscription[T](bufferSize) + p.subs[sub.ch] = sub + return sub.ch +} + +func (p *TypePublisher[T]) Unsubscribe(ch chan T) { + p.mu.Lock() + defer p.mu.Unlock() + + sub, ok := p.subs[ch] + if !ok { + return + } + delete(p.subs, ch) + sub.Close() +} + +func (p *TypePublisher[T]) Close() { + p.mu.Lock() + defer p.mu.Unlock() + + if p.closed { + return + } + + p.closed = true + subs := p.subs + for _, sub := range subs { + sub.Close() + } + p.subs = make(map[chan T]*subscription[T]) +} + +func (p *TypePublisher[T]) IsClosed() bool { + p.mu.RLock() + defer p.mu.RUnlock() + + return p.closed +} diff --git a/protocol/accounts_manager_interface.go b/protocol/accounts_manager_interface.go new file mode 100644 index 0000000000..e7ab51132b --- /dev/null +++ b/protocol/accounts_manager_interface.go @@ -0,0 +1,29 @@ +package protocol + +import ( + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/accounts-management/types" + cryptotypes "github.com/status-im/status-go/crypto/types" +) + +//go:generate mockgen -package=mock_protocol_accounts_manager -source=accounts_manager_interface.go -destination=mock/messenger_accounts_manager.go + +// AccountsManager interface for mocking purposes +type AccountsManager interface { + GetVerifiedWalletAccount(address cryptotypes.Address, password string) (*generator.Account, error) + DeleteAccount(address cryptotypes.Address, clock uint64) (account *types.Account, err error) + DeleteKeypair(keyUID string, clock uint64) (keypair *types.Keypair, err error) + DeleteKeystoreFileForAccount(address cryptotypes.Address) error + DeleteKeystoreFilesForKeypair(keypair *types.Keypair) (err error) + MakeSeedPhraseKeypairFullyOperable(mnemonic string, password string, clock uint64) (string, error) + MakePrivateKeyKeypairFullyOperable(privateKey string, password string, clock uint64) (string, error) + SaveOrUpdateKeycard(keycard *types.Keycard, clock uint64, removeKeystoreFiles bool) error + AddAccounts(keyUID string, accounts []*types.Account, password string) error + CreateKeypairFromMnemonicAndStore(mnemonic string, password string, keypairName string, + walletAccount *types.AccountCreationDetails, profile bool, clock uint64) (keypair *types.Keypair, err error) + AddKeypairStoredToKeycard(keyUID string, masterAddress string, name string, + walletAccounts []*types.Account, clock uint64) (keypair *types.Keypair, err error) + CreateKeypairFromPrivateKeyAndStore(privateKey string, password string, keypairName string, + walletAccount *types.AccountCreationDetails, clock uint64) (keypair *types.Keypair, err error) + MigrateNonProfileKeycardKeypairToApp(mnemonic string, password string, clock uint64) (string, error) +} diff --git a/protocol/messaging_persistence.go b/protocol/messaging_persistence.go new file mode 100644 index 0000000000..03969d1b71 --- /dev/null +++ b/protocol/messaging_persistence.go @@ -0,0 +1,376 @@ +package protocol + +import ( + "context" + "crypto/ecdsa" + "database/sql" + "fmt" + "strings" + "time" + + "github.com/status-im/status-go/crypto" + cryptotypes "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/messaging/types" + messagingtypes "github.com/status-im/status-go/messaging/types" + "github.com/status-im/status-go/protocol/protobuf" +) + +const tableName = "wakuv2_keys" + +type messagingPersistence struct { + db *sql.DB +} + +var _ types.Persistence = (*messagingPersistence)(nil) + +func NewMessagingPersistence(db *sql.DB) *messagingPersistence { + return &messagingPersistence{db: db} +} + +func (s *messagingPersistence) AddWakuKey(chatID string, key []byte) error { + statement := fmt.Sprintf("INSERT INTO %s(chat_id, key) VALUES(?, ?)", tableName) // nolint:gosec + stmt, err := s.db.Prepare(statement) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec(chatID, key) + return err +} + +func (s *messagingPersistence) WakuKeys() (map[string][]byte, error) { + keys := make(map[string][]byte) + + statement := fmt.Sprintf("SELECT chat_id, key FROM %s", tableName) // nolint: gosec + + stmt, err := s.db.Prepare(statement) + if err != nil { + return nil, err + } + defer stmt.Close() + + rows, err := stmt.Query() + if err != nil && err != sql.ErrNoRows { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var ( + chatID string + key []byte + ) + + err := rows.Scan(&chatID, &key) + if err != nil { + return nil, err + } + keys[chatID] = key + } + + return keys, nil +} + +func (c *messagingPersistence) MessageCacheClear() error { + _, err := c.db.Exec("DELETE FROM transport_message_cache") + return err +} + +func (c *messagingPersistence) MessageCacheHits(ids []string) (map[string]bool, error) { + hits := make(map[string]bool) + + // Split the results into batches of 999 items. + // To prevent excessive memory allocations, the maximum value of a host parameter number + // is SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999 + batch := 999 + for i := 0; i < len(ids); i += batch { + j := i + batch + if j > len(ids) { + j = len(ids) + } + + currentBatch := ids[i:j] + + idsArgs := make([]interface{}, 0, len(currentBatch)) + for _, id := range currentBatch { + idsArgs = append(idsArgs, id) + } + + inVector := strings.Repeat("?, ", len(currentBatch)-1) + "?" + query := "SELECT id FROM transport_message_cache WHERE id IN (" + inVector + ")" // nolint: gosec + + rows, err := c.db.Query(query, idsArgs...) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var id string + err := rows.Scan(&id) + if err != nil { + return nil, err + } + hits[id] = true + } + } + + return hits, nil +} + +func (c *messagingPersistence) MessageCacheAdd(ids []string, timestamp uint64) (err error) { + var tx *sql.Tx + tx, err = c.db.BeginTx(context.Background(), &sql.TxOptions{}) + if err != nil { + return + } + + defer func() { + if err == nil { + err = tx.Commit() + return + } + // don't shadow original error + _ = tx.Rollback() + }() + + for _, id := range ids { + + var stmt *sql.Stmt + stmt, err = tx.Prepare(`INSERT INTO transport_message_cache(id,timestamp) VALUES (?, ?)`) + if err != nil { + return + } + defer stmt.Close() + + _, err = stmt.Exec(id, timestamp) + if err != nil { + return + } + } + + return +} + +func (c *messagingPersistence) MessageCacheClearOlderThan(timestamp uint64) error { + _, err := c.db.Exec(`DELETE FROM transport_message_cache WHERE timestamp < ?`, timestamp) + return err +} + +func (c *messagingPersistence) InsertPendingConfirmation(confirmation *messagingtypes.RawMessageConfirmation) error { + _, err := c.db.Exec(`INSERT INTO raw_message_confirmations + (datasync_id, message_id, public_key) + VALUES + (?,?,?)`, + confirmation.DataSyncID, + confirmation.MessageID, + confirmation.PublicKey, + ) + return err +} + +func (c *messagingPersistence) SaveHashRatchetMessage(groupID []byte, keyID []byte, m *messagingtypes.ReceivedMessage) error { + _, err := c.db.Exec(`INSERT INTO hash_ratchet_encrypted_messages(hash, sig, timestamp, topic, payload, dst, padding, group_id, key_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, m.Hash, m.Sig, m.Timestamp, m.Topic.Bytes(), m.Payload, m.Dst, m.Padding, groupID, keyID) + return err +} + +func (c *messagingPersistence) GetHashRatchetMessages(keyID []byte) ([]*messagingtypes.ReceivedMessage, error) { + var messages []*messagingtypes.ReceivedMessage + + rows, err := c.db.Query(`SELECT hash, sig, timestamp, topic, payload, dst, padding FROM hash_ratchet_encrypted_messages WHERE key_id = ?`, keyID) + if err != nil { + return nil, err + } + + for rows.Next() { + var topic []byte + message := &messagingtypes.ReceivedMessage{} + + err := rows.Scan(&message.Hash, &message.Sig, &message.Timestamp, &topic, &message.Payload, &message.Dst, &message.Padding) + if err != nil { + return nil, err + } + + message.Topic = messagingtypes.BytesToContentTopic(topic) + messages = append(messages, message) + } + + return messages, nil +} + +func (c *messagingPersistence) DeleteHashRatchetMessages(ids [][]byte) error { + if len(ids) == 0 { + return nil + } + + idsArgs := make([]interface{}, 0, len(ids)) + for _, id := range ids { + idsArgs = append(idsArgs, id) + } + inVector := strings.Repeat("?, ", len(ids)-1) + "?" + + _, err := c.db.Exec("DELETE FROM hash_ratchet_encrypted_messages WHERE hash IN ("+inVector+")", idsArgs...) // nolint: gosec + + return err +} + +func (c *messagingPersistence) DeleteHashRatchetMessagesOlderThan(timestamp int64) error { + _, err := c.db.Exec("DELETE FROM hash_ratchet_encrypted_messages WHERE timestamp < ?", timestamp) + return err +} + +func (c *messagingPersistence) IsMessageAlreadyCompleted(hash []byte) (bool, error) { + var alreadyCompleted int + err := c.db.QueryRow("SELECT COUNT(*) FROM message_segments_completed WHERE hash = ?", hash).Scan(&alreadyCompleted) + if err != nil { + return false, err + } + return alreadyCompleted > 0, nil +} + +func (c *messagingPersistence) SaveMessageSegment(segment *messagingtypes.SegmentMessage, sigPubKey *ecdsa.PublicKey, timestamp int64) error { + sigPubKeyBlob := crypto.CompressPubkey(sigPubKey) + + _, err := c.db.Exec("INSERT INTO message_segments (hash, segment_index, segments_count, parity_segment_index, parity_segments_count, sig_pub_key, payload, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + segment.EntireMessageHash, segment.Index, segment.SegmentsCount, segment.ParitySegmentIndex, segment.ParitySegmentsCount, sigPubKeyBlob, segment.Payload, timestamp) + + return err +} + +// Get ordered message segments for given hash +func (c *messagingPersistence) GetMessageSegments(hash []byte, sigPubKey *ecdsa.PublicKey) ([]*messagingtypes.SegmentMessage, error) { + sigPubKeyBlob := crypto.CompressPubkey(sigPubKey) + + rows, err := c.db.Query(` + SELECT + hash, segment_index, segments_count, parity_segment_index, parity_segments_count, payload + FROM + message_segments + WHERE + hash = ? AND sig_pub_key = ? + ORDER BY + (segments_count = 0) ASC, -- Prioritize segments_count > 0 + segment_index ASC, + parity_segment_index ASC`, + hash, sigPubKeyBlob) + if err != nil { + return nil, err + } + defer rows.Close() + + var segments []*messagingtypes.SegmentMessage + for rows.Next() { + segment := &messagingtypes.SegmentMessage{ + SegmentMessage: &protobuf.SegmentMessage{}, + } + err := rows.Scan(&segment.EntireMessageHash, &segment.Index, &segment.SegmentsCount, &segment.ParitySegmentIndex, &segment.ParitySegmentsCount, &segment.Payload) + if err != nil { + return nil, err + } + segments = append(segments, segment) + } + err = rows.Err() + if err != nil { + return nil, err + } + + return segments, nil +} + +func (c *messagingPersistence) RemoveMessageSegmentsOlderThan(timestamp int64) error { + _, err := c.db.Exec("DELETE FROM message_segments WHERE timestamp < ?", timestamp) + return err +} + +func (c *messagingPersistence) CompleteMessageSegments(hash []byte, sigPubKey *ecdsa.PublicKey, timestamp int64) error { + tx, err := c.db.BeginTx(context.Background(), &sql.TxOptions{}) + if err != nil { + return err + } + + defer func() { + if err == nil { + err = tx.Commit() + return + } + // don't shadow original error + _ = tx.Rollback() + }() + + sigPubKeyBlob := crypto.CompressPubkey(sigPubKey) + + _, err = tx.Exec("DELETE FROM message_segments WHERE hash = ? AND sig_pub_key = ?", hash, sigPubKeyBlob) + if err != nil { + return err + } + + _, err = tx.Exec("INSERT INTO message_segments_completed (hash, sig_pub_key, timestamp) VALUES (?,?,?)", hash, sigPubKeyBlob, timestamp) + if err != nil { + return err + } + + return err +} + +func (c *messagingPersistence) RemoveMessageSegmentsCompletedOlderThan(timestamp int64) error { + _, err := c.db.Exec("DELETE FROM message_segments_completed WHERE timestamp < ?", timestamp) + return err +} + +// MarkAsConfirmed marks all the messages with dataSyncID as confirmed and returns +// the messageIDs that can be considered confirmed. +// If atLeastOne is set it will return messageid if at least once of the messages +// sent has been confirmed +func (c *messagingPersistence) MarkAsConfirmed(dataSyncID []byte, atLeastOne bool) (messageID cryptotypes.HexBytes, err error) { + tx, err := c.db.BeginTx(context.Background(), &sql.TxOptions{}) + if err != nil { + return nil, err + } + defer func() { + if err == nil { + err = tx.Commit() + return + } + // don't shadow original error + _ = tx.Rollback() + }() + + confirmedAt := time.Now().Unix() + _, err = tx.Exec(`UPDATE raw_message_confirmations SET confirmed_at = ? WHERE datasync_id = ? AND confirmed_at = 0`, confirmedAt, dataSyncID) + if err != nil { + return + } + + // Select any tuple that has a message_id with a datasync_id = ? and that has just been confirmed + rows, err := tx.Query(`SELECT message_id,confirmed_at FROM raw_message_confirmations WHERE message_id = (SELECT message_id FROM raw_message_confirmations WHERE datasync_id = ? LIMIT 1)`, dataSyncID) + if err != nil { + return + } + defer rows.Close() + + confirmedResult := true + + for rows.Next() { + var confirmedAt int64 + err = rows.Scan(&messageID, &confirmedAt) + if err != nil { + return + } + confirmed := confirmedAt > 0 + + if atLeastOne && confirmed { + // We return, as at least one was confirmed + return + } + + confirmedResult = confirmedResult && confirmed + } + + if !confirmedResult { + messageID = nil + return + } + + return +} diff --git a/protocol/messaging_persistence_test.go b/protocol/messaging_persistence_test.go new file mode 100644 index 0000000000..e2c1d01613 --- /dev/null +++ b/protocol/messaging_persistence_test.go @@ -0,0 +1,208 @@ +package protocol + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/status-im/status-go/crypto/types" + messagingtypes "github.com/status-im/status-go/messaging/types" +) + +func TestConfirmations(t *testing.T) { + dataSyncID1 := []byte("datsync-id-1") + dataSyncID2 := []byte("datsync-id-2") + dataSyncID3 := []byte("datsync-id-3") + dataSyncID4 := []byte("datsync-id-3") + + messageID1 := []byte("message-id-1") + messageID2 := []byte("message-id-2") + + publicKey1 := []byte("pk-1") + publicKey2 := []byte("pk-2") + publicKey3 := []byte("pk-3") + + db, err := openTestDB() + require.NoError(t, err) + p := NewMessagingPersistence(db) + + confirmation1 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID1, + MessageID: messageID1, + PublicKey: publicKey1, + } + + // Same datasyncID and same messageID, different pubkey + confirmation2 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID2, + MessageID: messageID1, + PublicKey: publicKey2, + } + + // Different datasyncID and same messageID, different pubkey + confirmation3 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID3, + MessageID: messageID1, + PublicKey: publicKey3, + } + + // Same dataSyncID, different messageID + confirmation4 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID4, + MessageID: messageID2, + PublicKey: publicKey1, + } + + require.NoError(t, p.InsertPendingConfirmation(confirmation1)) + require.NoError(t, p.InsertPendingConfirmation(confirmation2)) + require.NoError(t, p.InsertPendingConfirmation(confirmation3)) + require.NoError(t, p.InsertPendingConfirmation(confirmation4)) + + // We confirm the first datasync message, no confirmations + messageID, err := p.MarkAsConfirmed(dataSyncID1, false) + require.NoError(t, err) + require.Nil(t, messageID) + + // We confirm the second datasync message, no confirmations + messageID, err = p.MarkAsConfirmed(dataSyncID2, false) + require.NoError(t, err) + require.Nil(t, messageID) + + // We confirm the third datasync message, messageID1 should be confirmed + messageID, err = p.MarkAsConfirmed(dataSyncID3, false) + require.NoError(t, err) + require.Equal(t, messageID, types.HexBytes(messageID1)) +} + +func TestConfirmationsAtLeastOne(t *testing.T) { + dataSyncID1 := []byte("datsync-id-1") + dataSyncID2 := []byte("datsync-id-2") + dataSyncID3 := []byte("datsync-id-3") + + messageID1 := []byte("message-id-1") + + publicKey1 := []byte("pk-1") + publicKey2 := []byte("pk-2") + publicKey3 := []byte("pk-3") + + db, err := openTestDB() + require.NoError(t, err) + p := NewMessagingPersistence(db) + + confirmation1 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID1, + MessageID: messageID1, + PublicKey: publicKey1, + } + + // Same datasyncID and same messageID, different pubkey + confirmation2 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID2, + MessageID: messageID1, + PublicKey: publicKey2, + } + + // Different datasyncID and same messageID, different pubkey + confirmation3 := &messagingtypes.RawMessageConfirmation{ + DataSyncID: dataSyncID3, + MessageID: messageID1, + PublicKey: publicKey3, + } + + require.NoError(t, p.InsertPendingConfirmation(confirmation1)) + require.NoError(t, p.InsertPendingConfirmation(confirmation2)) + require.NoError(t, p.InsertPendingConfirmation(confirmation3)) + + // We confirm the first datasync message, messageID1 and 3 should be confirmed + messageID, err := p.MarkAsConfirmed(dataSyncID1, true) + require.NoError(t, err) + require.NotNil(t, messageID) + require.Equal(t, types.HexBytes(messageID1), messageID) +} + +func TestSaveHashRatchetMessage(t *testing.T) { + db, err := openTestDB() + require.NoError(t, err) + p := NewMessagingPersistence(db) + + groupID1 := []byte("group-id-1") + groupID2 := []byte("group-id-2") + keyID := []byte("key-id") + + message1 := &messagingtypes.ReceivedMessage{ + Hash: []byte{1}, + Sig: []byte{2}, + Timestamp: 2, + Payload: []byte{3}, + } + + require.NoError(t, p.SaveHashRatchetMessage(groupID1, keyID, message1)) + + message2 := &messagingtypes.ReceivedMessage{ + Hash: []byte{2}, + Sig: []byte{2}, + Topic: messagingtypes.BytesToContentTopic([]byte{5}), + Timestamp: 2, + Payload: []byte{3}, + Dst: []byte{4}, + } + + require.NoError(t, p.SaveHashRatchetMessage(groupID2, keyID, message2)) + + fetchedMessages, err := p.GetHashRatchetMessages(keyID) + require.NoError(t, err) + require.NotNil(t, fetchedMessages) + require.Len(t, fetchedMessages, 2) +} + +func TestDeleteHashRatchetMessage(t *testing.T) { + db, err := openTestDB() + require.NoError(t, err) + p := NewMessagingPersistence(db) + + groupID := []byte("group-id") + keyID := []byte("key-id") + + message1 := &messagingtypes.ReceivedMessage{ + Hash: []byte{1}, + Sig: []byte{2}, + Timestamp: 2, + Payload: []byte{3}, + } + + require.NoError(t, p.SaveHashRatchetMessage(groupID, keyID, message1)) + + message2 := &messagingtypes.ReceivedMessage{ + Hash: []byte{2}, + Sig: []byte{2}, + Topic: messagingtypes.BytesToContentTopic([]byte{5}), + Timestamp: 2, + Payload: []byte{3}, + Dst: []byte{4}, + } + + require.NoError(t, p.SaveHashRatchetMessage(groupID, keyID, message2)) + + message3 := &messagingtypes.ReceivedMessage{ + Hash: []byte{3}, + Sig: []byte{2}, + Topic: messagingtypes.BytesToContentTopic([]byte{5}), + Timestamp: 2, + Payload: []byte{3}, + Dst: []byte{4}, + } + + require.NoError(t, p.SaveHashRatchetMessage(groupID, keyID, message3)) + + fetchedMessages, err := p.GetHashRatchetMessages(keyID) + require.NoError(t, err) + require.NotNil(t, fetchedMessages) + require.Len(t, fetchedMessages, 3) + + require.NoError(t, p.DeleteHashRatchetMessages([][]byte{[]byte{1}, []byte{2}})) + + fetchedMessages, err = p.GetHashRatchetMessages(keyID) + require.NoError(t, err) + require.NotNil(t, fetchedMessages) + require.Len(t, fetchedMessages, 1) +} diff --git a/protocol/messenger_local_backup.go b/protocol/messenger_local_backup.go new file mode 100644 index 0000000000..26532c8ddb --- /dev/null +++ b/protocol/messenger_local_backup.go @@ -0,0 +1,70 @@ +package protocol + +import ( + "errors" + + "github.com/golang/protobuf/proto" + + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/signal" +) + +func (m *Messenger) ExportBackup() ([]byte, error) { + backup := &protobuf.MessengerLocalBackup{} + + clock, _ := m.getLastClockWithRelatedChat() + contactsToBackup := m.backupContacts(m.ctx) + communitiesToBackup, err := m.backupCommunities(m.ctx, clock) + if err != nil { + return nil, err + } + chatsToBackup := m.backupChats(m.ctx, clock) + profileToBackup, err := m.backupProfile(m.ctx, clock) + if err != nil { + return nil, err + } + + for _, d := range contactsToBackup { + backup.Contacts = append(backup.Contacts, d.Contacts...) + } + for _, d := range communitiesToBackup { + backup.Communities = append(backup.Communities, d.Communities...) + } + backup.Profile = profileToBackup.Profile + for _, d := range chatsToBackup { + backup.Chats = append(backup.Chats, d.Chats...) + } + return proto.Marshal(backup) +} + +func (m *Messenger) ImportBackup(data []byte) error { + var backup protobuf.MessengerLocalBackup + err := proto.Unmarshal(data, &backup) + if err != nil { + return err + } + + state := ReceivedMessageState{ + Response: &MessengerResponse{}, + AllChats: &chatMap{}, + AllContacts: &contactMap{ + me: m.selfContact, + }, + Timesource: m.getTimesource(), + ModifiedContacts: &stringBoolMap{}, + ModifiedInstallations: &stringBoolMap{}, + } + errs := m.handleLocalBackup( + &state, + &backup, + ) + if len(errs) > 0 { + return errors.Join(errs...) + } + + response, err := m.saveDataAndPrepareResponse(&state) + + signal.SendNewMessages(response) + + return err +} diff --git a/protocol/messenger_local_backup_test.go b/protocol/messenger_local_backup_test.go new file mode 100644 index 0000000000..33b0bd849b --- /dev/null +++ b/protocol/messenger_local_backup_test.go @@ -0,0 +1,159 @@ +package protocol + +import ( + "context" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/requests" +) + +func TestMessengerLocalBackupSuite(t *testing.T) { + suite.Run(t, new(MessengerLocalBackupSuite)) +} + +type MessengerLocalBackupSuite struct { + MessengerBaseTestSuite +} + +func (s *MessengerLocalBackupSuite) TestLocalBackup() { + // Create bob1 + bob1 := s.anotherMessenger() + defer TearDownMessenger(&s.Suite, bob1) + + // Create bob2 + bob2 := s.anotherMessenger() + defer TearDownMessenger(&s.Suite, bob2) + + // -------------------- CONTACTS -------------------- + // Create 2 contacts + contact1Key, err := crypto.GenerateKey() + s.Require().NoError(err) + contactID1 := types.EncodeHex(crypto.FromECDSAPub(&contact1Key.PublicKey)) + + _, err = bob1.AddContact(context.Background(), &requests.AddContact{ID: contactID1}) + s.Require().NoError(err) + + contact2Key, err := crypto.GenerateKey() + s.Require().NoError(err) + contactID2 := types.EncodeHex(crypto.FromECDSAPub(&contact2Key.PublicKey)) + + _, err = bob1.AddContact(context.Background(), &requests.AddContact{ID: contactID2}) + s.Require().NoError(err) + + s.Require().Len(bob1.Contacts(), 2) + + // Validate contacts on bob1 + actualContacts := bob1.Contacts() + if actualContacts[0].ID == contactID1 { + s.Require().Equal(actualContacts[0].ID, contactID1) + s.Require().Equal(actualContacts[1].ID, contactID2) + } else { + s.Require().Equal(actualContacts[0].ID, contactID2) + s.Require().Equal(actualContacts[1].ID, contactID1) + } + s.Require().Equal(ContactRequestStateSent, actualContacts[0].ContactRequestLocalState) + s.Require().Equal(ContactRequestStateSent, actualContacts[1].ContactRequestLocalState) + s.Require().True(actualContacts[0].added()) + s.Require().True(actualContacts[1].added()) + + // Check that bob2 has no contacts + s.Require().Len(bob2.Contacts(), 0) + + //-------------------- COMMUNITIES -------------------- + // Create a community + description := &requests.CreateCommunity{ + Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, + Name: "status", + Color: "#ffffff", + Description: "status community description", + } + response, err := bob1.CreateCommunity(description, true) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) + + // Check bob2 + communities, err := bob2.Communities() + s.Require().NoError(err) + s.Require().Len(communities, 0) + + // --------------------- LEFT COMMUNITY -------------------- + // Create another community + description = &requests.CreateCommunity{ + Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT, + Name: "other-status", + Color: "#fffff4", + Description: "other status community description", + } + + response, err = bob1.CreateCommunity(description, true) + s.Require().NoError(err) + s.Require().NotNil(response) + s.Require().Len(response.Communities(), 1) + + newCommunity := response.Communities()[0] + + // Leave community + response, err = bob1.LeaveCommunity(newCommunity.ID()) + s.Require().NoError(err) + s.Require().NotNil(response) + + // Check bob2 + communities, err = bob2.Communities() + s.Require().NoError(err) + s.Require().Len(communities, 0) + + // --------------------- CHATS -------------------- + // Create a group chat + response, err = bob1.CreateGroupChatWithMembers(context.Background(), "group", []string{}) + s.NoError(err) + s.Require().Len(response.Chats(), 1) + + ourGroupChat := response.Chats()[0] + + err = bob1.SaveChat(ourGroupChat) + s.NoError(err) + + // Create a one-to-one chat + alice := s.newMessenger() + defer TearDownMessenger(&s.Suite, alice) + + ourOneOneChat := CreateOneToOneChat("Our 1TO1", &alice.identity.PublicKey, alice.getTimesource()) + err = bob1.SaveChat(ourOneOneChat) + s.Require().NoError(err) + + // -------------------- BACKUP -------------------- + // Backup + marshalledBackup, err := bob1.ExportBackup() + s.Require().NoError(err) + + // Import the backup file and process it + err = bob2.ImportBackup(marshalledBackup) + s.Require().NoError(err) + + // -------------------- VALIDATE BACKUP -------------------- + // Validate contacts on bob2 + s.Require().Len(bob2.Contacts(), 2) + + // Validate communities on bob2 + communities, err = bob2.JoinedCommunities() + s.Require().NoError(err) + s.Require().Len(communities, 1) + + // Validate chats on bob2 + // Group chat + chat, ok := bob2.allChats.Load(ourGroupChat.ID) + s.Require().True(ok) + s.Require().Equal(ourGroupChat.Name, chat.Name) + + // One on one chat + chat, ok = bob2.allChats.Load(ourOneOneChat.ID) + s.Require().True(ok) + s.Require().True(chat.Active) + s.Require().Equal("", chat.Name) +} diff --git a/protocol/messenger_pubsub_events.go b/protocol/messenger_pubsub_events.go new file mode 100644 index 0000000000..2678a69ffe --- /dev/null +++ b/protocol/messenger_pubsub_events.go @@ -0,0 +1,11 @@ +package protocol + +import ( + messagingtypes "github.com/status-im/status-go/messaging/types" +) + +type RetrievedMessagesEvent struct { + Filter messagingtypes.ChatFilter + SHHMessage *messagingtypes.ReceivedMessage + Messages []*messagingtypes.Message +} diff --git a/protocol/migrations/sqlite/1754570630_drop_community_storenodes.up.sql b/protocol/migrations/sqlite/1754570630_drop_community_storenodes.up.sql new file mode 100644 index 0000000000..0cf1ca5f34 --- /dev/null +++ b/protocol/migrations/sqlite/1754570630_drop_community_storenodes.up.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS community_storenodes; diff --git a/protocol/protobuf/accounts_local_backup.proto b/protocol/protobuf/accounts_local_backup.proto new file mode 100644 index 0000000000..b09126662e --- /dev/null +++ b/protocol/protobuf/accounts_local_backup.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +import "sync_settings.proto"; + +option go_package = "./;protobuf"; +package protobuf; + +message AccountsLocalBackup { + repeated SyncSetting settings = 1; +} diff --git a/protocol/protobuf/messenger_local_backup.proto b/protocol/protobuf/messenger_local_backup.proto new file mode 100644 index 0000000000..a8975a3e5e --- /dev/null +++ b/protocol/protobuf/messenger_local_backup.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +import "pairing.proto"; + +option go_package = "./;protobuf"; +package protobuf; + + +message MessengerLocalBackup { + uint64 clock = 1; + + repeated SyncInstallationContactV2 contacts = 2; + repeated SyncInstallationCommunity communities = 3; + repeated SyncChat chats = 4; + BackedUpProfile profile = 5; +} \ No newline at end of file diff --git a/protocol/protobuf/wallet_local_backup.proto b/protocol/protobuf/wallet_local_backup.proto new file mode 100644 index 0000000000..7d3cd753be --- /dev/null +++ b/protocol/protobuf/wallet_local_backup.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +import "pairing.proto"; + +option go_package = "./;protobuf"; +package protobuf; + +message WalletLocalBackup { + repeated SyncAccount watchOnlyAccounts = 1; +} diff --git a/protocol/requests/load_local_backup.go b/protocol/requests/load_local_backup.go new file mode 100644 index 0000000000..2384f6cffa --- /dev/null +++ b/protocol/requests/load_local_backup.go @@ -0,0 +1,14 @@ +package requests + +import "errors" + +type LoadLocalBackup struct { + FilePath string `json:"filePath"` +} + +func (c *LoadLocalBackup) Validate() error { + if c.FilePath == "" { + return errors.New("filePath must be provided") + } + return nil +} diff --git a/rpc/events.go b/rpc/events.go new file mode 100644 index 0000000000..5205359028 --- /dev/null +++ b/rpc/events.go @@ -0,0 +1,9 @@ +package rpc + +import ( + "github.com/status-im/status-go/healthmanager" +) + +type EventBlockchainHealthChanged struct { + FullStatus healthmanager.BlockchainFullStatus +} diff --git a/rpc/network/events.go b/rpc/network/events.go new file mode 100644 index 0000000000..f2f451627a --- /dev/null +++ b/rpc/network/events.go @@ -0,0 +1,4 @@ +package network + +// EventActiveNetworksChanged is emitted when networks are activated/deactivated. This includes Testnet mode change. +type EventActiveNetworksChanged struct{} diff --git a/rpc/signals_transmitter.go b/rpc/signals_transmitter.go new file mode 100644 index 0000000000..c5a75141da --- /dev/null +++ b/rpc/signals_transmitter.go @@ -0,0 +1,52 @@ +package rpc + +import ( + gocommon "github.com/status-im/status-go/common" + "github.com/status-im/status-go/pkg/pubsub" + "github.com/status-im/status-go/signal" +) + +type SignalsTransmitter struct { + publisher *pubsub.Publisher + + quit chan struct{} +} + +func NewSignalsTransmitter(publisher *pubsub.Publisher) *SignalsTransmitter { + return &SignalsTransmitter{ + publisher: publisher, + } +} + +func (tmr *SignalsTransmitter) Start() error { + if tmr.quit != nil { + // already running, nothing to do + return nil + } + tmr.quit = make(chan struct{}) + ch, unsubFn := pubsub.Subscribe[EventBlockchainHealthChanged](tmr.publisher, 10) + + go func() { + defer gocommon.LogOnPanic() + defer unsubFn() + for { + select { + case <-tmr.quit: + return + case event, ok := <-ch: + if !ok { + return + } + signal.SendNetworksBlockchainHealthChanged(event.FullStatus) + } + } + }() + return nil +} + +func (tmr *SignalsTransmitter) Stop() { + if tmr.quit != nil { + close(tmr.quit) + tmr.quit = nil + } +} diff --git a/services/ens/ensresolver/address.go b/services/ens/ensresolver/address.go new file mode 100644 index 0000000000..68f8b7f40f --- /dev/null +++ b/services/ens/ensresolver/address.go @@ -0,0 +1,25 @@ +package ensresolver + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + walletCommon "github.com/status-im/status-go/services/wallet/common" +) + +var errorNotAvailableOnChainID = errors.New("nameWrapper contract address not available for chainID") + +var contractAddressByChainID = map[uint64]common.Address{ + walletCommon.EthereumMainnet: common.HexToAddress("0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401"), // mainnet + walletCommon.EthereumSepolia: common.HexToAddress("0x0635513f179D50A207757E05759CbD106d7dFcE8"), // sepolia testnet +} + +// GetNameWrapperAddress returns the address of the ENS Name Wrapper contract for a given chain ID. +// source: https://docs.ens.domains/wrapper/contracts/ +func NameWrapperContractAddress(chainID uint64) (common.Address, error) { + addr, exists := contractAddressByChainID[chainID] + if !exists { + return *new(common.Address), errorNotAvailableOnChainID + } + return addr, nil +} diff --git a/services/ens/ensresolver/address_test.go b/services/ens/ensresolver/address_test.go new file mode 100644 index 0000000000..86ca4bfa28 --- /dev/null +++ b/services/ens/ensresolver/address_test.go @@ -0,0 +1,49 @@ +package ensresolver + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + walletCommon "github.com/status-im/status-go/services/wallet/common" + + "github.com/stretchr/testify/require" +) + +func TestNameWrapperContractAddress(t *testing.T) { + tests := []struct { + name string + chainID uint64 + expected string + expectError bool + }{ + { + name: "Ethereum Mainnet", + chainID: walletCommon.EthereumMainnet, + expected: "0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401", + expectError: false, + }, + { + name: "Ethereum Sepolia", + chainID: walletCommon.EthereumSepolia, + expected: "0x0635513f179D50A207757E05759CbD106d7dFcE8", + expectError: false, + }, + { + name: "Unsupported Chain", + chainID: 12345, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + addr, err := NameWrapperContractAddress(tt.chainID) + if tt.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, common.HexToAddress(tt.expected), addr) + } + }) + } +} diff --git a/services/personal/service_test.go b/services/personal/service_test.go new file mode 100644 index 0000000000..6b70c8f3af --- /dev/null +++ b/services/personal/service_test.go @@ -0,0 +1,83 @@ +package personal + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" + + "github.com/stretchr/testify/require" +) + +func generateMessageToSign(t *testing.T) string { + requestID := "0x240235eb861041795bc84ebe837569f08f8306a23f3f377a2977bc18eba76326" + requestIDBytes, err := hexutil.Decode(requestID) + require.NoError(t, err) + + communityID := "0x02abc53deca7213ef265487b63715d226f3f31853e08636f822d74b9ebaddefb47" + communityIDBytes, err := hexutil.Decode(communityID) + require.NoError(t, err) + + identityPublicKeyCompressed := "0x03c8eec7e5b7ad01693376529387ae1f097c9967f161d745bf99318b321b3e7800" + identityPublicKeyCompressedBytes, err := hexutil.Decode(identityPublicKeyCompressed) + require.NoError(t, err) + + return types.EncodeHex(crypto.Keccak256(identityPublicKeyCompressedBytes, communityIDBytes, requestIDBytes)) +} + +func generateAccountForSigning(t *testing.T) *generator.Account { + seedPhrase := "inch describe nothing prepare salon foster market fabric bottom type trial glooom" + account, err := generator.CreateAccountFromMnemonic(seedPhrase, "") + require.NoError(t, err) + + derivedAccount, err := generator.DeriveChildFromAccount(account, "m/44'/60'/0'/0/0") + require.NoError(t, err) + + return derivedAccount +} + +func TestSignAndRecover(t *testing.T) { + expectedMessageToSign := "0x32a4ed227797845663dce42d5f595ab26aab43bb5bb98fca2c4599b4c255d18b" + + generatedMessageToSign := generateMessageToSign(t) + require.Equal(t, expectedMessageToSign, generatedMessageToSign) + + accountForSigning := generateAccountForSigning(t) + + personalService := New() + + // Sign the message as string + signature, err := personalService.Sign(SignParams{ + Data: generatedMessageToSign, + }, accountForSigning) + require.NoError(t, err) + + // Recover the address from the signed string message + recoveredAddress, err := personalService.Recover(RecoverParams{ + Message: generatedMessageToSign, + Signature: hexutil.Encode(signature), + }) + require.NoError(t, err) + + require.Equal(t, accountForSigning.Address().Hex(), recoveredAddress.Hex()) + + // Sign the message as bytes + generatedMessageToSignBytes, err := hexutil.Decode(generatedMessageToSign) + require.NoError(t, err) + + signature, err = personalService.Sign(SignParams{ + Data: generatedMessageToSignBytes, + }, accountForSigning) + require.NoError(t, err) + + // Recover the address from the signed bytes message + recoveredAddress, err = personalService.Recover(RecoverParams{ + Message: generatedMessageToSign, + Signature: hexutil.Encode(signature), + }) + require.NoError(t, err) + + require.Equal(t, accountForSigning.Address().Hex(), recoveredAddress.Hex()) +} diff --git a/services/wallet/leaderboard/utils.go b/services/wallet/leaderboard/utils.go new file mode 100644 index 0000000000..508b33e35c --- /dev/null +++ b/services/wallet/leaderboard/utils.go @@ -0,0 +1,27 @@ +package leaderboard + +import ( + "fmt" + "strings" +) + +const ( + MarketProxyHostSuffix = "market.status.im" +) + +// GetMarketProxyHost creates market proxy base URL based on stage name +func GetMarketProxyHost(customUrl, stageName string) string { + if customUrl != "" { + return strings.TrimRight(customUrl, "/") + } + if stageName == "" { + stageName = "test" + } + return fmt.Sprintf("https://%s.%s", stageName, MarketProxyHostSuffix) +} + +// GetMarketProxyUrl creates market proxy URL based on stage name with /v1 suffix +func GetMarketProxyUrl(customUrl, stageName string) string { + baseUrl := GetMarketProxyHost(customUrl, stageName) + return baseUrl + "/v1" +} diff --git a/services/wallet/thirdparty/utils/chunk_fetcher.go b/services/wallet/thirdparty/utils/chunk_fetcher.go new file mode 100644 index 0000000000..105e2630f2 --- /dev/null +++ b/services/wallet/thirdparty/utils/chunk_fetcher.go @@ -0,0 +1,87 @@ +package utils + +import ( + "context" + "fmt" + "slices" + "time" +) + +const PerChunkLimit = 100 + +func processInChunks[T any]( + ctx context.Context, + items []string, + chunkLimit int, + delay time.Duration, + fetchFunc func(context.Context, []string) (T, error), +) ([]T, error) { + if len(items) == 0 || chunkLimit <= 0 { + return make([]T, 0), nil + } + + var results []T + isFirst := true + + for chunk := range slices.Chunk(items, chunkLimit) { + if delay > 0 && !isFirst { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(delay): + } + } + isFirst = false + + chunkResult, err := fetchFunc(ctx, chunk) + if err != nil { + return nil, fmt.Errorf("failed to fetch chunk: %w", err) + } + + results = append(results, chunkResult) + } + + return results, nil +} + +func ChunkMapFetcher[T any]( + ctx context.Context, + items []string, + chunkLimit int, + delay time.Duration, + fetchFunc func(context.Context, []string) (map[string]T, error), +) (map[string]T, error) { + chunkResults, err := processInChunks(ctx, items, chunkLimit, delay, fetchFunc) + if err != nil { + return nil, err + } + + result := make(map[string]T) + for _, chunkResult := range chunkResults { + for k, v := range chunkResult { + result[k] = v + } + } + + return result, nil +} + +func ChunkArrayFetcher[T any]( + ctx context.Context, + items []string, + chunkLimit int, + delay time.Duration, + fetchFunc func(context.Context, []string) ([]T, error), +) ([]T, error) { + chunkResults, err := processInChunks(ctx, items, chunkLimit, delay, fetchFunc) + if err != nil { + return nil, err + } + + var result []T + for _, chunkResult := range chunkResults { + result = append(result, chunkResult...) + } + + return result, nil +} diff --git a/services/wallet/thirdparty/utils/chunk_fetcher_test.go b/services/wallet/thirdparty/utils/chunk_fetcher_test.go new file mode 100644 index 0000000000..2ff0cb763a --- /dev/null +++ b/services/wallet/thirdparty/utils/chunk_fetcher_test.go @@ -0,0 +1,207 @@ +package utils + +import ( + "context" + "errors" + "fmt" + "reflect" + "testing" +) + +func TestChunkMapFetcher(t *testing.T) { + tests := []struct { + name string + items []string + chunkLimit int + fetchFunc func(context.Context, []string) (map[string]int, error) + expected map[string]int + expectedErr bool + }{ + { + name: "empty items", + items: []string{}, + chunkLimit: 2, + fetchFunc: func(ctx context.Context, chunk []string) (map[string]int, error) { + result := make(map[string]int) + for i, item := range chunk { + result[item] = i + } + return result, nil + }, + expected: map[string]int{}, + expectedErr: false, + }, + { + name: "single chunk", + items: []string{"a", "b"}, + chunkLimit: 5, + fetchFunc: func(ctx context.Context, chunk []string) (map[string]int, error) { + result := make(map[string]int) + for i, item := range chunk { + result[item] = i + } + return result, nil + }, + expected: map[string]int{"a": 0, "b": 1}, + expectedErr: false, + }, + { + name: "multiple chunks", + items: []string{"a", "b", "c", "d", "e"}, + chunkLimit: 2, + fetchFunc: func(ctx context.Context, chunk []string) (map[string]int, error) { + result := make(map[string]int) + for _, item := range chunk { + result[item] = len(item) + } + return result, nil + }, + expected: map[string]int{"a": 1, "b": 1, "c": 1, "d": 1, "e": 1}, + expectedErr: false, + }, + { + name: "error in fetch function", + items: []string{"a", "b", "c"}, + chunkLimit: 2, + fetchFunc: func(ctx context.Context, chunk []string) (map[string]int, error) { + return nil, errors.New("fetch error") + }, + expected: nil, + expectedErr: true, + }, + { + name: "zero chunk limit returns empty", + items: []string{"a", "b"}, + chunkLimit: 0, + fetchFunc: func(ctx context.Context, chunk []string) (map[string]int, error) { + result := make(map[string]int) + for i, item := range chunk { + result[item] = i + } + return result, nil + }, + expected: map[string]int{}, + expectedErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ChunkMapFetcher[int]( + context.Background(), + tt.items, + tt.chunkLimit, + 0, + tt.fetchFunc, + ) + + if tt.expectedErr { + if err == nil { + t.Errorf("expected error, got nil") + } + return + } + + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + if !reflect.DeepEqual(result, tt.expected) { + t.Errorf("expected %v, got %v", tt.expected, result) + } + }) + } +} + +func TestChunkArrayFetcher(t *testing.T) { + tests := []struct { + name string + items []string + chunkLimit int + fetchFunc func(context.Context, []string) ([]string, error) + expected []string + expectedErr bool + }{ + { + name: "empty items", + items: []string{}, + chunkLimit: 2, + fetchFunc: func(ctx context.Context, chunk []string) ([]string, error) { + return chunk, nil + }, + expected: []string{}, + expectedErr: false, + }, + { + name: "single chunk", + items: []string{"a", "b"}, + chunkLimit: 5, + fetchFunc: func(ctx context.Context, chunk []string) ([]string, error) { + result := make([]string, len(chunk)) + for i, item := range chunk { + result[i] = fmt.Sprintf("%s_processed", item) + } + return result, nil + }, + expected: []string{"a_processed", "b_processed"}, + expectedErr: false, + }, + { + name: "multiple chunks", + items: []string{"a", "b", "c", "d", "e"}, + chunkLimit: 2, + fetchFunc: func(ctx context.Context, chunk []string) ([]string, error) { + result := make([]string, 0, len(chunk)*2) + for _, item := range chunk { + result = append(result, item, item+"_copy") + } + return result, nil + }, + expected: []string{"a", "a_copy", "b", "b_copy", "c", "c_copy", "d", "d_copy", "e", "e_copy"}, + expectedErr: false, + }, + { + name: "error in fetch function", + items: []string{"a", "b", "c"}, + chunkLimit: 2, + fetchFunc: func(ctx context.Context, chunk []string) ([]string, error) { + return nil, errors.New("fetch error") + }, + expected: nil, + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ChunkArrayFetcher[string]( + context.Background(), + tt.items, + tt.chunkLimit, + 0, + tt.fetchFunc, + ) + + if tt.expectedErr { + if err == nil { + t.Errorf("expected error, got nil") + } + return + } + + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + if len(tt.expected) == 0 && len(result) == 0 { + return + } + + if !reflect.DeepEqual(result, tt.expected) { + t.Errorf("expected %v, got %v", tt.expected, result) + } + }) + } +} diff --git a/signal/events_networks.go b/signal/events_networks.go new file mode 100644 index 0000000000..2df7138da6 --- /dev/null +++ b/signal/events_networks.go @@ -0,0 +1,16 @@ +package signal + +import ( + "github.com/status-im/status-go/healthmanager" +) + +const ( + EventNetworksBlockchainHealthChanged = "networks.blockchainHealthChanged" +) + +// BlockchainHealthChangedSignal is triggered when the rpc client for some blockchain goes up/down. +type BlockchainHealthChangedSignal healthmanager.BlockchainFullStatus + +func SendNetworksBlockchainHealthChanged(status healthmanager.BlockchainFullStatus) { + send(EventNetworksBlockchainHealthChanged, BlockchainHealthChangedSignal(status)) +} diff --git a/signal/events_peerstats.go b/signal/events_peerstats.go new file mode 100644 index 0000000000..a686721b6e --- /dev/null +++ b/signal/events_peerstats.go @@ -0,0 +1,14 @@ +package signal + +import messagingtypes "github.com/status-im/status-go/messaging/types" + +const ( + // EventPeerStats is sent when peer is added or removed. + // it will be a map with capability=peer count k/v's. + EventPeerStats = "wakuv2.peerstats" +) + +// SendPeerStats sends discovery.summary signal. +func SendPeerStats(peerStats messagingtypes.ConnStatus) { + send(EventPeerStats, peerStats) +} diff --git a/tests-functional/.dockerignore b/tests-functional/.dockerignore new file mode 100644 index 0000000000..671945ae45 --- /dev/null +++ b/tests-functional/.dockerignore @@ -0,0 +1,6 @@ +coverage/ +reports/ +__pycache__/ +*.pyc +*.pyo +*.log \ No newline at end of file diff --git a/tests-functional/.gitignore b/tests-functional/.gitignore new file mode 100644 index 0000000000..8416b159f0 --- /dev/null +++ b/tests-functional/.gitignore @@ -0,0 +1,8 @@ +.idea/ +.vscode/ + +**/coverage +.results/ +reports +signals +*.log diff --git a/tests-functional/Makefile b/tests-functional/Makefile new file mode 100644 index 0000000000..529c5f309a --- /dev/null +++ b/tests-functional/Makefile @@ -0,0 +1,5 @@ +.PHONY: pytest-lint + +lint: + @echo "Running python linting on all files..." + pre-commit run --all-files --verbose --config .pre-commit-config.yaml diff --git a/tests-functional/clients/expvar.py b/tests-functional/clients/expvar.py new file mode 100644 index 0000000000..ac26cd79fd --- /dev/null +++ b/tests-functional/clients/expvar.py @@ -0,0 +1,124 @@ +import logging +import requests +import time +import threading +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class GoMemoryStats: + """Memory statistics from Go's expvar /debug/vars endpoint""" + + alloc_bytes: int # Currently allocated bytes + total_alloc_bytes: int # Total bytes allocated (cumulative) + sys_bytes: int # Bytes obtained from OS + mallocs: int # Number of mallocs + frees: int # Number of frees + heap_alloc_bytes: int # Heap allocated bytes + heap_sys_bytes: int # Heap system bytes + heap_idle_bytes: int # Heap idle bytes + heap_in_use_bytes: int # Heap in-use bytes + heap_released_bytes: int # Heap released bytes + heap_objects: int # Number of heap objects + gc_cpu_fraction: float # GC CPU fraction + num_gc: int # Number of GC runs + timestamp: float # Timestamp when stats were collected + + +class ExpvarClient: + """Client for collecting Go memory metrics via /debug/vars endpoint""" + + def __init__(self, base_url: str): + """ + Initialize expvar client + + Args: + base_url: Base URL of the application (e.g., "http://localhost:8080") + """ + self.base_url = base_url.rstrip("/") + self.go_metrics = [] + self._stop_monitoring = None + self.monitor_thread = None + + def get_memory_stats(self, timeout: int = 10) -> Optional[GoMemoryStats]: + """ + Get memory statistics from /debug/vars endpoint + + Args: + timeout: Request timeout in seconds + + Returns: + MemoryStats object or None if request fails + """ + try: + response = requests.get(f"{self.base_url}/debug/vars", timeout=timeout) + response.raise_for_status() + + data = response.json() + memstats = data.get("memstats", {}) + if not memstats: + logging.warning("No memstats found in /debug/vars response") + return None + + return GoMemoryStats( + alloc_bytes=memstats.get("Alloc", 0), + total_alloc_bytes=memstats.get("TotalAlloc", 0), + sys_bytes=memstats.get("Sys", 0), + mallocs=memstats.get("Mallocs", 0), + frees=memstats.get("Frees", 0), + heap_alloc_bytes=memstats.get("HeapAlloc", 0), + heap_sys_bytes=memstats.get("HeapSys", 0), + heap_idle_bytes=memstats.get("HeapIdle", 0), + heap_in_use_bytes=memstats.get("HeapInuse", 0), + heap_released_bytes=memstats.get("HeapReleased", 0), + heap_objects=memstats.get("HeapObjects", 0), + gc_cpu_fraction=memstats.get("GCCPUFraction", 0.0), + num_gc=memstats.get("NumGC", 0), + timestamp=time.time(), + ) + + except requests.exceptions.RequestException as e: + raise e + except Exception as e: + logging.error(f"Error parsing /debug/vars response: {e}") + return None + + def start_monitoring(self, interval: float = 1.0): + """Start independent Go metrics monitoring thread + + Args: + interval: Monitoring interval in seconds + """ + self.go_metrics = [] + self._stop_monitoring = threading.Event() + + def monitor_go_metrics(): + while self._stop_monitoring and not self._stop_monitoring.is_set(): + try: + memory_stats = self.get_memory_stats() + if memory_stats: + self.go_metrics.append(memory_stats) + + # Wait for the specified interval or until stop event is set + self._stop_monitoring.wait(timeout=interval) + except Exception as e: + logging.error(f"Go metrics monitoring error: {e}") + self._stop_monitoring.set() + + self._stop_monitoring.clear() + self.monitor_thread = threading.Thread(target=monitor_go_metrics, daemon=True) + self.monitor_thread.start() + logging.info("Started Go metrics monitoring") + + def stop_monitoring(self): + """Stop the Go metrics monitoring thread and return collected metrics""" + if self._stop_monitoring: + self._stop_monitoring.set() + + if self.monitor_thread and self.monitor_thread.is_alive(): + self.monitor_thread.join(timeout=10) + if self.monitor_thread.is_alive(): + logging.warning("Go metrics monitoring thread didn't stop gracefully") + + return self.go_metrics diff --git a/tests-functional/clients/gorush_stub.py b/tests-functional/clients/gorush_stub.py new file mode 100644 index 0000000000..347121ba3f --- /dev/null +++ b/tests-functional/clients/gorush_stub.py @@ -0,0 +1,160 @@ +import json +import logging +import threading +import time +from http.server import BaseHTTPRequestHandler, HTTPServer + +import requests + + +class GorushRequestHandler(BaseHTTPRequestHandler): + """HTTP request handler for gorush stub""" + + # Class-level variable to store requests for debugging + push_requests = [] + + def log_message(self, format, *args): + logging.debug(f"gorush stub request: {format % args}") + + def _set_response(self, status_code=200, content_type="application/json"): + self.send_response(status_code) + self.send_header("Content-type", content_type) + self.end_headers() + + def do_GET(self): + if self.path == "/healthz": + self._set_response() + self.wfile.write(json.dumps({"status": "ok"}).encode("utf-8")) + else: + self._set_response(404) + self.wfile.write(json.dumps({"error": "Not found"}).encode("utf-8")) + + def do_POST(self): + content_length = int(self.headers["Content-Length"]) + post_data = self.rfile.read(content_length).decode("utf-8") + + if self.path == "/api/push": + # Store request for debugging + self.__class__.push_requests.append(post_data) + + # Decode post_data + try: + request = json.loads(post_data) + except json.JSONDecodeError: + self._set_response(400) + self.wfile.write(json.dumps({"error": "Invalid JSON"}).encode("utf-8")) + return + + # Return a successful response + self._set_response() + response = { + "success": "ok", + "counts": { + "total": len(request["notifications"]), + }, + } + self.wfile.write(json.dumps(response).encode("utf-8")) + else: + self._set_response(404) + self.wfile.write(json.dumps({"error": "Not found"}).encode("utf-8")) + + +class GorushStub: + """Client for interacting with gorush-stub service""" + + def __init__(self, address="localhost", port=8088): + """Initialize GorushStub client + + Args: + port: Port to expose gorush-stub on the host + """ + # Setup logging + self.logger = logging.getLogger(__name__) + + # Initialize the HTTP server + self.base_url = "" + self.server = None + self.server_thread = None + + # Clear previous debug requests + GorushRequestHandler.push_requests = [] + + # Create and start the HTTP server + self.server = HTTPServer((address, port), GorushRequestHandler) + self.server_thread = threading.Thread(target=self.server.serve_forever) + self.server_thread.daemon = True + self.server_thread.start() + + # Create base URL for API requests + self.base_url = f"http://{address}:{self.server.server_port}" + + # Wait for the server to start + self._wait_for_service() + self.logger.info(f"gorush-stub initialized at {self.base_url}") + + def _wait_for_service(self, timeout=30, interval=1): + """Wait for gorush-stub service to be available + + Args: + timeout: Maximum time to wait in seconds + interval: Interval between attempts in seconds + + Returns: + bool: True if service is available, False otherwise + """ + start_time = time.time() + while time.time() - start_time < timeout: + try: + response = requests.get(f"{self.base_url}/healthz") + if response.status_code == 200: + return True + except requests.RequestException: + pass + time.sleep(interval) + + self.logger.error(f"gorush-stub service not available after {timeout} seconds") + return False + + def get_requests(self): + """Get debug requests from gorush-stub + + Returns: + list: List of recorded requests + """ + # Get a copy of the current push_requests + requests = GorushRequestHandler.push_requests.copy() + + # Clear the original list + GorushRequestHandler.push_requests = [] + return requests + + def wait_for_requests(self, timeout=10): + start_time = time.time() + push_requests = [] + + while len(push_requests) == 0: + if time.time() - start_time > timeout: + assert False, "Timeout waiting for push notifications requests" + + time.sleep(1) + + for req in self.get_requests(): + for notification in json.loads(req)["notifications"]: + push_requests.append(notification) + + return push_requests + + def close(self): + """Stop the gorush-stub HTTP server""" + if not self.server: + return True + + try: + self.server.shutdown() + self.server.server_close() + self.server = None + self.server_thread = None + return True + except Exception as e: + self.logger.error(f"Failed to close gorush-stub server: {e}") + return False diff --git a/tests-functional/clients/metrics.py b/tests-functional/clients/metrics.py new file mode 100644 index 0000000000..e384bd7224 --- /dev/null +++ b/tests-functional/clients/metrics.py @@ -0,0 +1,547 @@ +import json +import logging +import os +import time +import statistics + +from dataclasses import dataclass + +import matplotlib +import matplotlib.pyplot as plt + +from clients.expvar import GoMemoryStats + +matplotlib.use("Agg") # Use non-interactive backend +logging.getLogger("matplotlib.font_manager").setLevel(logging.WARNING) + + +@dataclass +class CPUMetrics: + cpu_percent: float + cpu_count: int + + +@dataclass +class RAMMetrics: + memory_usage_mb: float + memory_max_usage_mb: float + + +@dataclass +class NetworkMetrics: + rx_bytes: int # Received bytes + tx_bytes: int # Transmitted bytes + rx_packets: int # Received packets + tx_packets: int # Transmitted packets + rx_dropped: int # Received packets dropped + tx_dropped: int # Transmitted packets dropped + rx_errors: int # Receive errors + tx_errors: int # Transmit errors + rx_bytes_per_sec: float = 0 # Bytes per second received + tx_bytes_per_sec: float = 0 # Bytes per second transmitted + + +@dataclass +class GoMemStats: + idle_memory_mb: float # Heap idle memory in MB + heap_alloc_mb: float # Currently allocated heap memory in MB + heap_sys_mb: float # Heap system memory in MB + heap_in_use_mb: float # Heap in-use memory in MB + num_gc: int # Number of GC runs + gc_cpu_fraction: float # GC CPU fraction + + +class Events: + def __init__(self): + self.events = {} + + def append(self, event: str): + logging.info(f"Metrics event: {event}") + self.events[event] = time.time() + + def __iter__(self): + return iter(self.events) + + def to_dict(self): + return self.events + + +def calculate_cpu_metrics(stats): + # CPU Usage fields + cpu_stats = stats["cpu_stats"] + precpu_stats = stats["precpu_stats"] + + # Total CPU usage in nanoseconds + cpu_total = cpu_stats["cpu_usage"]["total_usage"] + cpu_total_prev = precpu_stats["cpu_usage"]["total_usage"] + + # System CPU usage in nanoseconds + system_total = cpu_stats.get("system_cpu_usage", 0) + system_total_prev = precpu_stats.get("system_cpu_usage", 0) + + # CPU cores + try: + try: + cpu_count = len(cpu_stats["cpu_usage"]["percpu_usage"]) + except KeyError: + cpu_count = cpu_stats["online_cpus"] + except KeyError: + cpu_count = 1 + + # Calculate deltas + cpu_delta = cpu_total - cpu_total_prev + system_delta = system_total - system_total_prev + + # Calculate percentages + cpu_percent = 0.0 + if system_delta > 0 and cpu_delta > 0: + cpu_percent = (cpu_delta / system_delta) * cpu_count * 100.0 + + return CPUMetrics( + cpu_percent=cpu_percent, + cpu_count=cpu_count, + ) + + +def calculate_memory_metrics(stats): + usage = stats["memory_stats"]["usage"] + max_usage = stats["memory_stats"].get("max_usage", usage) # Use current usage as fallback + + # Convert to MB for readability + mb = 1024 * 1024 + return RAMMetrics( + memory_usage_mb=usage / mb, + memory_max_usage_mb=max_usage / mb, + ) + + +def calculate_network_metrics(stats, prev_stats=None): + """Calculate network metrics from Docker stats + + Args: + stats: Current Docker stats containing network information + prev_stats: Previous stats for calculating rates (optional) + + Returns: + NetworkMetrics: Network statistics + """ + network_stats = stats.get("networks", {}) + + # Initialize totals + total_rx_bytes = 0 + total_tx_bytes = 0 + total_rx_packets = 0 + total_tx_packets = 0 + total_rx_dropped = 0 + total_tx_dropped = 0 + total_rx_errors = 0 + total_tx_errors = 0 + + # Sum up all network interfaces + for interface_name, interface_stats in network_stats.items(): + total_rx_bytes += interface_stats.get("rx_bytes", 0) + total_tx_bytes += interface_stats.get("tx_bytes", 0) + total_rx_packets += interface_stats.get("rx_packets", 0) + total_tx_packets += interface_stats.get("tx_packets", 0) + total_rx_dropped += interface_stats.get("rx_dropped", 0) + total_tx_dropped += interface_stats.get("tx_dropped", 0) + total_rx_errors += interface_stats.get("rx_errors", 0) + total_tx_errors += interface_stats.get("tx_errors", 0) + + # Calculate rates if previous stats are available + rx_bytes_per_sec = 0 + tx_bytes_per_sec = 0 + + if prev_stats is not None: + prev_network_stats = prev_stats.get("networks", {}) + prev_rx_bytes = 0 + prev_tx_bytes = 0 + + for interface_name, interface_stats in prev_network_stats.items(): + prev_rx_bytes += interface_stats.get("rx_bytes", 0) + prev_tx_bytes += interface_stats.get("tx_bytes", 0) + + # Calculate time difference + current_time = stats.get("read", "") + prev_time = prev_stats.get("read", "") + + if current_time and prev_time: + try: + from datetime import datetime + + current_dt = datetime.fromisoformat(current_time.replace("Z", "+00:00")) + prev_dt = datetime.fromisoformat(prev_time.replace("Z", "+00:00")) + time_diff = (current_dt - prev_dt).total_seconds() + except (ValueError, AttributeError): + # If timestamp parsing fails, use a default time difference + time_diff = 1.0 + else: + # Fallback: assume 1 second interval if no timestamps + time_diff = 1.0 + + # Calculate rates + if time_diff > 0: + rx_bytes_per_sec = (total_rx_bytes - prev_rx_bytes) / time_diff + tx_bytes_per_sec = (total_tx_bytes - prev_tx_bytes) / time_diff + else: + # If time_diff is 0 or negative, use the difference as bytes per second + rx_bytes_per_sec = total_rx_bytes - prev_rx_bytes + tx_bytes_per_sec = total_tx_bytes - prev_tx_bytes + + return NetworkMetrics( + rx_bytes=total_rx_bytes, + tx_bytes=total_tx_bytes, + rx_packets=total_rx_packets, + tx_packets=total_tx_packets, + rx_dropped=total_rx_dropped, + tx_dropped=total_tx_dropped, + rx_errors=total_rx_errors, + tx_errors=total_tx_errors, + rx_bytes_per_sec=max(0, rx_bytes_per_sec), # Ensure non-negative + tx_bytes_per_sec=max(0, tx_bytes_per_sec), # Ensure non-negative + ) + + +@dataclass +class ContainerStats: + """Container stats object""" + + def __init__(self, stat, prev_stat=None, go_memory_stats=None): + self.timestamp = time.time() + self.cpu = calculate_cpu_metrics(stat) + self.ram = calculate_memory_metrics(stat) + self.network = calculate_network_metrics(stat, prev_stat) + self.expvars = go_memory_stats + + +@dataclass +class StatusGoMetrics: + # Container for performance monitoring metrics + duration = 0 + samples = 0 + cpu_median = 0 + cpu_max = 0 + ram_median = 0 + ram_max = 0 + rx_bytes_per_sec_median = 0 + rx_bytes_per_sec_max = 0 + rx_total_bytes = 0 + ex_total_packets = 0 + tx_bytes_per_sec_median = 0 + tx_bytes_per_sec_max = 0 + tx_total_bytes = 0 + tx_total_packets = 0 + total_network_errors = 0 + + # Expvars metrics + total_memory_median = 0 + total_memory_max = 0 + idle_memory_median = 0 # "Idle" that is kepy by Go and not released to OS + idle_memory_max = 0 + final_gc_count = 0 + timestamp = 0 + version = "" + + def __init__( + self, + container_stats: list[ContainerStats] | None = None, + go_metrics: list[GoMemoryStats] | None = None, + events: Events | None = None, + version: str = "", + stats: list[ContainerStats] | None = None, + ): + """ + Initialize PerformanceMetrics with independent arrays + + Args: + container_stats: List of container statistics with their own timestamps + go_metrics: List of Go memory statistics with their own timestamps + events: Events tracker + version: Version string + stats: Legacy parameter for backward compatibility + """ + # Handle backward compatibility + if stats is not None and container_stats is None: + container_stats = stats + + self.container_stats = container_stats or [] + self.go_metrics = go_metrics or [] + self.events = events or Events() + self.timestamp = time.time() + self.version = version + + self._calculate_metrics() + + def _calculate_container_metrics(self): + # Calculate duration from container stats + self.duration = self.container_stats[-1].timestamp - self.container_stats[0].timestamp + + # Extract CPU and RAM metrics + cpu_percents = [stat.cpu.cpu_percent for stat in self.container_stats] + ram_usage = [stat.ram.memory_usage_mb for stat in self.container_stats] + + # Extract network metrics + rx_bytes_per_sec = [stat.network.rx_bytes_per_sec for stat in self.container_stats] + tx_bytes_per_sec = [stat.network.tx_bytes_per_sec for stat in self.container_stats] + + self.samples = len(self.container_stats) + self.cpu_median = statistics.median(cpu_percents) + self.cpu_max = max(cpu_percents) + self.ram_median = statistics.median(ram_usage) + self.ram_max = max(ram_usage) + + # Network metrics + self.rx_bytes_per_sec_median = statistics.median(rx_bytes_per_sec) + self.rx_bytes_per_sec_max = max(rx_bytes_per_sec) + self.tx_bytes_per_sec_median = statistics.median(tx_bytes_per_sec) + self.tx_bytes_per_sec_max = max(tx_bytes_per_sec) + + # Total network statistics from the last sample + last_stat = self.container_stats[-1] + self.rx_total_bytes = last_stat.network.rx_bytes + self.tx_total_bytes = last_stat.network.tx_bytes + self.ex_total_packets = last_stat.network.rx_packets + self.tx_total_packets = last_stat.network.tx_packets + self.total_network_errors = ( + last_stat.network.rx_errors + last_stat.network.tx_errors + last_stat.network.rx_dropped + last_stat.network.tx_dropped + ) + + def _calculate_go_metrics(self): + # Convert to MB for consistency + mb = 1024 * 1024 + + total_memory = [metric.sys_bytes - metric.heap_released_bytes for metric in self.go_metrics] + idle_memory = [metric.heap_idle_bytes - metric.heap_released_bytes for metric in self.go_metrics] + + if total_memory: + self.total_memory_median = statistics.median(total_memory) / mb + self.total_memory_max = max(total_memory) / mb + if idle_memory: + self.idle_memory_median = statistics.median(idle_memory) / mb + self.idle_memory_max = max(idle_memory) / mb + + # Final GC count from the last sample + self.final_gc_count = self.go_metrics[-1].num_gc + + def _calculate_metrics(self): + """Calculate summary metrics from collected data""" + if self.container_stats: + self._calculate_container_metrics() + if self.go_metrics: + self._calculate_go_metrics() + + def to_dict(self): + """Convert PerformanceMetrics to a JSON-serializable dictionary""" + return { + "timestamp": self.timestamp, + "version": self.version, + "events": self.events.to_dict(), + "metrics": { + "cpu": { + "median": self.cpu_median, + "max": self.cpu_max, + }, + "ram": { + "median": self.ram_median, + "max": self.ram_max, + }, + "network": { + "rx": { + "bytes_per_sec": { + "median": self.rx_bytes_per_sec_median, + "max": self.rx_bytes_per_sec_max, + }, + "total_bytes": self.rx_total_bytes, + "total_packets": self.ex_total_packets, + }, + "tx": { + "bytes_per_sec": { + "median": self.tx_bytes_per_sec_median, + "max": self.tx_bytes_per_sec_max, + }, + "total_bytes": self.tx_total_bytes, + "total_packets": self.tx_total_packets, + }, + "total_errors": self.total_network_errors, + }, + "expvar": { + "idle_memory_mb": { + "median": self.idle_memory_median, + "max": self.idle_memory_max, + }, + "total_memory_mb": { + "median": self.total_memory_median, + "max": self.total_memory_max, + }, + "gc_count": self.final_gc_count, + }, + }, + } + + def save_performance_chart(self, title: str, output_path=None): + """Generate and save a performance chart as a PNG image + + Args: + title: Chart title + output_path: Path to save the chart. If None, saves to ./performance_metrics_{container_id}.png + + Returns: + str: Path to the saved chart file + """ + if not self.container_stats or not self.go_metrics: + raise ValueError("No performance data to generate chart") + + mb = 1024 * 1024 + + # Create a figure with four subplots (CPU, Memory, Network, and Accumulated Network) + fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, figsize=(12, 18), sharex=True) + fig.suptitle(title, fontsize=16, y=0.98) + + # Extract data from container stats + container_timestamps = [stat.timestamp for stat in self.container_stats] + cpu_values = [stat.cpu.cpu_percent for stat in self.container_stats] + ram_values = [stat.ram.memory_usage_mb for stat in self.container_stats] + rx_values = [stat.network.rx_bytes_per_sec / mb for stat in self.container_stats] + tx_values = [stat.network.tx_bytes_per_sec / mb for stat in self.container_stats] + + # Convert to relative time + start_time = container_timestamps[0] + container_time_points = [t - start_time for t in container_timestamps] + + # Extract accumulated network data + rx_bytes = [stat.network.rx_bytes for stat in self.container_stats] + tx_bytes = [stat.network.tx_bytes for stat in self.container_stats] + rx_bytes_mb = [bytes / mb for bytes in rx_bytes] + tx_bytes_mb = [bytes / mb for bytes in tx_bytes] + + # Extract data from Go metrics independently + go_timestamps = [metric.timestamp for metric in self.go_metrics] + sys_values = [metric.sys_bytes / mb for metric in self.go_metrics] + actual_memory_values = [(metric.sys_bytes - metric.heap_released_bytes) / mb for metric in self.go_metrics] + could_be_released = [(metric.heap_idle_bytes - metric.heap_released_bytes) / mb for metric in self.go_metrics] + + # Convert to relative time (use container start time if available, otherwise Go metrics start time) + go_start_time = start_time if self.container_stats else go_timestamps[0] + go_time_points = [t - go_start_time for t in go_timestamps] + + # CPU usage plot + cpu_median = statistics.median(cpu_values) + cpu_max = max(cpu_values) + ax1.plot(container_time_points, cpu_values, "b-", label="CPU Usage (%)") + ax1.set_ylabel("CPU Usage (%)") + ax1.set_title("CPU Usage Over Time") + ax1.grid(True) + ax1.set_xlim(left=0) + ax1.set_ylim(bottom=0) + ax1.legend(loc="best") + + # Memory usage plot with independent arrays + median_memory = statistics.median(ram_values) + max_memory = max(ram_values) + ax2.plot(container_time_points, ram_values, "m-", label="Container Memory (MB)") + + sys_median = statistics.median(sys_values) + sys_max = max(sys_values) + ax2.plot(go_time_points, sys_values, "orange", label="Go Sys Memory (MB)", linewidth=2) + + actual_memory_median = statistics.median(actual_memory_values) + actual_memory_max = max(actual_memory_values) + ax2.plot(go_time_points, actual_memory_values, "g-", label="Go Actual Memory Usage (MB)", linewidth=2) + ax2.plot(go_time_points, could_be_released, "b", label="Go Idle Memory (MB)", linewidth=2) + + ax2.set_ylabel("Memory Usage (MB)") + ax2.set_title("Memory Usage Over Time") + ax2.grid(True) + ax2.set_xlim(left=0) + ax2.set_ylim(bottom=0) + ax2.legend(loc="best") + + # Network usage plot + rx_median = statistics.median(rx_values) + tx_median = statistics.median(tx_values) + rx_max = max(rx_values) + tx_max = max(tx_values) + ax3.plot(container_time_points, rx_values, "c-", label="Download (MB/s)", linewidth=2) + ax3.plot(container_time_points, tx_values, "r-", label="Upload (MB/s)", linewidth=2) + ax3.set_ylabel("Network Throughput (MB/s)") + ax3.set_title("Network Activity Over Time") + ax3.grid(True) + ax3.set_xlim(left=0) + ax3.set_ylim(bottom=0) + ax3.legend(loc="best", labelspacing=2) + + # Accumulated network usage plot + rx_total_bytes = rx_bytes[-1] + tx_total_bytes = tx_bytes[-1] + ax4.plot(container_time_points, rx_bytes_mb, "c-", label=f"Download (MB), total: {rx_total_bytes / mb:.2f} MB", linewidth=2) + ax4.plot(container_time_points, tx_bytes_mb, "r-", label=f"Upload (MB), total: {tx_total_bytes / mb:.2f} MB", linewidth=2) + ax4.set_xlabel("Time (seconds)") + ax4.set_ylabel("Total Data Transferred (MB)") + ax4.set_title("Accumulated Network Data Over Time") + ax4.grid(True) + ax4.set_xlim(left=0) + ax4.set_ylim(bottom=0) + ax4.legend(loc="best") + + # Add vertical lines for events across all plots + if self.events and hasattr(self.events, "events") and self.events.events: + for event_name, event_timestamp in self.events.events.items(): + # Convert the event timestamp to relative time (seconds from start) + event_time = event_timestamp - start_time + + # Only add lines for events that occur within our time range + if container_time_points and 0 <= event_time <= max(container_time_points): + # Add vertical line to all subplots + for ax in [ax1, ax2, ax3, ax4]: + ax.axvline(x=event_time, color="black", linestyle="--", alpha=0.7, linewidth=1) + + # Add an event label to the top plot (CPU) to avoid cluttering + ax1.text( + event_time, + ax1.get_ylim()[1] * 0.95, + event_name, + rotation=90, + verticalalignment="top", + horizontalalignment="right", + fontsize=8, + color="black", + alpha=0.8, + ) + + # Create consolidated statistical summary outside plots + stats_text = "Performance Statistics:\n" + stats_text += f"- CPU Usage: median = {cpu_median:.2f}%, max = {cpu_max:.2f}%\n" + stats_text += f"- Container Memory: median = {median_memory:.2f} MB, max = {max_memory:.2f} MB\n" + stats_text += f"- Go Sys Memory: median = {sys_median:.2f} MB, max = {sys_max:.2f} MB\n" + stats_text += f"- Go Actual Memory: median = {actual_memory_median:.2f} MB, max = {actual_memory_max:.2f} MB\n" + stats_text += f"- Network Download: median = {rx_median:.2f} MB/s, max = {rx_max:.2f} MB/s\n" + stats_text += f"- Network Upload: median = {tx_median:.2f} MB/s, max = {tx_max:.2f} MB/s" + + # Adjust layout to make room for the statistics text at the bottom + plt.tight_layout(rect=(0, 0.15, 1, 1)) + + ax5.axis("off") + ax5.invert_yaxis() + ax5.text(0.5, 0.5, stats_text, verticalalignment="top") + + # Save the figure + if output_path is None: + timestamp = time.strftime("%Y%m%d-%H%M%S") + output_path = f"./performance_metrics_{timestamp}.png" + + # Ensure directory exists + os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True) + + # Save figure + plt.savefig(output_path, dpi=100, bbox_inches="tight") + plt.close(fig) + + logging.info(f"Performance chart saved to {output_path}") + return output_path + + def save_to_file(self, filename: str): + metrics = self.to_dict() + os.makedirs(os.path.dirname(filename), exist_ok=True) + with open(filename, "w") as f: + json.dump(metrics, f, indent=2) + logging.info(f"Performance report saved to {filename}") diff --git a/tests-functional/clients/push_notification_server.py b/tests-functional/clients/push_notification_server.py new file mode 100644 index 0000000000..27030284c3 --- /dev/null +++ b/tests-functional/clients/push_notification_server.py @@ -0,0 +1,17 @@ +from clients.statusgo_container import PushNotificationServerContainer + + +class PushNotificationServer: + container = None + + def __init__(self, gorush_port=8080): + self.gorush_port = gorush_port + self.container = PushNotificationServerContainer( + identity="3e64442a0ba8a59b4d2dc7385cd4533a10e86dd644e7ec549cb92503787f5282", + gorush_port=self.gorush_port, + ) + + self.data_dir = self.container.data_dir() + self.container.start_health_monitoring() + + assert self.data_dir != "" diff --git a/tests-functional/clients/statusgo_container.py b/tests-functional/clients/statusgo_container.py new file mode 100644 index 0000000000..7b48e9b973 --- /dev/null +++ b/tests-functional/clients/statusgo_container.py @@ -0,0 +1,414 @@ +import io +import logging +import os +import random +import tarfile +import tempfile +import threading + +import docker +import docker.errors +from docker.errors import APIError + +from clients.metrics import ContainerStats +from utils.config import Config + +DATA_DIR = "/usr/status-user" + + +class StatusGoContainer: + all_containers = [] + container = None + + def __init__(self, entrypoint, ports=None, privileged=False, container_name_suffix=""): + if ports is None: + ports = {} + + # Initialize stop event for monitoring thread + self._stop_monitoring = threading.Event() + self.health_monitor = None + self._stop_perf_monitoring = threading.Event() + self.perf_monitor = None + + # Initialize performance metrics container + self.stats = list[ContainerStats]() + + # Prepare image and container name + # NOTE: This part needs some love. + # There's magic with `docker_project_name`, `docker_image` and `identifier` variables. + docker_project_name = Config.docker_project_name + self.network_name = f"{docker_project_name}_default" + git_commit = os.popen("git rev-parse --short HEAD").read().strip() + identifier = os.environ.get("BUILD_ID") if os.environ.get("CI") else git_commit + image_name = Config.docker_image or f"statusgo-{identifier}:latest" + self.container_name = f"{docker_project_name}-{identifier}{container_name_suffix}" + coverage_path = Config.codecov_dir if Config.codecov_dir else os.path.abspath("./coverage/binary") + + # Run the container + logging.debug(f"Creating status-go container from image '{image_name}'") + + container_args = { + "image": image_name, + "detach": True, + "privileged": privileged, + "name": self.container_name, + "labels": {"com.docker.compose.project": docker_project_name}, # TODO: Is this still needed? + "environment": { + "GOCOVERDIR": "/coverage/binary", + }, + "volumes": { + coverage_path: { + "bind": "/coverage/binary", + "mode": "rw", + } + }, + "extra_hosts": { + "host.docker.internal": "host-gateway", + }, + "entrypoint": entrypoint, + "ports": ports, + "stop_signal": "SIGINT", + } + + if "FUNCTIONAL_TESTS_DOCKER_UID" in os.environ: + container_args["user"] = os.environ["FUNCTIONAL_TESTS_DOCKER_UID"] + + self.docker_client = docker.from_env() + + try: + self.docker_client.images.get(image_name) + except docker.errors.ImageNotFound: + raise RuntimeError(f"Docker image '{image_name}' not found") + + self.container = self.docker_client.containers.run(**container_args) + StatusGoContainer.all_containers.append(self) + + logging.debug(f"Container {self.container.name} created. ID = {self.container.id}") + + network = self.docker_client.networks.get(self.network_name) + network.connect(self.container) + + def __del__(self): + self.stop() + + def data_dir(self): + return DATA_DIR + + def id(self): + return self.container.id if self.container else "" + + def short_id(self): + return self.container.id[:8] if self.container else "" + + def name(self): + return self.container.name if self.container else "" + + def _check_container_health(self): + """Check if container is healthy""" + if not self.container: + raise RuntimeError("Container is not initialized") + + self.container.reload() + if self.container.status != "running": + logs = self.container.logs().decode("utf-8").splitlines()[-10:] + logs = "\n".join(logs) + raise RuntimeError(f"Container is not running. Status: {self.container.status}. Logs (last 10 lines):\n{logs}") + return True + + def start_health_monitoring(self): + """Start background health monitoring thread""" + + def monitor(): + while not self._stop_monitoring.is_set(): + try: + self._check_container_health() + # Wait for 5 seconds or until stop event is set + self._stop_monitoring.wait(timeout=1) + except Exception as e: + logging.error(f"Container health check failed: {e}") + raise e # This will kill the thread and fail the test + + self._stop_monitoring.clear() # Reset the event + self.health_monitor = threading.Thread(target=monitor, daemon=True) + self.health_monitor.start() + + def start_performance_monitoring(self): + """Start independent container performance monitoring thread""" + # Reset metrics storage + self.container_stats = [] + self._stop_perf_monitoring = threading.Event() + + def monitor_performance(): + stats_stream = self.docker_client.api.stats(self.id(), decode=True, stream=True) + prev_stat = None + + for stat in stats_stream: + # Create ContainerStats with only container data + container_stats = ContainerStats(stat, prev_stat, go_memory_stats=None) + self.container_stats.append(container_stats) + + # Store current stat as previous for the next iteration + prev_stat = stat + + if self._stop_perf_monitoring.is_set(): + break + + logging.debug(f"Performance monitoring stopped for container {self.name()}") + + self._stop_perf_monitoring.clear() + self.perf_monitor = threading.Thread(target=monitor_performance, daemon=True) + self.perf_monitor.start() + logging.info(f"Started performance monitoring for container {self.name()}") + + def stop_performance_monitoring(self): + """Stop the performance monitoring thread and return the collected metrics""" + self._stop_perf_monitoring.set() # Signal the thread to stop + if not self.perf_monitor or not self.perf_monitor.is_alive(): + return [] + + self.perf_monitor.join(timeout=10) + if self.perf_monitor.is_alive(): + logging.warning("Performance monitoring thread didn't stop gracefully") + + return self.container_stats + + def stop_health_monitoring(self): + """Stop the health monitoring thread""" + self._stop_monitoring.set() # Signal the thread to stop + if not self.health_monitor or not self.health_monitor.is_alive(): + return + self.health_monitor.join(timeout=10) + if self.health_monitor.is_alive(): + logging.warning("Health monitoring thread didn't stop gracefully") + + def shutdown(self): + """ + Stops, saves logs, and removes a container with error handling. + Args: + container: The container object (should have stop, save_logs, remove methods) + log_prefix: Optional string for logging context + """ + if not self.container: + logging.debug("No container to shutdown") + return + + container_id = self.short_id() + self.stop() + self.save_logs() + self.remove() + logging.debug(f"Container '{container_id}' shutdown finished") + + def stop(self): + """Stop the container and monitoring""" + self.stop_health_monitoring() # Stop health monitoring first + if hasattr(self, "_stop_perf_monitoring"): + self.stop_performance_monitoring() # Stop performance monitoring if running + if self.container: + logging.debug(f"Stopping container {self.container.name}...") + self.container.stop(timeout=10) + logging.debug(f"Container {self.container.name} stopped.") + + def remove(self): + """Remove the container""" + if self.container: + name = self.container.name + logging.debug(f"Removing container {name}...") + self.container.remove() + self.container = None + logging.debug(f"Container {name} removed.") + + def pause(self): + if not self.container: + raise RuntimeError("Container is not initialized.") + self.container.pause() + logging.info(f"Container {self.container.name} paused.") + + def unpause(self): + if not self.container: + raise RuntimeError("Container is not initialized.") + self.container.unpause() + logging.info(f"Container {self.container.name} unpaused.") + + def exec(self, command): + if not self.container: + raise RuntimeError("Container is not initialized.") + try: + exec_result = self.container.exec_run(cmd=["sh", "-c", command], stdout=True, stderr=True, tty=False) + if exec_result.exit_code != 0: + raise RuntimeError(f"Failed to execute command in container {self.container.id}:\n" f"OUTPUT: {exec_result.output.decode().strip()}") + return exec_result.output.decode().strip() + except APIError as e: + raise RuntimeError(f"API error during container execution: {str(e)}") from e + + def extract_data(self, path: str): + if not self.container: + raise RuntimeError("Container is not initialized.") + + try: + stream, _ = self.container.get_archive(path) + except docker.errors.NotFound: + logging.error(f"Path '{path}' not found in container {self.container.name}.") + return None + + temp_dir = tempfile.mkdtemp() + tar_bytes = io.BytesIO(b"".join(stream)) + + with tarfile.open(fileobj=tar_bytes) as tar: + tar.extractall(path=temp_dir) + # If the tar contains a single file, return the path to that file + # Otherwise it's a directory, just return temp_dir. + if len(tar.getmembers()) == 1: + return os.path.join(temp_dir, tar.getmembers()[0].name) + + return temp_dir + + def import_data(self, src_path: str, dest_path: str): + """ + Copy data from the host (src_path) into the container at dest_path. + """ + if not self.container: + raise RuntimeError("Container is not initialized.") + + if not os.path.exists(src_path): + raise FileNotFoundError(f"Source path '{src_path}' does not exist.") + + # Create a tar archive of the source path + tar_stream = io.BytesIO() + with tarfile.open(fileobj=tar_stream, mode="w") as tar: + arcname = os.path.basename(src_path) + tar.add(src_path, arcname=arcname) + tar_stream.seek(0) + + # Put the archive into the container at the destination path + try: + # Ensure destination directory exists in the container + response = self.container.exec_run(cmd=["mkdir", "-p", dest_path]) + assert response.exit_code == 0, f"Failed to ensure directory exists: {response.output.decode().strip()}" + success = self.container.put_archive(dest_path, tar_stream.getvalue()) + assert success, f"Failed to put archive to {dest_path} in container {self.container.name}" + except Exception as e: + logging.error(f"Failed to import data to container: {e}") + raise + + def get_name(self): + return self.container.name if self.container else None + + def save_logs(self): + if not self.container: + raise RuntimeError("Container is not initialized.") + if Config.logs_dir == "": + logging.debug("Save container logs skipped") + return + + file_path = os.path.join(Config.logs_dir, f"container_{self.short_id()}.log") + logging.info(f"Saving logs to {file_path}") + + with open(file_path, "wb") as f: + logs = self.container.logs() + f.write(logs) + + +class PushNotificationServerContainer(StatusGoContainer): + def __init__(self, identity, gorush_port): + entrypoint = [ + "push-notification-server", + "--identity", + identity, + "--gorush-url", + f"http://host.docker.internal:{gorush_port}", + "--data-dir", + DATA_DIR, + "--log-level", + "DEBUG", + "--waku-fleet-config", + Config.waku_fleets_config, + "--waku-fleet", + Config.waku_fleet, + ] + super().__init__(entrypoint, container_name_suffix=f"-push-notification-server-{gorush_port}") + + +class StatusBackendContainer(StatusGoContainer): + def __init__(self, host_port: int, privileged=False, ipv6=False, **kwargs): + container_port = 3333 + entrypoint = [ + "status-backend", + "--address", + f"0.0.0.0:{container_port}" if not ipv6 else f"[::]:{container_port}", + "--pprof", + "true" if kwargs.get("pprof_enabled", False) else "false", + ] + + self.ipv6 = ipv6 + self.url = f"http://{'[::1]' if ipv6 else '127.0.0.1'}:{host_port}" + + if ipv6: + ports = { + f"{container_port}/tcp": [ + {"HostIp": "::", "HostPort": str(host_port)}, + ] + } + else: + ports = { + f"{container_port}/tcp": str(host_port), + } + + super().__init__(entrypoint, ports, privileged, container_name_suffix=f"-status-backend-{host_port}") + + def _change_ip(self, new_ipv4=None, new_ipv6=None): + if not self.container: + raise RuntimeError("Container is not initialized.") + + # Get the network details + network = self.docker_client.networks.get(self.network_name) + + # Ensure network has explicitly configured subnets + ipam_config = network.attrs.get("IPAM", {}).get("Config", []) + if not ipam_config: + raise RuntimeError("Network does not have a user-defined subnet, cannot assign a custom IP.") + + self.container.reload() + container_info = self.container.attrs["NetworkSettings"]["Networks"].get(self.network_name, {}) + current_ipv4 = container_info.get("IPAddress", "Unknown") + current_ipv6 = container_info.get("GlobalIPv6Address", "Unknown") + + logging.info(f"Current IPs for {self.container.name} - IPv4: {current_ipv4}, IPv6: {current_ipv6}") + + # Generate new IPs based on mode + for config in ipam_config: + subnet = config.get("Subnet") + + if self.ipv6 and ":" in subnet and not new_ipv6: # IPv6 Subnet + base_ipv6 = subnet.rstrip("::/64") + new_ipv6 = f"{base_ipv6}::{random.randint(1, 9999):x}:{random.randint(1, 9999):x}" + logging.info(f"Generated new IPv6: {new_ipv6}") + + elif not self.ipv6 and "." in subnet and not new_ipv4: # IPv4 Subnet + new_ipv4 = subnet.rsplit(".", 1)[0] + f".{random.randint(2, 254)}" + logging.info(f"Generated new IPv4: {new_ipv4}") + + # Disconnect and reconnect with only the needed IP type + network.disconnect(self.container) + if self.ipv6: + network.connect(self.container, ipv6_address=new_ipv6) + else: + network.connect(self.container, ipv4_address=new_ipv4) + + self.container.reload() + updated_info = self.container.attrs["NetworkSettings"]["Networks"].get(self.network_name, {}) + updated_ipv4 = updated_info.get("IPAddress", "Unknown") + updated_ipv6 = updated_info.get("GlobalIPv6Address", "Unknown") + + if self.ipv6 and current_ipv6 == updated_ipv6: + raise RuntimeError("IPV6 is the same after network reconnect") + if not self.ipv6 and current_ipv4 == updated_ipv4: + raise RuntimeError("IPV4 is the same after network reconnect") + + logging.info(f"Changed container {self.container.name} IPs - New IPv4: {updated_ipv4}, New IPv6: {updated_ipv6}") + + def change_ip(self, new_ipv4=None, new_ipv6=None): + try: + logging.info(f"Trying to change container {self.container_name} IPs (IPv6 Mode: {self.ipv6})") + self._change_ip(new_ipv4, new_ipv6) + except Exception as e: + raise RuntimeError(f"Failed to change container IP: {e}") diff --git a/tests-functional/resources/images/test-image-200x200.jpg b/tests-functional/resources/images/test-image-200x200.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c83855aec0ae10b90ad9520bf6926229d00be0b8 GIT binary patch literal 4925 zcmb7HcOcaN|G#s#!<{|r&fc7zgtK>NRze(SDJdOV-6=lkT-$sAx>?~bP%0AOS!0iXo{0Mq~$AP4{? zbEg*%km^rsOXhk1<{inr*xxb~WS*7cKY7oGlz-&O2LF&D`F?8WpOyvycuWJJB)^f9 zN5}ya|KfpU3lEZL0377^ugMo6_iq`5oE$LsFY6~K002eqU)FocBB1}_PgRgsIz~q1 z7Uk&@7~~5x(p7^g$|FuD0XhI$YHAv4Dq0#E8ag^!dN3O!n1KPz&BDse#?N#13_lMa zA52I_6eb`g$j2w9A}%F|P*hYrD|+sNs=T_4f};GX5g;8M9hd>k#mLAd59fo+|G(*^ z69APlx~>@<4!OIvv5^M4k*vDr#~c=V{0P_K>HN0(3F~0E2)4 z3J3^7ex5GcUA9q@CRqeAiFe`sP0Y1>T_6-XM)daiQ2PdzBKxF?$E`#8Q>sni;aH$R zpI+eum_UA{@p8$qiyw}$pWki4xbF#f6eOOO5!|H>HAeMG@-|7?&{5YnXDji!dp}ZW z;48-Pi3U1?Mu)dAJ*UaMd-ti@?zVct%UWhPM3wCIF{fM23-6yBy}O4`u1?KY$hL^L zk5NHYz{VD`rr76W=~;dBaGd%g+pgY^ts;kfhJN5(a%05|(VUVC?p{j5){$k-JfCOp`mRItLuBB{iUIT?+Q2VpE`sBqeQAy9f-qD z;QXs}Qm|nS8plE2xiIV_p7ny5{pPvz8J)j$5_jt!Z@9Au)y40PbpEDSe@`mgX1=Ur zdRQ^IOk*+F;yYkHD#6DjR%nT1N*?TqtP!U~`HzVtS9mylDX3U@EypKUN7{h}{<34Vd#M1=i&S^o>9DbG&X# z>M%K{h>(2LIVih04d39d5VC)79R+u0I{$_ z*x)b$IRqurkG$Bl?3~|5zETT3c6C7nNcz3Ehoob@2QXTP>h}6ulM3F zxQalqQx{l7M8r@+wBcL@Y%aUhB0@$Hk?e>c%WILeg3*ZO<0B;V4w5poW0ewOu<|z1 z#>i#@I&Of$|E74Qql|LR=`q<<4HB{mW!g0*92WK^xw`qdxqaeai%;d&EP;`YY(6P# z4Rkxawe*7zNeMy5ke!{j=vTLH*Y4~$DFlByPlMslG)ZtCFI-36l1}}cU#2qo?{QV- zs`9XJ?j*7iE8^zr<{B3>e_^=tK{_L6@Q6=o8?y~&YVPC)CAvY;h| z5@poY6>|IhWn*~N=a(jJKd6XRrWIm|7tg>ys#{qshztK%pGQW}d@&1YLe{XWd5L$( z(pdB64q+vI@TMP)Vs-sfc%j)M#Q3;zqsH;Zh?&Cahd0LsUF!s_*o}C(C(pAz@jy2x zHVl2c&1+Gcj21CSl(IRCM-<|8;E9$OgdZbgh0kIU`a;N6(VeY6`a&OzoD4Y0MBZ)8 zSDBl|a8h1gx1d8qeL)Z{5mX}-CU`T?#^j4xbt_1kwGY4}>6~@<<98TrQDSKsyhlHHWfr zM*BrX){gv*QEE+!-{^# z$K7D}?pE^KLV9|Z{|K@Eh|s3R=#omx(~?jr!gSh;GJnpnYeLCm*=czKldm#=E<|}a6w9ss@v+ffr4rG41SQRK@H@~yK{lqmPfOl=!X(x+Q zJnZ0{E)4r9i@?cOuSj4kRk|)=oHX__X{U14Q>VXJPm_h@lQBt1KAkKv2!OmnfhbQS z`QIppLl8&{XaB?qSYFL{xsk1oxql*A6aK*?s%Ru!aAYkiA0uvTp*dSLva+K+meOh& zLol`^n3R8@)ssolWBuTLv*=K)2Og?eB(D3`qBf;S+@u`R9=VcXQZz<>FouUh5>{|y zkT~2Jo`Vda|k42{PI=Lo)jOWkM%@j5Cl#tJg)=Yf%17g>S(yBM?Pf%WnU z&j=ptU}2U}aB)xE0GGbN1XW}D1904h`irYrvD$tXbiK-FuB&u;r7!dfN&4=l8S+8{ zeHR7H>798KyIJC)&z`S4!S=R#ypPI76OS@-3T%D9{rw+#!u$g6H41jpHEZAd1( zIiKTA`cT@I^7ToXCS8FP^Op1PFuQ`i8NLOJ8eM0I@TOnXCxCUyuR9kjXtg0YkwY7W z+W6f{>G>|{5eqEk=;+nKf&+BIKf2;X)SJP$(y1&Uho%2fbZrJ)NLPh#0&%M{|mPe?&X=F(3BD=DzG=D!u zhybC*!T2!s^Sk6ehL$siZ3*t-o8htHv4QPqPD4&T4bvA|%MrIr+&L;sZYM9c9gk8a z9OsWyK05)NBVhY}S*riyU;3t#R)zkW=O@<+yl&X;YFcO9FgM&Gwk0!tFW#T2+DzDF zC1(Nl9rjVc?RNx0*t7K-C_AkCVua$9?yK!{{?64gPZ{hsU?0!={X`3gQN9ZaNnrO4 zi66WnWh0-o%^kkt5T3-#99%xWRHe7cz*oHDF=ILz93D}Cvk&iLxvc?AG?J=Ux#TWK zw7OSWWK`&mLrqSz2fJe5jvsLPAtR>a-=xyAMCITtC$}FR3@yCm1Q|r!e1m<~sJ%px z`&}#9nIMG%zv@tW%O(=r@{md6GF~I@VepIH8@;}b?bO}(9@Xu!sN_i9E2gS9mtkvT z+Dh4%5dQT5T%GaiCl8n263eu})%F&%gPFuHJC_hmH=~7bRWQaai;tXT6HjYfuw2``^jPV&oX4XqsPK1 z&lg?~Z)##x&UE=g$A{i<9!I!M3K8@zuUawYSSZc?JijQ~!1&}W*h*tBh>)KEOX-kw z8a_PY9PWAk1zu&Vh~AqL>~J6wB7Y8B!<|a5+(=VA;HW0X_Z{DcGrhqHO;*)(gg|S5 z!HbgGsl^lE#VfOIhHcK*3p_JL}g zpTv||F{uG#iWACcJn%QHO9IMryS1e!u=H=V_HLH-OSN7dU=xiBh?c1H zEU21#Hnro1DZbX#V5@h=S+(vpSo6L5_+m_7 za}={efuDW)i=1b8q2w?5H^uzP%RnduCI{F0lUh!90thVHZ0@{ybsP>(mm4Q~<-5A+ zbEpY*7dlofE^cRM$51(10v1UhOQz@p7eO+?Y6Xbex}t1|z(0G&U$y8zX^iaS)B{`& zf&Am*bkBgCF&8n*(##f{=}9Ti$`)jxio$#yZ0G8$(v69Vb%g(Zh>H~w>NKa)_9%eM zL*f#m;&2OF4musnS(aM|S%bJ9b@bc~vNKT#xrU`6*FWUa|8#~=e-oha)2s>ck4Vhx zs2Q1qZGHbYYeLASzY2RbdT>BN<|a0}@(uxIAz9H5Hh5L;jHQ(4nTfYgC-; zaIx0@1tG?@mB1m_IVg~*W8prEmbIeQH+`w4t^OE)0*H8fEiaH`p6GIksw6sNJdXL;`#_*aD{Jj)Owr^IfwHLw&j!C#_$VH#CM`FpcNZG=g5HpeYaoog! zej>9;37vaDA8ubSjX-K5z5if~&f8(E-4v*H&?&PbJzKhf43Z`tr0mMd205l4raf}H zV4@oBg9q8Am{f1;L}Odqb$PGh&OcU+SK{qF0gUiZ;8kF4mXB({M*;zFR4;#*zrTpL zQBv&I^T;;Rt1^gb@SGbcPMBBIr6NtUEH_JieNSUmf>%NE$X~9akPJ?%Ceg-f#5GaM z=UMPxni{6I{CII7=&g%FCf+!o5l!t@^pGoxTfm8OY?iN^2~CLc7l5UCU7J_KW7Lh6 zOsCI9`d}ZVa@XJgfTnZA`gJOka>wAEh;!iL(sh?ncdXwzlMEk;>yY4BZ^*diKpB6c zPV^V`V1jatG&fdSfhxvIWZv5cAuU}KAD_xn>Y9h!@X|QIb*CT1G+ODS^hAraRnQ3% zZ_}&dt__UM^o0{Os5T0@{`;o(WosUoU!*(Iu-@<(N2A6u+R9s_+7qio0*S+9_>uY4E%JA~X0N z=I3uM`(t58%=wghiU?o36+#+e&5^nEdQs8re7a=Xjx_0Ib*_}{RC{XFT2U}o5%%Fr z`I)WsuwJv2X<)*c;k!5QrE(u|Sg4M@XL)Gm(j&ar(DZ=88U`%8XZ&P#wLcnT zw_JaAU+e@>@<4N(;RI0YaCpTt8Xu#%U3UVIW@0X&l)hBURvr?L({bYg{?@h2kq!6f z?wFq;@$-em>jLX~g2YRM^DCV{N4!Q1>~jLdBEQfM-$&<=ILLnrrGbRVrKlt4SB1^I zuf4v0qt1Sces6up3D+HlnP)=;8;o7udOQ<*s5L;qVFIBO!dV9&9vA}3tO6GLCWw%- z5rthb<0NN;pyb#6BjM40a1H+-sM^W3+NjJ4^rGYu_ch54KJ98>tLa^uT#FB@B>)$owIk-qB%(X$fU&Da`e(XbClYZBT}PP181SE9}mxRJPZ-u3YDX& zgV3>sD#A41+hfsENTKZRc>-BH=;U=mA#u71a#VKd9OHy-}| zSeD{=IKMfw5goDZQW)wVbW}ZJdjhCjQr4McEuof|yH|M+thINioN79_Wb?`wiiz_+ z&eJyIweHeQ1Ny|ZHLh|tI%eumArFYCP<|wh2@JF#l4n_NPw$4hpPlx*bC!0CE4^XE zhTh92kI1nnsOcyBOJQHE^33B3CN5RlM!WA6WubUjvCzv#Vo!I60akO39(@K%Jvqq= z@B0Sra!gYG`lTrx!WNq7eUNtP`4_2j1CA4b1>I$w_0KF_>U6P=uA|&3p8^;Cd?O*2^t2{JgW6n0{NUj&wXnX~a zX+o8?8*PRHn|1GSADF>Rn?x6q6gv2n{7loorQ6!x>qlKf+2$t|j|4n08WxyfAO21| z(qh|=7^vAupAF}Z>^?(R>hHE6s9F=N{Bn|}#vXKypb#TFtWpx=In z-&s{Kuj-~`D=$%%w;DrOVZJr@!F%2{&w#DF&ZSF!lxEs_mIp?hOgB;AXDLcm-=fA( z#XpO?-Q3t;dBY0m^6ZkA?UTb)ZeX^R8y$c#ZOl#Bwdt+b722X1`OY6(_`Kvy7^`6J gkf2cr)RuRXjKAn_G{jeS@mG{4Ts|e?15d{P56YEGga7~l literal 0 HcmV?d00001 diff --git a/tests-functional/resources/test_data/__init__.py b/tests-functional/resources/test_data/__init__.py new file mode 100644 index 0000000000..02b3d28c5a --- /dev/null +++ b/tests-functional/resources/test_data/__init__.py @@ -0,0 +1 @@ +# Make test_data a proper Python package diff --git a/tests-functional/resources/test_data/mnemonic_12.py b/tests-functional/resources/test_data/mnemonic_12.py new file mode 100644 index 0000000000..aaba1ae739 --- /dev/null +++ b/tests-functional/resources/test_data/mnemonic_12.py @@ -0,0 +1,61 @@ +# Account data for mnemonic with 12 words + +accounts = [ + { + "address": "0xb01a7dbaaacc92581558a4d178289be7471ba0f4", + "public-key": ( + "0x047fd6e4384b764cb7782bf747ad3fb51e8c54c2b3c2be7029c72d85d16b07f4be6a8703cf0a1d97be4c8712ad" "52cd6a519efdc723faae4935bbaba5c320dde02b" + ), + "path": "m/43'/60'/1581'/0'/0", + "prodPreferredChainIds": "1:10:42161:8453", + "operable": "fully", + "position": -1, + }, + { + "address": "0xc43f4ab94ec965a3ee9815c5df07383057d261a8", + "public-key": ( + "0x041d8f6ebfa662c506d3d11cd407373f8ff2eb4c9ddc61a834864150a908172efbaa37f0de7dbeeea51f02272" "74e6ccd78fa5a07de55716094dbba475ac9e9ab44" + ), + "path": "m/44'/60'/0'/0/0", + "name": "Account 1", + "colorId": "primary", + "hidden": False, + "prodPreferredChainIds": "1:10:42161:8453", + "position": 0, + }, +] + +profile_data = { + "address": "0x5f8e02f9f52709b29c82bd893d9af0f83273a6e4", + "currency": "usd", + "networks/current-network": "", + "dapps-address": "0xc43f4ab94ec965a3ee9815c5df07383057d261a8", + "eip1581-address": "0x803102f704324d4a4f2ddb1c47f6ab31339d0f70", + "key-uid": "0x3231d92c94548d14f097173765a50bebe28fbad8f2267c9e08cc4433a6f219a4", + "latest-derived-path": 0, + "link-preview-request-enabled": True, + "messages-from-contacts-only": False, + "mutual-contact-enabled?": False, + "name": "Anchored Open Wirehair", + "networks/networks": [], + "news-feed-enabled?": True, + "news-rss-enabled?": True, + "photo-path": "", + "preview-privacy?": False, + "public-key": ( + "0x047fd6e4384b764cb7782bf747ad3fb51e8c54c2b3c2be7029c72d85d16b07f4be6a8703cf0a1d97be4c8712ad52cd" "6a519efdc723faae4935bbaba5c320dde02b" + ), + "default-sync-period": 777600, + "appearance": 0, + "profile-pictures-show-to": 2, + "profile-pictures-visibility": 2, + "use-mailservers?": True, + "wallet-root-address": "0x1846a7930d0ab03e5a120ebdd46eff3fe0365824", + "send-status-updates?": True, + "backup-enabled?": True, + "show-community-asset-when-sending-tokens?": True, + "display-assets-below-balance-threshold": 100000000, + "url-unfurling-mode": 1, + "compressedKey": "zQ3shoF8xQNaT44MWQxztUXK6DK9UU63PRgJhn1Zd7oYWXJ5K", + "emojiHash": ["🔢", "🤞🏽", "🖍️", "🙇🏽‍♀️", "🙋🏼‍♀️", "🙌", "💎", "🎞️", "😊", "🦸🏼", "😤", "👵🏿", "🧑🏿‍🔧", "🤶🏿"], +} diff --git a/tests-functional/resources/test_data/mnemonic_15.py b/tests-functional/resources/test_data/mnemonic_15.py new file mode 100644 index 0000000000..fc18fcd62a --- /dev/null +++ b/tests-functional/resources/test_data/mnemonic_15.py @@ -0,0 +1,39 @@ +# Account data for mnemonic with 15 words + +accounts = [ + { + "address": "0x245b7438961de05444645898f9215e5cf0786891", + "public-key": ( + "0x04c898c7763afd577f10efdd9e5d607caafd6d708e6cad8cee1b6d822d6ab148eb4e76d1c8266c8b73c8ce1d76" "699e072ac5844a9a6934abb565044bf619336302" + ), + "path": "m/43'/60'/1581'/0'/0", + "prodPreferredChainIds": "1:10:42161:8453", + "operable": "fully", + "position": -1, + }, + { + "address": "0x685d7ec8e08769ca7020a6b65709887e38e68e6d", + "public-key": ( + "0x0480acddfad1e73c3e70e8e50f82eb1566e3df125736e9fe9042c4df5022c825afe6234021ad8bbb43e0ab0196" "878c2d9e3c8b5a8f266aca72b0e23d1f84464c72" + ), + "path": "m/44'/60'/0'/0/0", + "name": "Account 1", + "colorId": "primary", + "hidden": False, + "prodPreferredChainIds": "1:10:42161:8453", + "position": 0, + }, +] + +profile_data = { + "address": "0x3644a8cc3860606fdee3b95c8825e17933a91647", + "dapps-address": "0x685d7ec8e08769ca7020a6b65709887e38e68e6d", + "eip1581-address": "0xe98734898ff58ac33a1a9c28f732696ec3e6b580", + "key-uid": "0x944c1ce03f83dd1750acee591745d6ef14da90723af86f97b2df7d7282e8dd97", + "name": "Overcooked Lost Grayreefshark", + "public-key": ( + "0x04c898c7763afd577f10efdd9e5d607caafd6d708e6cad8cee1b6d822d6ab148eb4e76d1c8266c8b73c8ce1d76699e" "072ac5844a9a6934abb565044bf619336302" + ), + "wallet-root-address": "0xe89675c9be641ceeca9f250345dc58528c3de93b", + "emojiHash": ["🏄🏾", "👒", "👨🏽‍🎓", "🅰️", "👩🏾‍🍳", "🪀", "📩", "🐄", "⏳", "👸🏻", "🚣🏾‍♂️", "👩🏽‍🤝‍👩🏻", "📀", "🌒"], +} diff --git a/tests-functional/resources/test_data/mnemonic_24.py b/tests-functional/resources/test_data/mnemonic_24.py new file mode 100644 index 0000000000..fdc7c7d070 --- /dev/null +++ b/tests-functional/resources/test_data/mnemonic_24.py @@ -0,0 +1,39 @@ +# Account data for mnemonic with 24 words + +accounts = [ + { + "address": "0x8a6d1f3b9f158f7274ca4be1a3f0056c86e2ccdb", + "public-key": ( + "0x04c25b359fab7fc8989d6325128b06dd9734b38d207dc2ab652e130a5d59852910fd6414694e1f5ce3a9cdd5c1" "f6bec9a425a57bae10c98ff4337adba3bf8c18bb" + ), + "path": "m/43'/60'/1581'/0'/0", + "prodPreferredChainIds": "1:10:42161:8453", + "operable": "fully", + "position": -1, + }, + { + "address": "0xf2d58ae5aa880f7c3f65d769296b1061c61e0955", + "public-key": ( + "0x04218096ceb5420c9b4cfa9d0187a057099540edff0aa5882b0a16b76fc8f0056d1a01930db4981f8885d00137" "c535740c04eec7ebe8bae7ef9fd98338fba31e04" + ), + "path": "m/44'/60'/0'/0/0", + "name": "Account 1", + "colorId": "primary", + "hidden": False, + "prodPreferredChainIds": "1:10:42161:8453", + "position": 0, + }, +] + +profile_data = { + "address": "0xb47386b0074a9ddfd979540f134915d1df8dc3d0", + "dapps-address": "0xf2d58ae5aa880f7c3f65d769296b1061c61e0955", + "eip1581-address": "0xf203f9c33afd10e2d3888289ad2cad81c4b017c4", + "key-uid": "0xcf119f28496e4123dd6d5a4936c5f595ee1a873b11ead5f275098456eb8777c4", + "name": "Selfassured Pesky Mayfly", + "public-key": ( + "0x04c25b359fab7fc8989d6325128b06dd9734b38d207dc2ab652e130a5d59852910fd6414694e1f5ce3a9cdd5c1f6be" "c9a425a57bae10c98ff4337adba3bf8c18bb" + ), + "wallet-root-address": "0x0410bd5715fdd8ccadede1d3131a9180a96e502c", + "emojiHash": ["👦🏻", "🕔", "🧜", "👩🏽‍🤝‍👨🏼", "👩🏿‍🔧", "🉐", "🧝🏿‍♂️", "🚣🏾‍♀️", "🫀", "🏄🏿", "🌘", "🤵🏼‍♀️", "🏄🏿‍♀️", "🎴"], +} diff --git a/tests-functional/resources/test_data/profile_showcase_utils.py b/tests-functional/resources/test_data/profile_showcase_utils.py new file mode 100644 index 0000000000..a7b02a6549 --- /dev/null +++ b/tests-functional/resources/test_data/profile_showcase_utils.py @@ -0,0 +1,93 @@ +def dummy_profile_showcase_preferences(with_collectibles: bool): + preferences = { + "communities": [ + { + "communityId": "0x254254546768764565565", + "showcaseVisibility": 3, + "order": 0, + }, + { + "communityId": "0x865241434343432412343", + "showcaseVisibility": 2, + "order": 0, + }, + ], + "accounts": [ + { + "address": "0x0000000000000000000000000033433445133423", + "showcaseVisibility": 3, + "order": 0, + }, + { + "address": "0x0000000000000000000000000032433445133424", + "showcaseVisibility": 2, + "order": 1, + }, + ], + "verifiedTokens": [ + { + "symbol": "ETH", + "showcaseVisibility": 3, + "order": 1, + }, + { + "symbol": "DAI", + "showcaseVisibility": 1, + "order": 2, + }, + { + "symbol": "SNT", + "showcaseVisibility": 0, + "order": 3, + }, + ], + "unverifiedTokens": [ + { + "contractAddress": "0x454525452023452", + "chainId": 11155111, + "showcaseVisibility": 3, + "order": 0, + }, + { + "contractAddress": "0x12312323323233", + "chainId": 1, + "showcaseVisibility": 2, + "order": 1, + }, + ], + "socialLinks": [ + { + "text": "TwitterID", + "url": "https://twitter.com/ethstatus", + "showcaseVisibility": 3, + "order": 1, + }, + { + "text": "TwitterID", + "url": "https://twitter.com/StatusIMBlog", + "showcaseVisibility": 1, + "order": 2, + }, + { + "text": "GithubID", + "url": "https://github.com/status-im", + "showcaseVisibility": 2, + "order": 3, + }, + ], + } + + if with_collectibles: + preferences["collectibles"] = [ + { + "contractAddress": "0x12378534257568678487683576", + "chainId": 1, + "tokenId": "12321389592999903", + "showcaseVisibility": 3, + "order": 0, + } + ] + else: + preferences["collectibles"] = [] + + return preferences diff --git a/tests-functional/resources/test_data/test_old_user_data.bkp b/tests-functional/resources/test_data/test_old_user_data.bkp new file mode 100644 index 0000000000000000000000000000000000000000..adef914bed5f7bc8017e66c71ab2209c0951e26f GIT binary patch literal 2622 zcmV-E3c>XPg`=`CE`Kt0%Dbggysnq8{l1|3)#;-%MmO6YZ7q-$8HzV)&x!Vm1D^lv ziy^9Q`P$W7FYA0$Jo4)$ z$;OI~2^irQ#32pr{xpib9+s**96_Cv_h*j38nolw_>u%$!i6BUAo~C7yVF3f$e4L% z)tvy0kjf7CDJc_EQdWwyhaY+9#YLt*DMmWRY_(q2LqyY}k7C?9J-D-mM|}8#i`@PV z+HGs!PEB>$xn$Tb(V2}N2ot;DsSN61*ZDf)FD`-C3Q#zH{tOFuuC=B`ubDWvY#w)1 z?|Nqqi)#Hy*@lC?Hv9?)f0y8tpHW(e>X+jlr2)v@Dz~1NeaWCNWacl>&fIb7m!_YY zs#B!S*t?5cT(uW~fp|qeCSYchj3E`l{k4$|bMYL5M@K?!y?4uR{Gh+@nJ2g+@I@n& zT!wGMZTM6knGci42yu{LgAgb5o(Z4F+&!1xe z*qR|a#`}0sf}COYUuok(-%G3!|6`|9e1)h2Qq*T$acT*iT={E=F2KZ!%`$_f6zeAq zX{n(+g_|R(#o?*^kkp&qLEu51{Mj`0gq{*@S_l20t;I}qy=e!HjQh!LiF~vJ>c6iu z5X&$PlEV8?_r$PRa5d+JH?zfWNWs`<33H%-FDwZ7YqJHSXh1hg_*G)wpm$|NJ^0|E zbN1J>`|T{t9KKQSODTa*f9|4zuX$3hH_5Qikx@Mff0Y9#I_Lz)691SD2wp}W7u)BX zONh*dkaq{wRUF8EOp{_!{ZqO{sD*Z8Q)3(ky4z?yeY8o& zl?9V*oil zz^a5fJb)$!s5${zCok>hP_hOX3$t379AEfq=Eh!n-qSdYo9V8X1nN-Fu%|j}KD#j< zK?W8AUstQ{d}}&pZiNe$7t4nYg2|A37u$*ilSd(AXy94#O!%gRR>1KoAk_8qb)Dwm z1?Mw0rf)~iUdp~KvD|3@>qq|}SNeJSw+x8Flq07u;%OcacYyl5BN+X1iVrtPPAu_k zB5n2}@m!kTP5=xVvep48#KI|#iCu?ix@iIaOg0u!m`d_^x+&30@#Ij$hZmAU*z4gN z;C)k`yEB0Ww4G$g^8|Ol6U_ROW+(1HKALbP#bJXTW{q@2zbh8344QrN7Eb(|Ieqc~ z^hfR?OYYtG@C~Q8qfl!M^o)CK@MWXngvEJ@fGXBzo6d6WLR06Az-?WfcTVi9+(Q%e-fR#c% z4R)dspY8A_d5F#MV%qc14jGf${LD?o0!>IS(;pxYMo*@UV};0+YVB zPt|Aayfd70nO70aQBTdjJ}yiQU}Dvk119v$`jr5M3vs$*m=iPdu)smIjoTJ!Bnb%S zynffFRi6#c^Lr2Jc9CdS2D zO3|is^u7#n6?A>j;x2`7n0N0)8rI=b=i@=Ct($8gYXKp20UYCzW)0K6g1*M!)yk4Tyq|A+i6-3M1Ah-Oa4d(@&!Nse6hyNyGj|w9 zm=Z|&1^L`Bp}frkX7mrax$l`zWIDg7 zs=|gitJ#<--$gP(^X;s!DJN_~3&Lmm9AiaCUQMdO5-+Sx8%8_Q&GRGC<|YYqocO@P zJwJgkZZCt{bO*ErO4ZuWSBpGv_9?x9|_WIah*)VOCw0 zFd-vJVyc4Cy2Etc6RD%ub)Cu`*Qf?;rQ)$TL1hm*wv>6{AavKpHZkU2 zIE!MCwL~s|=yPEr*3XpWc4Y1x6NB3d(A^emivBXQ) zgz(_15@mEMEOdasQ1Bc9sCiJG_4k7XME-R($(TaCLMR!Iux!pdd#lq#E3)bXDV>Gk zKt&UbMmG!wVCOPCi^?kw0t-X*JDow?pzqa|7({yjeYIca|%u14_ddvv`$ z-fe5>mT?+NpQ0I&76VWE3%g(rQI0G<@6^=&S1!(UP){310W`$rnhyoR&F^v+*tz$L z1Tu@$#3ZGdqks%pp$RLj2wEtEl3X-$LF`yD>8PKe`4Yz2WcbKIA;NDSUeeQvy*YuX zXMBvm%SMO2$$x&_?z^;7uKDz?pROeXqHyMu20_5Q*W!$j z*F&gGa>;Fu-~!Jjlqvq|W6u=poK5=0YE_5Bf?RDHCQk}_-X08*r#Tx&vWrDd5HU= timeout: - raise TimeoutError(f"Tx {tx_hash} is still pending after {timeout} seconds") - time.sleep(0.5) - response = self.rpc_client.rpc_valid_request(method, params) - return response.json()["result"]["tx"] diff --git a/tests-functional/steps/messenger.py b/tests-functional/steps/messenger.py index 68e2ad4fab..4265f491ab 100644 --- a/tests-functional/steps/messenger.py +++ b/tests-functional/steps/messenger.py @@ -1,3 +1,5 @@ +# pyright: reportOptionalMemberAccess=false +# pyright: reportAttributeAccessIssue=false import logging import random import string @@ -6,8 +8,6 @@ import pytest from tenacity import retry, stop_after_delay, wait_fixed from clients.signals import SignalType -from clients.status_backend import StatusBackend -from resources.constants import USE_IPV6 from resources.enums import MessageContentType from steps.network_conditions import NetworkConditionsSteps @@ -21,47 +21,58 @@ class MessengerSteps(NetworkConditionsSteps): SignalType.NODE_LOGOUT.value, ] - @pytest.fixture(scope="function", autouse=False) - def setup_two_privileged_nodes(self, request): - request.cls.sender = self.sender = self.initialize_backend(self.await_signals, True) - request.cls.receiver = self.receiver = self.initialize_backend(self.await_signals, True) - - @pytest.fixture(scope="function", autouse=False) - def setup_two_unprivileged_nodes(self, request): - light_client_mode = request.param if hasattr(request, "param") else False - logging.info(f"Starting node with wakuV2LightClient: {light_client_mode}") - request.cls.sender = self.sender = self.initialize_backend(self.await_signals, False, wakuV2LightClient=light_client_mode) - request.cls.receiver = self.receiver = self.initialize_backend(self.await_signals, False, wakuV2LightClient=light_client_mode) - - def initialize_backend(self, await_signals, privileged=True, ipv6=USE_IPV6, **kwargs): - backend = StatusBackend(await_signals, privileged=privileged, ipv6=ipv6) - backend.init_status_backend() - backend.create_account_and_login(**kwargs) - backend.wait_for_login() - backend.find_public_key() - backend.wakuext_service.start_messenger() - return backend - - def send_contact_request_and_wait_for_signal_to_be_received(self): - response = self.sender.wakuext_service.send_contact_request(self.receiver.public_key, "contact_request") + def send_contact_request_and_wait_for_signal_to_be_received(self, sender=None, receiver=None) -> str: + """ + Send a contact request from sender to receiver and wait for confirmation. + + This function sends a contact request through the WakuExt service and waits + for the receiver to receive the MESSAGES_NEW signal containing the message ID. + This ensures the request has been delivered before proceeding with other operations. + + Args: + sender: StatusBackend instance of the sender (defaults to self.sender) + receiver: StatusBackend instance of the receiver (defaults to self.receiver) + + Returns: + str: The message ID of the sent contact request + + Raises: + AssertionError: If the message is not found or signal is not received + """ + response = sender.wakuext_service.send_contact_request(receiver.public_key, "contact_request") expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.CONTACT_REQUEST.value)[0] message_id = expected_message.get("id") - self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=message_id) + receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=message_id) return message_id - def accept_contact_request_and_wait_for_signal_to_be_received(self, message_id): - self.receiver.wakuext_service.accept_contact_request(message_id) - accepted_signal = f"@{self.receiver.public_key} accepted your contact request" - self.sender.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=accepted_signal) + def accept_contact_request_and_wait_for_signal_to_be_received(self, message_id, sender=None, receiver=None): + sender = sender or self.sender + receiver = receiver or self.receiver + receiver.wakuext_service.accept_contact_request(message_id) + accepted_signal = f"@{receiver.public_key} accepted your contact request" + sender.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=accepted_signal) - def make_contacts(self): - existing_contacts = self.receiver.wakuext_service.get_contacts() + def make_contacts(self, sender=None, receiver=None) -> str: + """ + Create a contact between sender and receiver. - if self.sender.public_key in str(existing_contacts): - return + This function sends a contact request from sender to receiver and waits for confirmation. + It also checks if the contact request has been accepted by the receiver. + + Args: + sender: StatusBackend instance of the sender (defaults to self.sender) + receiver: StatusBackend instance of the receiver (defaults to self.receiver) + + Returns: + str: The message ID of the sent contact request + """ + existing_contacts = receiver.wakuext_service.get_contacts() - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() - self.accept_contact_request_and_wait_for_signal_to_be_received(message_id) + if sender.public_key in str(existing_contacts): + return # type: ignore + + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(sender, receiver) + self.accept_contact_request_and_wait_for_signal_to_be_received(message_id, sender, receiver) return message_id def validate_signal_event_against_response(self, signal_event, fields_to_validate, expected_message): @@ -101,7 +112,7 @@ def get_message_by_content_type(self, response, content_type, message_pattern="" if matched_messages: return matched_messages else: - raise ValueError(f"Failed to find a message with contentType '{content_type}' in response") + raise ValueError(f"Failed to find a message with contentType '{content_type}' and message_pattern: `{message_pattern}` in response") def get_message_id(self, response, index=0): return response.get("result", {}).get("messages", [])[index].get("id", "") @@ -117,16 +128,17 @@ def get_message_by_message_id(self, response, message_id: str): raise ValueError(f"Failed to find a message with message id '{message_id}' in response") return matched_message - def join_private_group(self): + def join_private_group(self, admin=None, member=None) -> str: + private_group_name = f"private_group_{uuid4()}" - response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], private_group_name) - expected_group_creation_msg = f"@{self.sender.public_key} created the group {private_group_name}" + response = admin.wakuext_service.create_group_chat_with_members([member.public_key], private_group_name) + expected_group_creation_msg = f"@{admin.public_key} created the group {private_group_name}" expected_message = self.get_message_by_content_type( response, content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, message_pattern=expected_group_creation_msg, )[0] - self.receiver.find_signal_containing_pattern( + member.find_signal_containing_pattern( SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id"), timeout=60, @@ -144,9 +156,9 @@ def fetch_community(self, node, community_id=None): community_id = self.community_id return node.wakuext_service.fetch_community(community_id) - def join_community(self, node): - self.fetch_community(node) - response_to_join = node.wakuext_service.request_to_join_community(self.community_id) + def join_community(self, member=None, admin=None): + self.fetch_community(member) + response_to_join = member.wakuext_service.request_to_join_community(self.community_id) join_id = response_to_join.get("result", {}).get("requestsToJoinCommunity", [{}])[0].get("id") # I couldn't find any signal related to the requestToJoinCommunity request in the peer node. @@ -155,9 +167,11 @@ def join_community(self, node): retry_interval = 0.5 for attempt in range(max_retries): try: - response = self.sender.wakuext_service.accept_request_to_join_community(join_id) + response = admin.wakuext_service.accept_request_to_join_community(join_id) if response.get("result"): break + err = response.get("error") or "unknown error (no result and no error)" + raise Exception(err) except Exception as e: logging.error(f"Attempt {attempt + 1}/{max_retries}: Unexpected error: {e}") time.sleep(retry_interval) @@ -185,17 +199,17 @@ def check_node_joined_community(self, node, joined, community_id=None): response = self.fetch_community(node, community_id) assert response.get("result", {}).get("joined") is joined - def community_messages(self, message_chat_id, message_count): + def community_messages(self, message_chat_id, message_count, sender=None, receiver=None): sent_messages = [] for i in range(message_count): message_text = f"test_message_{i+1}_{uuid4()}" - response = self.sender.wakuext_service.send_chat_message(message_chat_id, message_text) + response = sender.wakuext_service.send_chat_message(message_chat_id, message_text) expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.TEXT_PLAIN.value)[0] sent_messages.append(expected_message) time.sleep(0.01) for i, expected_message in enumerate(sent_messages): - messages_new_event = self.receiver.find_signal_containing_pattern( + messages_new_event = receiver.find_signal_containing_pattern( SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id"), timeout=60, @@ -206,12 +220,12 @@ def community_messages(self, message_chat_id, message_count): expected_message=expected_message, ) - def one_to_one_message(self, message_count): - _, responses = self.send_multiple_one_to_one_messages(message_count) + def one_to_one_message(self, message_count, sender=None, receiver=None): + _, responses = self.send_multiple_one_to_one_messages(message_count, sender=sender, receiver=receiver) messages = list(map(lambda r: r.get("result", {}).get("messages", [])[0], responses)) for expected_message in messages: - messages_new_event = self.receiver.find_signal_containing_pattern( + messages_new_event = receiver.find_signal_containing_pattern( SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id"), timeout=60, @@ -224,23 +238,20 @@ def one_to_one_message(self, message_count): return responses - def send_multiple_one_to_one_messages(self, message_count=1) -> tuple[list[str], list[dict]]: + def send_multiple_one_to_one_messages(self, message_count=1, sender=None, receiver=None) -> tuple[list[str], list[dict]]: sent_texts = [] responses = [] for i in range(message_count): message_text = f"test_message_{i}_{uuid4()}" sent_texts.append(message_text) - response = self.sender.wakuext_service.send_one_to_one_message(self.receiver.public_key, message_text) + response = sender.wakuext_service.send_one_to_one_message(receiver.public_key, message_text) responses.append(response) return sent_texts, responses - def add_contact(self, execution_number, network_condition=None, privileged=True): + def add_contact(self, sender=None, receiver=None, execution_number=None, network_condition=None): message_text = f"test_contact_request_{execution_number}_{uuid4()}" - sender = self.initialize_backend(await_signals=self.await_signals, privileged=privileged) - receiver = self.initialize_backend(await_signals=self.await_signals, privileged=privileged) - existing_contacts = receiver.wakuext_service.get_contacts() if sender.public_key in str(existing_contacts): @@ -300,17 +311,17 @@ def create_private_group(self, private_groups_count): fields_to_validate={"text": "text"}, ) - def private_group_message(self, message_count, private_group_id): + def private_group_message(self, message_count, private_group_id, sender=None, receiver=None): sent_messages = [] for i in range(message_count): message_text = f"test_message_{i+1}_{uuid4()}" - response = self.sender.wakuext_service.send_group_chat_message(private_group_id, message_text) + response = sender.wakuext_service.send_group_chat_message(private_group_id, message_text) expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.TEXT_PLAIN.value)[0] sent_messages.append(expected_message) time.sleep(0.01) for _, expected_message in enumerate(sent_messages): - messages_new_event = self.receiver.find_signal_containing_pattern( + messages_new_event = receiver.find_signal_containing_pattern( SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id"), timeout=60, diff --git a/tests-functional/steps/network_conditions.py b/tests-functional/steps/network_conditions.py index bc2c6db95b..235b4fe2ec 100644 --- a/tests-functional/steps/network_conditions.py +++ b/tests-functional/steps/network_conditions.py @@ -7,7 +7,9 @@ class NetworkConditionsSteps: @contextmanager def add_latency(self, node, latency=300, jitter=50): logging.info("Entering context manager: add_latency") - node.container_exec(f"apk add iproute2 && tc qdisc add dev eth0 root netem delay {latency}ms {jitter}ms distribution normal") + node.container_exec( + f"apt-get update && apt-get install -y iproute2 && tc qdisc add dev eth0 root netem delay {latency}ms {jitter}ms distribution normal" + ) try: yield finally: @@ -17,7 +19,7 @@ def add_latency(self, node, latency=300, jitter=50): @contextmanager def add_packet_loss(self, node, packet_loss=2): logging.info("Entering context manager: add_packet_loss") - node.container_exec(f"apk add iproute2 && tc qdisc add dev eth0 root netem loss {packet_loss}%") + node.container_exec(f"apt-get update && apt-get install -y iproute2 && tc qdisc add dev eth0 root netem loss {packet_loss}%") try: yield finally: @@ -27,7 +29,9 @@ def add_packet_loss(self, node, packet_loss=2): @contextmanager def add_low_bandwith(self, node, rate="1mbit", burst="32kbit", limit="12500"): logging.info("Entering context manager: add_low_bandwith") - node.container_exec(f"apk add iproute2 && tc qdisc add dev eth0 root tbf rate {rate} burst {burst} limit {limit}") + node.container_exec( + f"apt-get update && apt-get install -y iproute2 && tc qdisc add dev eth0 root tbf rate {rate} burst {burst} limit {limit}" + ) try: yield finally: diff --git a/tests-functional/steps/status_backend.py b/tests-functional/steps/status_backend.py deleted file mode 100644 index 992ba730c2..0000000000 --- a/tests-functional/steps/status_backend.py +++ /dev/null @@ -1,28 +0,0 @@ -from clients.services.wallet import WalletService -from clients.signals import SignalType -from clients.status_backend import StatusBackend -from conftest import option -from resources.constants import ANVIL_NETWORK_ID - - -class StatusBackendSteps: - reuse_container = True # Skip close_status_backend_containers cleanup - await_signals = [SignalType.NODE_LOGIN.value] - - network_id = ANVIL_NETWORK_ID - - @classmethod - def setup_class(cls, skip_login=False): - cls.rpc_client = StatusBackend(await_signals=cls.await_signals) - cls.wallet_service = WalletService(cls.rpc_client) - cls.rpc_client.init_status_backend() - - if not skip_login: - cls.rpc_client.restore_account_and_login() - cls.rpc_client.wait_for_login() - - def teardown_class(self): - for status_backend in option.status_backend_containers: - status_backend.container.stop(timeout=10) - option.status_backend_containers.remove(status_backend) - status_backend.container.remove() diff --git a/tests-functional/steps/wallet.py b/tests-functional/steps/wallet.py deleted file mode 100644 index b356170f78..0000000000 --- a/tests-functional/steps/wallet.py +++ /dev/null @@ -1,58 +0,0 @@ -from clients.anvil import Anvil -from clients.smart_contract_runner import SmartContractRunner -from clients.contract_deployers.snt import SNTDeployer, SNTV2_ABI, SNT_TOKEN_CONTROLLER_ABI -from clients.contract_deployers.communities import CommunitiesDeployer -from resources.constants import DEPLOYER_ACCOUNT -from steps.status_backend import StatusBackendSteps -from web3 import Web3 - - -class WalletSteps(StatusBackendSteps): - """ - WalletSteps is a test utility class for managing wallet-related operations - in functional tests. All tests requiring Smart Contracts - deployment need to run in the same worker to avoid deployment conflicts, - which can cause failures. To achieve this, tests should be marked with - @pytest.mark.xdist_group(name="WalletSteps"). - """ - - erc20_token_list = {} - - @classmethod - def setup_class(cls, skip_login=False): - super().setup_class(skip_login=True) - - cls.anvil_client = Anvil() - cls.anvil_client.eth.default_account = Web3.to_checksum_address(DEPLOYER_ACCOUNT.address) - - cls.smart_contract_runner = SmartContractRunner() - cls.snt_deployer = SNTDeployer(cls.smart_contract_runner) - cls.communities_deployer = CommunitiesDeployer(cls.smart_contract_runner) - - cls.erc20_token_list["SNT"] = cls.snt_deployer.snt_contract_address - token_overrides = cls._token_list_to_token_overrides(cls.erc20_token_list) - cls.rpc_client.restore_account_and_login(token_overrides=token_overrides) - cls.rpc_client.wait_for_login() - - def get_snt_contract(self): - return self.anvil_client.eth.contract(address=self.snt_deployer.snt_contract_address, abi=SNTV2_ABI) - - def get_snt_token_controller(self): - return self.anvil_client.eth.contract(address=self.snt_deployer.snt_token_controller_address, abi=SNT_TOKEN_CONTROLLER_ABI) - - def mint_snt(self, address, amount): - snt_controller = self.get_snt_token_controller() - tx_hash = snt_controller.functions.generateTokens(address, amount).transact() - self.anvil_client.eth.wait_for_transaction_receipt(tx_hash) - - @classmethod - def _token_list_to_token_overrides(cls, token_list): - token_overrides = [] - for token_symbol, token_address in token_list.items(): - token_overrides.append( - { - "symbol": token_symbol, - "address": token_address, - } - ) - return token_overrides diff --git a/tests-functional/tests/benchmark/test_basic_benchmark.py b/tests-functional/tests/benchmark/test_basic_benchmark.py new file mode 100644 index 0000000000..8af1c4344f --- /dev/null +++ b/tests-functional/tests/benchmark/test_basic_benchmark.py @@ -0,0 +1,85 @@ +import pytest +import time + +from clients.signals import SignalType +from clients.status_backend import StatusBackend +from utils.config import Config +from steps.messenger import MessengerSteps + + +@pytest.mark.benchmark +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["waku_light_client_False", "waku_light_client_True"]) +class TestBasicBenchmark(MessengerSteps): + """Test StatusBackend performance. + + This test suite contains a few test cases that track CPU, RAM and network usage via Docker API. + """ + + await_signals = [ + SignalType.MESSAGES_NEW.value, + SignalType.MESSAGE_DELIVERED.value, + SignalType.NODE_LOGIN.value, + SignalType.NODE_LOGOUT.value, + ] + + @pytest.fixture(scope="function", autouse=False) + def aut(self, request, backend_factory, waku_light_client): + """Creates a AUT (Application Under Test) - a StatusBackend instance initialized for performance testing.""" + + # Create a new user + status_backend = backend_factory("AUT", pprof_enabled=True) + status_backend.start_performance_monitoring() + self.sleep(status_backend, 5) # Keep idle for a short time + + status_backend.init_status_backend() + status_backend.events.append("CreateAccountAndLogin") + status_backend.create_account_and_login(waku_light_client=waku_light_client) + status_backend.wait_for_login() + status_backend.events.append("Logged in") + status_backend.wakuext_service.start_messenger() + + yield status_backend + + status_backend.events.append("FreeOSMemory") + status_backend.free_os_memory() + time.sleep(20) + + # Finalize + test_name = request.node.name + filename = f"{Config.benchmark_results_dir}/{test_name}-{time.strftime('%Y%m%d-%H%M%S')}" + + metrics = status_backend.gather_metrics() + metrics.save_to_file(f"{filename}.json") + metrics.save_performance_chart(test_name, f"{filename}.png") + + def sleep(self, backend: StatusBackend, duration: int): + backend.events.append(f"Sleep for {duration} seconds") + time.sleep(duration) + + def test_idle(self, aut): + """Benchmark StatusBackend in idle state after creating a new profile""" + self.sleep(aut, 60) + + def test_one_to_one_messages(self, aut, backend_new_profile): + """Benchmark StatusBackend during receiving 1-1 messages.""" + + # Create a message sender + sender = backend_new_profile("sender") + self.make_contacts(sender, aut) + + messages_count = 200 + post_sleep_duration = 30 + + # Benchmark receiving many messages. + # Don't verify reception, because it might be 1-2 messages flaky at the moment. + aut.events.append(f"Send {messages_count} messages to AUT") + self.send_multiple_one_to_one_messages(messages_count, sender=sender, receiver=aut) + self.sleep(aut, post_sleep_duration) + + # Benchmark sending many messages + aut.events.append(f"Send {messages_count} messages from AUT") + self.send_multiple_one_to_one_messages(messages_count, sender=aut, receiver=sender) + self.sleep(aut, post_sleep_duration) + + # Extra sleep after the test + self.sleep(aut, 60) diff --git a/tests-functional/tests/conftest.py b/tests-functional/tests/conftest.py new file mode 100644 index 0000000000..afbed178df --- /dev/null +++ b/tests-functional/tests/conftest.py @@ -0,0 +1,165 @@ +import logging +import pytest + +from resources.constants import USE_IPV6 +from clients.status_backend import StatusBackend +from clients.statusgo_container import StatusGoContainer + + +@pytest.fixture(scope="function", autouse=False) +def backend_factory(request): + """ + Individual backend factory that creates backends one by one. + Each backend is created separately and all are cleaned up at the end. + + Usage: + @pytest.fixture(autouse=True) + def setup_backends(self, backend_factory): + self.sender = backend_factory("sender") + self.receiver = backend_factory("receiver") + + # Or with parameters: + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) + def test_with_params(self, backend_factory): + self.sender = backend_factory("sender") + self.receiver = backend_factory("receiver") + """ + + # Get class-level configuration + await_signals = getattr(request.cls, "await_signals", ["messages.new", "message.delivered", "node.login", "node.logout"]) + + # Get parameters from request.param if available + params = getattr(request, "param", {}) + + # Extract parameters with defaults + privileged = params.get("privileged", False) + ipv6 = params.get("ipv6", USE_IPV6) + + # Store created backends for cleanup + created_backends: list[StatusBackend] = [] + + def factory(name, **kwargs) -> StatusBackend: + """ + Create a single backend with the given name. + + Args: + name (str): Name for the backend (e.g., "sender", "receiver") + start_messenger (bool): Whether to start messenger service + + Returns: + StatusBackend: Created backend instance + """ + test_name = request.cls.__name__ if hasattr(request, "cls") else "test" + logging.debug(f"🔧 [SETUP] Creating {name} backend for {request.cls.__name__}") + logging.debug(f"🔧 [SETUP] Creating {name} backend for {test_name}") + logging.debug(f"📋 [SETUP] Parameters: privileged={privileged}, ipv6={ipv6}") + + # Create backend + backend = StatusBackend(await_signals=await_signals, privileged=privileged, ipv6=ipv6, **kwargs) + created_backends.append(backend) + logging.debug(f"✅ [SETUP] {name.capitalize()} backend created") + + return backend + + yield factory + + # Cleanup all created backends + logging.debug(f"🧹 [TEARDOWN] Cleaning up {len(created_backends)} backends for {request.cls.__name__ if hasattr(request, 'cls') else 'test'}") + + for i, backend in enumerate(reversed(created_backends)): + logging.debug(f"🧹 [TEARDOWN] Cleaning up backend {len(created_backends) - i}...") + backend.shutdown() + + +@pytest.fixture(scope="function", autouse=False) +def waku_light_client(request) -> bool: + return getattr(request, "param", False) + + +@pytest.fixture(scope="function", autouse=False) +def backend_new_profile(request, backend_factory): + backends: list[StatusBackend] = [] + + def _backend_new_profile(name: str, waku_light_client: bool = False, **kwargs) -> StatusBackend: + logging.debug(f"📋 [SETUP] backend_new_profile parameters: wakuV2LightClient={waku_light_client}") + backend = backend_factory(name, **kwargs) + backends.append(backend) + + backend.init_status_backend() + backend.create_account_and_login(waku_light_client=waku_light_client) + backend.wait_for_login() + backend.wakuext_service.start_messenger() + return backend + + yield _backend_new_profile + + for backend in backends: + backend.logout() + + +@pytest.fixture(scope="function", autouse=False) +def backend_recovered_profile(request, backend_factory): + backends: list[StatusBackend] = [] + + def _backend_recovered_profile(name: str, user: object, waku_light_client: bool = False, **kwargs) -> StatusBackend: + logging.debug(f"📋 [SETUP] backend_recovered_profile parameters: wakuV2LightClient={waku_light_client}") + backend = backend_factory(name, **kwargs) + backends.append(backend) + + backend.init_status_backend() + backend.restore_account_and_login(user=user, waku_light_client=waku_light_client, **kwargs) + backend.wait_for_login() + backend.wakuext_service.start_messenger() + return backend + + yield _backend_recovered_profile + + for backend in backends: + backend.logout() + + +@pytest.fixture(scope="function", autouse=False) +def close_status_backend_containers(request): + """ + Fixture to automatically cleanup Status backend containers after each test. + Should be used ONLY for tests that do not use backend_factory or class_backend fixtures. + + This fixture ensures that all Status backend containers are properly stopped, + logs are saved, and containers are removed to prevent resource leaks and + conflicts between tests. + + How it works: + 1. Yields immediately (runs before test execution) + 2. After test completes, stops all containers in StatusGoContainer.all_containers + 3. Saves logs from each container for debugging + 4. Removes containers to free up system resources + 5. Clears the containers list + + Usage: + # Automatic cleanup for all tests in a class + @pytest.fixture(autouse=True) + def setup_cleanup(self, close_status_backend_containers): + yield + + # Manual cleanup for specific test + def test_something(self, close_status_backend_containers): + # test code here + pass + + Parameters: + request: pytest request object containing test metadata + + Dependencies: + - StatusGoContainer.all_containers: Global list of active containers + - Container objects with stop(), save_logs(), remove() methods + + Scope: function (runs once per test function) + Autouse: False (must be explicitly requested) + """ + yield + for container in StatusGoContainer.all_containers: + try: + container.shutdown() # pyright: ignore[reportAttributeAccessIssue] + except Exception as e: + logging.error(f"Error cleaning up container: {e}") + StatusGoContainer.all_containers = [] diff --git a/tests-functional/tests/reliability/README.MD b/tests-functional/tests/reliability/README.MD new file mode 100644 index 0000000000..721f0a9380 --- /dev/null +++ b/tests-functional/tests/reliability/README.MD @@ -0,0 +1,53 @@ +# Reliability Test Suite + +This test suite, located under `tests-functional/tests/reliability`, is designed to evaluate the robustness and stability of the system under challenging network and runtime conditions. These tests go beyond typical functional checks and simulate real-world scenarios that stress the system's resilience. + +## 🧪 What We Test + +The suite includes tests that simulate: + +* **Adverse network conditions**: + + * High latency + * Packet loss + * Low bandwidth +* **Node lifecycle disruptions**: + + * Runtime IP address changes + * Node pause/unpause behavior +* **Network protocols**: + + * IPv4 and IPv6 coverage +* **System rate limiting**: + + * Testing throttling mechanisms under stress + +## 🚀 How to Run + +Running the reliability tests is nearly identical to running functional tests see [how-to-run guide](https://github.com/status-im/status-go/blob/develop/tests-functional/README.MD#how-to-run). +Example of running a test: + +```bash +pytest tests-functional/tests/reliability/ -k test_one_to_one_message_with_latency +``` + +Note! To run locally you need [`tc`](https://man7.org/linux/man-pages/man8/tc.8.html) (ex: wasn't able to run it on `windows` or `wsl`) on your host. + +## 🕒 CI Integration + +These tests are executed: + +* **Nightly** on a schedule +* **On demand**, via GitHub Actions + +Workflow link: [test-reliability.yml](https://github.com/status-im/status-go/actions/workflows/test-reliability.yml) + +Both **IPv4** and **IPv6** test runs are included in CI to ensure broad network compatibility. + +## 📊 Reporting + +Test results are available in the **GitHub Actions summary** of each run. For example: + +🔗 [Example run report](https://github.com/status-im/status-go/actions/runs/15748011404) + +While the reporting is currently minimal, it provides quick insight into which tests passed or failed, and under what conditions. diff --git a/tests-functional/tests/reliability/test_community_messages.py b/tests-functional/tests/reliability/test_community_messages.py index 179d78eca2..c9da7fa9c0 100644 --- a/tests-functional/tests/reliability/test_community_messages.py +++ b/tests-functional/tests/reliability/test_community_messages.py @@ -6,32 +6,40 @@ from resources.constants import USE_IPV6 -@pytest.mark.usefixtures("setup_two_privileged_nodes") @pytest.mark.reliability class TestCommunityMessages(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_community_messages_baseline(self, message_count=1, network_condition=None): self.create_community(self.sender) - message_chat_id = self.join_community(self.receiver) + message_chat_id = self.join_community(member=self.receiver, admin=self.sender) if network_condition: network_condition(self.receiver) - self.community_messages(message_chat_id, message_count) + self.community_messages(message_chat_id, message_count, sender=self.sender, receiver=self.receiver) def test_multiple_community_messages(self): self.test_community_messages_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_community_messages_with_latency(self): self.test_community_messages_baseline(network_condition=self.add_latency) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_community_messages_with_packet_loss(self): self.test_community_messages_baseline(network_condition=self.add_packet_loss) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_community_messages_with_low_bandwidth(self): self.test_community_messages_baseline(network_condition=self.add_low_bandwith) def test_community_messages_with_node_pause_30_seconds(self): self.create_community(self.sender) - message_chat_id = self.join_community(self.receiver) + message_chat_id = self.join_community(member=self.receiver, admin=self.sender) with self.node_pause(self.receiver): message_text = f"test_message_{uuid4()}" @@ -42,8 +50,8 @@ def test_community_messages_with_node_pause_30_seconds(self): @pytest.mark.skipif(USE_IPV6 == "Yes", reason="Test works only with IPV4") def test_community_messages_with_ip_change(self): self.create_community(self.sender) - message_chat_id = self.join_community(self.receiver) + message_chat_id = self.join_community(member=self.receiver, admin=self.sender) - self.community_messages(message_chat_id, 1) + self.community_messages(message_chat_id, 1, sender=self.sender, receiver=self.receiver) self.receiver.change_container_ip() - self.community_messages(message_chat_id, 1) + self.community_messages(message_chat_id, 1, sender=self.sender, receiver=self.receiver) diff --git a/tests-functional/tests/reliability/test_contact_request.py b/tests-functional/tests/reliability/test_contact_request.py index d5b925e3af..c5a23e4400 100644 --- a/tests-functional/tests/reliability/test_contact_request.py +++ b/tests-functional/tests/reliability/test_contact_request.py @@ -10,42 +10,46 @@ @pytest.mark.reliability class TestContactRequests(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_contact_request_baseline(self, execution_number=1, network_condition=None): - self.add_contact(execution_number, network_condition) + self.add_contact(sender=self.sender, receiver=self.receiver, execution_number=execution_number, network_condition=network_condition) @pytest.mark.parametrize("execution_number", range(10)) def test_multiple_contact_requests(self, execution_number): self.test_contact_request_baseline(execution_number=execution_number) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) @pytest.mark.parametrize("execution_number", range(10)) def test_contact_request_with_latency(self, execution_number): self.test_contact_request_baseline(execution_number=execution_number, network_condition=self.add_latency) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_contact_request_with_packet_loss(self): self.test_contact_request_baseline(execution_number=10, network_condition=self.add_packet_loss) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_contact_request_with_low_bandwidth(self): self.test_contact_request_baseline(execution_number=10, network_condition=self.add_low_bandwith) def test_contact_request_with_node_pause_30_seconds(self): - sender = self.initialize_backend(await_signals=self.await_signals) - receiver = self.initialize_backend(await_signals=self.await_signals) - - with self.node_pause(receiver): + with self.node_pause(self.receiver): message_text = f"test_contact_request_{uuid4()}" - response = sender.wakuext_service.send_contact_request(receiver.public_key, message_text) + response = self.sender.wakuext_service.send_contact_request(self.receiver.public_key, message_text) expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.CONTACT_REQUEST.value)[0] sleep(30) - receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id")) - sender.wait_for_signal(SignalType.MESSAGE_DELIVERED.value) + self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id")) + self.sender.wait_for_signal(SignalType.MESSAGE_DELIVERED.value) @pytest.mark.skipif(USE_IPV6 == "Yes", reason="Test works only with IPV4") def test_contact_request_with_ip_change(self): - sender = self.initialize_backend(await_signals=self.await_signals, privileged=True) - receiver = self.initialize_backend(await_signals=self.await_signals, privileged=True) - receiver.change_container_ip() + self.receiver.change_container_ip() message_text = f"test_contact_request_{uuid4()}" - response = sender.wakuext_service.send_contact_request(receiver.public_key, message_text) + response = self.sender.wakuext_service.send_contact_request(self.receiver.public_key, message_text) expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.CONTACT_REQUEST.value)[0] - receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id")) + self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id")) diff --git a/tests-functional/tests/reliability/test_create_private_groups.py b/tests-functional/tests/reliability/test_create_private_groups.py index d10cab4e78..9a6bfda0ae 100644 --- a/tests-functional/tests/reliability/test_create_private_groups.py +++ b/tests-functional/tests/reliability/test_create_private_groups.py @@ -6,19 +6,24 @@ from resources.constants import USE_IPV6 -@pytest.mark.usefixtures("setup_two_privileged_nodes") @pytest.mark.reliability class TestCreatePrivateGroups(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_create_private_group_baseline(self, private_groups_count=1): - self.make_contacts() + self.make_contacts(self.sender, self.receiver) self.create_private_group(private_groups_count) def test_multiple_create_private_groups(self): self.test_create_private_group_baseline(private_groups_count=50) def test_create_private_groups_with_node_pause_30_seconds(self): - self.make_contacts() + self.make_contacts(self.sender, self.receiver) with self.node_pause(self.receiver): private_group_name = f"private_group_{uuid4()}" @@ -28,7 +33,7 @@ def test_create_private_groups_with_node_pause_30_seconds(self): @pytest.mark.skipif(USE_IPV6 == "Yes", reason="Test works only with IPV4") def test_create_private_groups_with_ip_change(self): - self.make_contacts() + self.make_contacts(self.sender, self.receiver) self.receiver.change_container_ip() private_group_name = f"private_group_{uuid4()}" diff --git a/tests-functional/tests/reliability/test_join_leave_community.py b/tests-functional/tests/reliability/test_join_leave_community.py index 06f262475b..f640493f03 100644 --- a/tests-functional/tests/reliability/test_join_leave_community.py +++ b/tests-functional/tests/reliability/test_join_leave_community.py @@ -3,10 +3,15 @@ from steps.messenger import MessengerSteps -@pytest.mark.usefixtures("setup_two_privileged_nodes") @pytest.mark.reliability class TestJoinLeaveCommunities(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_join_leave_community_baseline(self, num_joins=1, network_condition=None): nodes_list = [self.sender, self.receiver] self.create_community(self.sender) @@ -17,27 +22,31 @@ def test_join_leave_community_baseline(self, num_joins=1, network_condition=None network_condition(node) for _ in range(num_joins): - for node in nodes_list: - self.join_community(node) - self.check_node_joined_community(node, joined=True) - self.leave_the_community(node) - self.check_node_joined_community(node, joined=False) + self.join_community(member=self.receiver, admin=self.sender) + self.check_node_joined_community(self.receiver, joined=True) + self.leave_the_community(self.receiver) + self.check_node_joined_community(self.receiver, joined=False) + @pytest.mark.skip(reason="Skipping due to failing on local build") + # TODO: check in nightly build locally and recheck test logic def test_multiple_join_leave_community_requests(self): self.test_join_leave_community_baseline(num_joins=10) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_join_leave_community_with_latency(self): self.test_join_leave_community_baseline(network_condition=self.add_latency) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_join_leave_community_with_packet_loss(self): self.test_join_leave_community_baseline(network_condition=self.add_packet_loss) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_join_leave_community_with_low_bandwidth(self): self.test_join_leave_community_baseline(network_condition=self.add_low_bandwith) def test_join_leave_community_with_node_pause(self): self.create_community(self.sender) - self.join_community(self.receiver) + self.join_community(member=self.receiver, admin=self.sender) self.check_node_joined_community(self.receiver, joined=True) with self.node_pause(self.receiver): @@ -47,7 +56,7 @@ def test_join_leave_community_with_node_pause(self): def test_join_leave_community_with_ip_change(self): self.create_community(self.sender) - self.join_community(self.receiver) + self.join_community(member=self.receiver, admin=self.sender) self.check_node_joined_community(self.receiver, joined=True) self.receiver.change_container_ip() diff --git a/tests-functional/tests/reliability/test_light_client_rate_limiting.py b/tests-functional/tests/reliability/test_light_client_rate_limiting.py index cdcd6f635e..e70cf18f64 100644 --- a/tests-functional/tests/reliability/test_light_client_rate_limiting.py +++ b/tests-functional/tests/reliability/test_light_client_rate_limiting.py @@ -10,9 +10,13 @@ @pytest.mark.reliability class TestLightClientRateLimiting(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two light client backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client=True) + self.receiver = backend_new_profile("receiver", waku_light_client=True) + def test_light_client_rate_limiting(self): - self.sender = self.initialize_backend(await_signals=self.await_signals, wakuV2LightClient=True) - self.receiver = self.initialize_backend(await_signals=self.await_signals, wakuV2LightClient=True) sent_messages = [] for i in range(200): diff --git a/tests-functional/tests/reliability/test_one_to_one_messages.py b/tests-functional/tests/reliability/test_one_to_one_messages.py index 662ee246e6..01a1aec946 100644 --- a/tests-functional/tests/reliability/test_one_to_one_messages.py +++ b/tests-functional/tests/reliability/test_one_to_one_messages.py @@ -6,24 +6,32 @@ from resources.constants import USE_IPV6 -@pytest.mark.usefixtures("setup_two_privileged_nodes") @pytest.mark.reliability class TestOneToOneMessages(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_one_to_one_message_baseline(self, message_count=1): - self.one_to_one_message(message_count) + self.one_to_one_message(message_count, sender=self.sender, receiver=self.receiver) def test_multiple_one_to_one_messages(self): self.test_one_to_one_message_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_one_to_one_message_with_latency(self): with self.add_latency(self.receiver): self.test_one_to_one_message_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_one_to_one_message_with_packet_loss(self): with self.add_packet_loss(self.receiver): self.test_one_to_one_message_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_one_to_one_message_with_low_bandwidth(self): with self.add_low_bandwith(self.receiver): self.test_one_to_one_message_baseline(message_count=50) diff --git a/tests-functional/tests/reliability/test_private_groups_messages.py b/tests-functional/tests/reliability/test_private_groups_messages.py index 076e13a5c3..a8fbef8801 100644 --- a/tests-functional/tests/reliability/test_private_groups_messages.py +++ b/tests-functional/tests/reliability/test_private_groups_messages.py @@ -6,33 +6,41 @@ from resources.constants import USE_IPV6 -@pytest.mark.usefixtures("setup_two_privileged_nodes") @pytest.mark.reliability class TestPrivateGroupMessages(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_private_group_messages_baseline(self, message_count=1): - self.make_contacts() - self.private_group_id = self.join_private_group() - self.private_group_message(message_count, self.private_group_id) + self.make_contacts(self.sender, self.receiver) + self.private_group_id = self.join_private_group(admin=self.sender, member=self.receiver) + self.private_group_message(message_count, self.private_group_id, sender=self.sender, receiver=self.receiver) def test_multiple_group_chat_messages(self): self.test_private_group_messages_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_private_group_chat_messages_with_latency(self): with self.add_latency(self.receiver): self.test_private_group_messages_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_private_group_chat_messages_with_packet_loss(self): with self.add_packet_loss(self.receiver): self.test_private_group_messages_baseline(message_count=50) + @pytest.mark.parametrize("backend_factory", [{"privileged": True}], indirect=True) def test_private_group_chat_messages_with_low_bandwidth(self): with self.add_low_bandwith(self.receiver): self.test_private_group_messages_baseline(message_count=50) def test_private_group_messages_with_node_pause_30_seconds(self): - self.make_contacts() - self.private_group_id = self.join_private_group() + self.make_contacts(self.sender, self.receiver) + self.private_group_id = self.join_private_group(admin=self.sender, member=self.receiver) with self.node_pause(self.receiver): message_text = f"test_message_{uuid4()}" @@ -43,8 +51,8 @@ def test_private_group_messages_with_node_pause_30_seconds(self): @pytest.mark.skipif(USE_IPV6 == "Yes", reason="Test works only with IPV4") def test_private_group_messages_with_ip_change(self): - self.make_contacts() - self.private_group_id = self.join_private_group() - self.private_group_message(1, self.private_group_id) + self.make_contacts(self.sender, self.receiver) + self.private_group_id = self.join_private_group(admin=self.sender, member=self.receiver) + self.private_group_message(1, self.private_group_id, sender=self.sender, receiver=self.receiver) self.receiver.change_container_ip() - self.private_group_message(1, self.private_group_id) + self.private_group_message(1, self.private_group_id, sender=self.sender, receiver=self.receiver) diff --git a/tests-functional/tests/test_accounts.py b/tests-functional/tests/test_accounts.py index 87db2be7e4..34b8f50836 100644 --- a/tests-functional/tests/test_accounts.py +++ b/tests-functional/tests/test_accounts.py @@ -1,14 +1,17 @@ +import os import random - import pytest - from resources.constants import user_1 -from steps.status_backend import StatusBackendSteps @pytest.mark.accounts @pytest.mark.rpc -class TestAccounts(StatusBackendSteps): +class TestAccounts: + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_new_profile): + """Initialize one backend for each test function""" + self.rpc_client = backend_new_profile("rpc_client") @pytest.mark.parametrize( "method, params", @@ -22,6 +25,28 @@ class TestAccounts(StatusBackendSteps): ) def test_(self, method, params): _id = str(random.randint(1, 8888)) + self.rpc_client.rpc_valid_request(method, params, _id) + # TODO: Add assertions on response + + def test_store_identity_image(self): + self.rpc_client.import_data( + os.path.abspath(os.path.join(os.path.dirname(__file__), "../resources/images/test-image-200x200.jpg")), "/tmp/images/" + ) + response = self.rpc_client.rpc_valid_request( + "multiaccounts_storeIdentityImage", [self.rpc_client.key_uid, "/tmp/images/test-image-200x200.jpg", 0, 0, 200, 200] + ) + + jsonResponse = response.json() + result = jsonResponse.get("result", {}) + assert result is not None, "Identity images were not stored (no result)" + assert len(result) == 2, "Identity images were not stored (wrong count)" + assert result[0]["localUrl"] is not None, "Local URL for identity image 1 is not set" + assert result[1]["localUrl"] is not None, "Local URL for identity image 2 is not set" - response = self.rpc_client.rpc_valid_request(method, params, _id) - self.rpc_client.verify_json_schema(response.json(), method) + response = self.rpc_client.rpc_valid_request("multiaccounts_getIdentityImages", [self.rpc_client.key_uid]) + jsonResponse = response.json() + result = jsonResponse.get("result", {}) + assert result is not None, "Identity images were not retrieved (no result)" + assert len(result) == 2, "Identity images were not retrieved (wrong count)" + assert result[0]["localUrl"] is not None, "Local URL for identity image 1 is not set" + assert result[1]["localUrl"] is not None, "Local URL for identity image 2 is not set" diff --git a/tests-functional/tests/test_activity_center_notifications.py b/tests-functional/tests/test_activity_center_notifications.py index 83cc288a7c..ab0f402ac4 100644 --- a/tests-functional/tests/test_activity_center_notifications.py +++ b/tests-functional/tests/test_activity_center_notifications.py @@ -15,14 +15,18 @@ def _get_activity_center_notifications( return backend_instance.wakuext_service.rpc_request(method="activityCenterNotifications", params=[params]).json() -@pytest.mark.usefixtures("setup_two_unprivileged_nodes") @pytest.mark.rpc class TestActivityCenterNotifications(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_activity_center_notifications(self): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = _get_activity_center_notifications(backend_instance=self.receiver, activity_types=[5], read_type=2) - self.receiver.verify_json_schema(response, method="wakuext_activityCenterNotifications") notification = response["result"]["notifications"][0] assert all( ( @@ -37,7 +41,6 @@ def test_activity_center_notifications(self): self.accept_contact_request_and_wait_for_signal_to_be_received(message_id) response = _get_activity_center_notifications(backend_instance=self.sender) - self.sender.verify_json_schema(response, method="wakuext_activityCenterNotifications") notification = response["result"]["notifications"][0] assert all( ( @@ -52,31 +55,31 @@ def test_activity_center_notifications(self): ) def test_activity_center_notifications_count(self): - self.send_contact_request_and_wait_for_signal_to_be_received() + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.rpc_request( method="activityCenterNotificationsCount", params=[{"activityTypes": [1, 2, 3, 4, 5, 7, 8, 9, 10, 23, 24], "readType": 2}] ).json() - self.receiver.verify_json_schema(response, method="wakuext_activityCenterNotificationsCount") assert response["result"]["5"] == 1 + # TODO: Add more assertions on response def test_seen_unseen_activity_center_notifications(self): - self.send_contact_request_and_wait_for_signal_to_be_received() + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.rpc_request(method="hasUnseenActivityCenterNotifications").json() - self.receiver.verify_json_schema(response, method="wakuext_hasUnseenActivityCenterNotifications") assert response["result"] is True + # TODO: Add more assertions on response response = self.receiver.wakuext_service.rpc_request(method="markAsSeenActivityCenterNotifications").json() - self.receiver.verify_json_schema(response, method="wakuext_markAsSeenActivityCenterNotifications") + # TODO: Add more assertions on response response = self.receiver.wakuext_service.rpc_request(method="hasUnseenActivityCenterNotifications").json() - self.receiver.verify_json_schema(response, method="wakuext_hasUnseenActivityCenterNotifications") assert response["result"] is False + # TODO: Add more assertions on response def test_get_activity_center_state(self): - self.send_contact_request_and_wait_for_signal_to_be_received() + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.rpc_request(method="getActivityCenterState").json() - self.receiver.verify_json_schema(response, method="wakuext_getActivityCenterState") assert response["result"]["hasSeen"] is False + # TODO: Add more assertions on response self.receiver.wakuext_service.rpc_request(method="markAsSeenActivityCenterNotifications").json() @@ -84,9 +87,8 @@ def test_get_activity_center_state(self): assert response["result"]["hasSeen"] is True def test_mark_all_activity_center_notifications_read(self): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.rpc_request(method="markAllActivityCenterNotificationsRead").json() - self.receiver.verify_json_schema(response, method="wakuext_markAllActivityCenterNotificationsRead") assert all( ( response["result"]["activityCenterState"]["hasSeen"] is True, @@ -99,7 +101,7 @@ def test_mark_all_activity_center_notifications_read(self): assert response["result"] is False def test_mark_activity_center_notifications_read_unread(self): - message_id = self.make_contacts() + message_id = self.make_contacts(self.sender, self.receiver) response = self.sender.wakuext_service.rpc_request( method="markActivityCenterNotificationsRead", params=[ @@ -108,7 +110,6 @@ def test_mark_activity_center_notifications_read_unread(self): ], ], ).json() - self.sender.verify_json_schema(response, method="wakuext_markActivityCenterNotificationsRead") assert all( ( response["result"]["activityCenterNotifications"][0]["id"] == message_id, @@ -127,7 +128,6 @@ def test_mark_activity_center_notifications_read_unread(self): ], ], ).json() - self.sender.verify_json_schema(response, method="wakuext_markActivityCenterNotificationsUnread") assert all( ( response["result"]["activityCenterState"]["hasSeen"] is False, @@ -140,8 +140,8 @@ def test_mark_activity_center_notifications_read_unread(self): assert result["notifications"][0]["read"] is False def test_accept_activity_center_notifications(self): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() - response = self.receiver.wakuext_service.rpc_request( + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) + self.receiver.wakuext_service.rpc_request( method="acceptActivityCenterNotifications", params=[ [ @@ -149,14 +149,14 @@ def test_accept_activity_center_notifications(self): ], ], ).json() - self.receiver.verify_json_schema(response, method="wakuext_acceptActivityCenterNotifications") + # TODO: Add assertions on response result = _get_activity_center_notifications(backend_instance=self.receiver)["result"] assert all((result["notifications"][0]["accepted"] is True, result["notifications"][0]["id"] == message_id)) def test_dismiss_activity_center_notifications(self): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() - response = self.receiver.wakuext_service.rpc_request( + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) + self.receiver.wakuext_service.rpc_request( method="dismissActivityCenterNotifications", params=[ [ @@ -164,16 +164,16 @@ def test_dismiss_activity_center_notifications(self): ], ], ).json() - self.receiver.verify_json_schema(response, method="wakuext_dismissActivityCenterNotifications") + # TODO: Add more assertions on response result = _get_activity_center_notifications(backend_instance=self.receiver)["result"] assert all((result["notifications"][0]["dismissed"] is True, result["notifications"][0]["id"] == message_id)) def test_delete_activity_center_notifications(self): - message_id = self.make_contacts() + message_id = self.make_contacts(self.sender, self.receiver) result = _get_activity_center_notifications(backend_instance=self.sender)["result"] assert len(result["notifications"]) == 1 - response = self.sender.wakuext_service.rpc_request( + self.sender.wakuext_service.rpc_request( method="deleteActivityCenterNotifications", params=[ [ @@ -181,6 +181,6 @@ def test_delete_activity_center_notifications(self): ], ], ).json() - self.sender.verify_json_schema(response, method="wakuext_deleteActivityCenterNotifications") + # TODO: Add more assertions on response result = _get_activity_center_notifications(backend_instance=self.sender)["result"] assert not result["notifications"] diff --git a/tests-functional/tests/test_add_account.py b/tests-functional/tests/test_add_account.py new file mode 100644 index 0000000000..7251860e61 --- /dev/null +++ b/tests-functional/tests/test_add_account.py @@ -0,0 +1,181 @@ +import copy +import pytest +from resources.constants import new_account_data_1, user_1 + + +@pytest.mark.rpc +class TestAddAccount: + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + self.account = backend_new_profile("sender") + self.account_data = copy.deepcopy(new_account_data_1) + + def test_add_second_wallet_account_to_profile_keypair(self): + # add account on path m/44'/60'/0'/0/1 to profile keypair + path = "m/44'/60'/0'/0/1" + derived_addresses_response = self.account.wallet_service.get_derived_addresses_for_mnemonic(self.account.mnemonic, [path]) + derived_addresses = derived_addresses_response.json()["result"] + + # update account being added with necessary details + self.account_data["key-uid"] = self.account.key_uid # keyuid of profile keypair + self.account_data["path"] = path + self.account_data["address"] = derived_addresses[0].get("address") + self.account_data["public-key"] = derived_addresses[0].get("public-key") + + self.account.accounts_service.add_account(self.account.password, self.account_data) + # TODO: Add more assertions on response + + # After adding the account check that the get accounts will retrieve the new account + accounts_response = self.account.accounts_service.get_accounts() + accounts = accounts_response.get("result", []) + self.check_new_account_was_created(accounts, self.account_data) + + def test_add_duplicate_account(self): + # since default wallet account is already added by creating the backend profile, we can try just adding the same account again + accounts_response = self.account.accounts_service.get_accounts() + assert len(accounts_response.get("result", [])) == 2 + defaultAccount = accounts_response.get("result", [])[0] + if not defaultAccount["wallet"]: + defaultAccount = accounts_response.get("result", [])[1] + assert defaultAccount["wallet"] is True + + # Add the same account second time + add_account_response = self.account.accounts_service.add_account(self.account.password, defaultAccount) + assert add_account_response.get("error", {}).get("message", "") == "account already exists" + + def test_add_new_keypair_via_seed_phrase(self): + keypair_name = "SeedImportedKeypair" + wallet_account_details = { + "name": "SeedImportedAccount", + "path": "m/44'/60'/0'/0/0", + "emoji": "🔑", + "colorId": "primary", + } + add_keypair_response = self.account.accounts_service.add_keypair_via_seed_phrase( + user_1.passphrase, self.account.password, keypair_name, wallet_account_details + ) + + keypairs = self.get_account_keypairs() + assert len(keypairs) == 2 + imported_keypair = keypairs[0] + if imported_keypair["name"] != keypair_name: + imported_keypair = keypairs[1] + assert imported_keypair["name"] == keypair_name + + assert imported_keypair["key-uid"] == add_keypair_response["result"]["key-uid"] + assert imported_keypair["type"] == "seed" + assert add_keypair_response["result"]["type"] == "seed" + assert add_keypair_response["result"]["key-uid"] == imported_keypair["key-uid"] + assert add_keypair_response["result"]["derived-from"] == imported_keypair["derived-from"] + assert len(add_keypair_response["result"]["accounts"]) == 1 + assert len(imported_keypair["accounts"]) == 1 + + def test_add_account_for_unknown_key_uid(self): + self.account_data["key-uid"] = "0x3231d92c94548d14f097173765a50bebe28fbad8f2267c9e08cc4433a6f219a4" + add_account_response = self.account.accounts_service.add_account(self.account.password, self.account_data) + assert add_account_response.get("error", {}).get("message", "") == "keypair is not found" + + def test_add_account_for_empty_address(self): + self.account_data["address"] = "" + add_account_response = self.account.accounts_service.add_account(self.account.password, self.account_data) + assert add_account_response.get("error", {}).get("message", "") == "invalid argument 1: hex string has length 0, want 40 for types.Address" + + def test_add_account_for_empty_path(self): + self.account_data["path"] = "" + add_account_response = self.account.accounts_service.add_account(self.account.password, self.account_data) + expected_error = "[account] account mismatch" + expected_error_context = "address: " + self.account_data["address"] + error_message = add_account_response.get("error", {}).get("message", "") + assert expected_error in error_message + assert expected_error_context.lower() in error_message.lower() + + @pytest.mark.parametrize("key", ["wallet", "chat"]) + def test_add_account_with_key_set_on_true__(self, key): + self.account_data["key-uid"] = self.account.key_uid + self.account_data[key] = True + add_account_response = self.account.accounts_service.add_account(self.account.password, self.account_data) + if key == "wallet": + assert add_account_response.get("error", {}).get("message", "") == "[database] cannot add default wallet account" + else: + assert add_account_response.get("error", {}).get("message", "") == "[database] cannot add default chat account" + + def test_add_watch_account(self): + self.account_data["type"] = "watch" + self.account.accounts_service.add_account(self.account.password, self.account_data) + # TODO: Add more assertions on response + + # After adding the account check that the get accounts will retrieve the new account + accounts_response = self.account.accounts_service.get_accounts() + accounts = accounts_response.get("result", []) + self.check_new_account_was_created(accounts, self.account_data) + + def test_add_account_to_seed_imported_keypair(self): + used_mnemonic = user_1.passphrase + profile_password = self.account.password + + keypair_name = "SeedImportedKeypair" + wallet_account_details = { + "name": "SeedImportedAccount", + "path": "m/44'/60'/0'/0/0", + "emoji": "🔑", + "colorId": "primary", + } + add_keypair_response = self.account.accounts_service.add_keypair_via_seed_phrase( + used_mnemonic, profile_password, keypair_name, wallet_account_details + ) + + path = "m/44'/60'/0'/0/1" + derived_addresses_response = self.account.wallet_service.get_derived_addresses_for_mnemonic(used_mnemonic, [path]) + derived_addresses = derived_addresses_response.json()["result"] + + # update account being added with necessary details + self.account_data["key-uid"] = add_keypair_response["result"]["key-uid"] + self.account_data["path"] = path + self.account_data["address"] = derived_addresses[0].get("address") + self.account_data["public-key"] = derived_addresses[0].get("public-key") + + self.account.accounts_service.add_account(profile_password, self.account_data) + # TODO: Add more assertions on response + + def test_delete_account(self): + self.account_data["type"] = "watch" + self.account.accounts_service.add_account(self.account.password, self.account_data) + # TODO: Add more assertions on response + + accounts_response = self.account.accounts_service.get_accounts() + assert len(accounts_response.get("result", [])) == 3 + + # Delete the account + self.account.accounts_service.delete_account(self.account_data["address"]) + # TODO: Add more assertions on response + + accounts_response = self.account.accounts_service.get_accounts() + assert len(accounts_response.get("result", [])) == 2 + + def get_account_keypairs(self): + keypairs_response = self.account.accounts_service.get_account_keypairs() + keypairs = keypairs_response.get("result", []) + assert len(keypairs) > 0 + return keypairs + + def check_new_account_was_created(self, accounts, account_data): + mismatch_details = "" + for acc in accounts: + mismatches = [] + for key, value in account_data.items(): + if key not in acc: + mismatches.append(f"Missing key: {key}") + continue + actual_value = acc[key] + if key == "address" and value.lower() == actual_value.lower(): + continue + if value == actual_value: + continue + mismatches.append(f"Mismatch in key '{key}': expected '{value}', got '{actual_value}'") + if not mismatches: + break + else: + mismatch_details = "\\n".join(mismatches) + else: + assert False, f"Added account not found or mismatched in accounts list. Details:\\n{mismatch_details}" diff --git a/tests-functional/tests/test_app_general.py b/tests-functional/tests/test_app_general.py index 9c1109ba70..23599d777d 100644 --- a/tests-functional/tests/test_app_general.py +++ b/tests-functional/tests/test_app_general.py @@ -1,13 +1,15 @@ import random - import pytest -from steps.status_backend import StatusBackendSteps - @pytest.mark.accounts @pytest.mark.rpc -class TestAppGeneral(StatusBackendSteps): +class TestAppGeneral: + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_new_profile): + """Initialize one backend for each test function""" + self.rpc_client = backend_new_profile("rpc_client") @pytest.mark.parametrize( "method, params", @@ -18,5 +20,5 @@ class TestAppGeneral(StatusBackendSteps): def test_(self, method, params): _id = str(random.randint(1, 8888)) - response = self.rpc_client.rpc_valid_request(method, params, _id) - self.rpc_client.verify_json_schema(response.json(), method) + self.rpc_client.rpc_valid_request(method, params, _id) + # TODO: Add more assertions on response diff --git a/tests-functional/tests/test_backup_mnemonic_and_restore.py b/tests-functional/tests/test_backup_mnemonic_and_restore.py new file mode 100644 index 0000000000..b6c60b4b33 --- /dev/null +++ b/tests-functional/tests/test_backup_mnemonic_and_restore.py @@ -0,0 +1,179 @@ +import random +import string +import copy +from clients.status_backend import StatusBackend +from clients.signals import SignalType +import pytest + +from resources.constants import user_mnemonic_12, user_mnemonic_15, user_mnemonic_24, user_keycard_1 +from resources.utils import assert_response_attributes + + +@pytest.mark.create_account +@pytest.mark.rpc +class TestBackupMnemonicAndRestore: + + await_signals = [ + SignalType.MEDIASERVER_STARTED.value, + SignalType.NODE_STARTED.value, + SignalType.NODE_READY.value, + SignalType.NODE_LOGIN.value, + SignalType.NODE_LOGOUT.value, + ] + + @pytest.fixture(autouse=True) + def setup_cleanup(self, close_status_backend_containers): + """Automatically cleanup containers after each test""" + yield + + def test_profile_creation_and_mnemonics_backup(self): + # Create a new account container and initialize + account = StatusBackend(self.await_signals) + account.init_status_backend() + account.create_account_and_login() + account.wait_for_login() + + # Retrieve and verify the mnemonic + settings = account.settings_service.get_settings() + mnemonic = settings.get("result", {}).get("mnemonic", None) + assert mnemonic is not None + assert isinstance(mnemonic, str) + assert len(mnemonic.split()) == 12 # Basic check for mnemonic length + + def test_backup_account_and_restore_it_via_mnemonics(self): + # Create original account and backup mnemonic + original_account = StatusBackend(self.await_signals) + original_account.init_status_backend() + original_account.create_account_and_login() + original_account.wait_for_login() + original_get_settings_response = original_account.settings_service.get_settings() + original_settings = original_get_settings_response.get("result", {}) + mnemonic = original_settings.get("mnemonic", None) + assert mnemonic is not None + + user = copy.deepcopy(user_mnemonic_12) + user.passphrase = mnemonic + + # Restore account in a new container + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account.restore_account_and_login(user=user) + restored_account.wait_for_login() + + # Verify mnemonic is not exposed after restore + restored_get_settings_response = restored_account.settings_service.get_settings() + restored_settings = restored_get_settings_response.get("result", {}) + assert restored_settings.get("mnemonic", None) is None + + # Verify keys in the restored respone match the original respones + for key in [ + "address", + "compressedKey", + "current-user-status", + "dapps-address", + "eip1581-address", + "emojiHash", + "name", + "public-key", + "wallet-root-address", + ]: + assert original_settings.get(key) == restored_settings.get(key), f"Restored {key} doesn't match with original" + + # But some are different as expected + assert original_settings.get("installation-id") != restored_settings.get("installation-id"), "installation-id shouldn't match" + + @pytest.mark.parametrize( + "user_mnemonic", + [user_mnemonic_24, user_mnemonic_15, user_mnemonic_12], + ids=["mnemonic_24", "mnemonic_15", "mnemonic_12"], + ) + def test_restore_app_different_valid_size_mnemonics(self, user_mnemonic): + # Initialize backend client and restore account using user_mnemonic. + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account.restore_account_and_login(user=user_mnemonic) + restored_account.wait_for_login() + + # Request getAccounts and check restoreed accounts attributes. + get_accounts_response = restored_account.accounts_service.get_accounts() + assert_response_attributes(get_accounts_response.get("result", {}), user_mnemonic.accounts) + + # Request getSettings and check restoreed profile data attributes. + get_settings_response = restored_account.settings_service.get_settings() + restored_settings = get_settings_response.get("result", {}) + assert_response_attributes(restored_settings, user_mnemonic.profile_data) + + assert restored_settings.get("mnemonic", None) is None + assert restored_settings.get("address", None) + + @pytest.mark.parametrize( + "mnemonic_size", + [1, 3, 7, 13, 29], + ) + def test_restore_with_arbitrary_size_mnemonics(self, mnemonic_size): + # Restore with an arbitrary length mnemonic + user = user_mnemonic_12 + user.passphrase = " ".join("".join(random.choice(string.ascii_lowercase) for _ in range(random.randint(2, 10))) for _ in range(mnemonic_size)) + + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account.restore_account_and_login(user=user) + restored_account.wait_for_login() + + get_settings_response = restored_account.settings_service.get_settings() + restored_settings = get_settings_response.get("result", {}) + assert restored_settings.get("mnemonic", None) is None + assert restored_settings.get("address", None) + + def test_restore_with_mnemonic_with_special_chars(self): + # Restore with an mnemonic with special chars + user = user_mnemonic_12 + user.passphrase = "<>?`~!@#$%^&*()_+1 $fgdg ^&*()" + + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account.restore_account_and_login(user=user) + restored_account.wait_for_login() + get_settings_response = restored_account.settings_service.get_settings() + restored_settings = get_settings_response.get("result", {}) + assert restored_settings.get("mnemonic", None) is None + assert restored_settings.get("address", None) + + def test_restore_with_empty_mnemonic(self): + # Restore with empty mnemonic isn't allowed + user = user_mnemonic_12 + + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account._set_display_name() + data = restored_account._create_account_request(user) + data["mnemonic"] = "" + restored_account_response = restored_account.api_request("RestoreAccountAndLogin", data) + assert restored_account_response.json().get("error") == "restore-account: mnemonic is not set" + + def test_restore_with_both_mnemonic_and_keycard(self): + # Restore with both keycard and mnemonic isn't allowed + user = user_mnemonic_12 + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account._set_display_name() + data = restored_account._create_account_request(user) + data["mnemonic"] = user.passphrase + data["keycard"] = user_keycard_1 + restored_account_response = restored_account.api_request("RestoreAccountAndLogin", data) + assert restored_account_response.json().get("error") == "restore-account: mnemonic is set for keycard account" + + def test_restored_on_existing_restored_account_fails(self): + user = user_mnemonic_12 + restored_account = StatusBackend(self.await_signals) + restored_account.init_status_backend() + restored_account.restore_account_and_login(user=user) + restored_account.wait_for_login() + restored_account.restore_account_and_login(user=user) + signal = restored_account.wait_for_signal(SignalType.NODE_LOGIN.value) + + assert user.profile_data is not None, "User profile_data should not be None" + key_uid = user.profile_data.get("key-uid", "") + expected_error = f"[validation] keypair already added - keyuid: {key_uid}" + + assert expected_error in signal.get("event").get("error") diff --git a/tests-functional/tests/test_eth_api.py b/tests-functional/tests/test_eth_api.py index 9a378d24ca..ccfb46a6c4 100644 --- a/tests-functional/tests/test_eth_api.py +++ b/tests-functional/tests/test_eth_api.py @@ -1,6 +1,11 @@ import pytest +from collections import namedtuple -from steps.eth_rpc import EthRpcSteps +from clients.anvil import Anvil +from clients.signals import SignalType +from resources.constants import user_1, user_2 +from uuid import uuid4 +from utils import wallet_utils def validate_header(header, block_number, block_hash): @@ -18,58 +23,46 @@ def validate_transaction(tx, tx_hash): assert tx["tx"]["hash"] == tx_hash -def validate_receipt(receipt, tx_hash, block_number, block_hash): - assert receipt["transactionHash"] == tx_hash - assert receipt["blockNumber"] == block_number - assert receipt["blockHash"] == block_hash - - @pytest.mark.rpc @pytest.mark.ethclient @pytest.mark.xdist_group(name="Eth") -class TestEth(EthRpcSteps): - - def test_block_number(self): - self.rpc_client.rpc_valid_request("ethclient_blockNumber", [self.network_id]) - - def test_suggest_gas_price(self): - self.rpc_client.rpc_valid_request("ethclient_suggestGasPrice", [self.network_id]) - - def test_header_by_number(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_headerByNumber", [self.network_id, tx_data.block_number]) - validate_header(response.json()["result"], tx_data.block_number, tx_data.block_hash) - - def test_block_by_number(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_blockByNumber", [self.network_id, tx_data.block_number]) - validate_block( - response.json()["result"], - tx_data.block_number, - tx_data.block_hash, - tx_data.tx_hash, - ) - - def test_header_by_hash(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_headerByHash", [self.network_id, tx_data.block_hash]) - validate_header(response.json()["result"], tx_data.block_number, tx_data.block_hash) - - def test_block_by_hash(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_blockByHash", [self.network_id, tx_data.block_hash]) - validate_block( - response.json()["result"], - tx_data.block_number, - tx_data.block_hash, - tx_data.tx_hash, - ) - - def test_transaction_by_hash(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_transactionByHash", [self.network_id, tx_data.tx_hash]) - validate_transaction(response.json()["result"], tx_data.tx_hash) - - def test_transaction_receipt(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_transactionReceipt", [self.network_id, tx_data.tx_hash]) - validate_receipt( - response.json()["result"], - tx_data.tx_hash, - tx_data.block_number, - tx_data.block_hash, - ) +class TestEth: + await_signals = [ + SignalType.NODE_LOGIN.value, + SignalType.WALLET.value, + SignalType.WALLET_SUGGESTED_ROUTES.value, + SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value, + SignalType.WALLET_ROUTER_SENDING_TRANSACTIONS_STARTED.value, + SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value, + ] + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_recovered_profile): + self.rpc_client = backend_recovered_profile(name="rpc_client", user=user_1) + """Create a transaction and assign tx_data to self.""" + uuid = str(uuid4()) + input_params = { + "uuid": uuid, + "sendType": 0, + "addrFrom": user_1.address, + "addrTo": user_2.address, + "amountIn": "0xde0b6b3a7640000", + "amountOut": "0x0", + "tokenID": "ETH", + "tokenIDIsOwnerToken": False, + "toTokenID": "", + "fromChainID": 31337, + "toChainID": 31337, + "gasFeeMode": 1, + "slippagePercentage": 0, + } + tx_data = wallet_utils.send_router_transaction(self.rpc_client, **input_params) + tx_hash = tx_data["tx_status"]["hash"] + anvil = Anvil() + + anvil.eth.wait_for_transaction_receipt(tx_hash) + receipt = anvil.transaction_receipt(tx_hash) + block_number = receipt["blockNumber"] + block_hash = receipt["blockHash"] + TxData = namedtuple("TxData", ["tx_hash", "block_number", "block_hash"]) + self.tx_data = TxData(tx_hash, block_number, block_hash) diff --git a/tests-functional/tests/test_init_status_app.py b/tests-functional/tests/test_init_status_app.py index a9b2e0adf6..2bdeea32de 100644 --- a/tests-functional/tests/test_init_status_app.py +++ b/tests-functional/tests/test_init_status_app.py @@ -8,6 +8,11 @@ @pytest.mark.rpc class TestInitialiseApp: + @pytest.fixture(autouse=True) + def setup_cleanup(self, close_status_backend_containers): + """Automatically cleanup containers after each test""" + yield + @pytest.mark.init def test_init_app(self): @@ -23,22 +28,6 @@ def test_init_app(self): backend_client.restore_account_and_login() assert backend_client is not None - backend_client.verify_json_schema( - backend_client.wait_for_login(), - "signal_node_login", - ) - backend_client.verify_json_schema( - backend_client.wait_for_signal(SignalType.MEDIASERVER_STARTED.value), - "signal_mediaserver_started", - ) - backend_client.verify_json_schema( - backend_client.wait_for_signal(SignalType.NODE_STARTED.value), - "signal_node_started", - ) - backend_client.verify_json_schema( - backend_client.wait_for_signal(SignalType.NODE_READY.value), - "signal_node_ready", - ) def assert_file_first_line(path, pattern: str, expected: bool): @@ -55,7 +44,7 @@ def assert_file_first_line(path, pattern: str, expected: bool): @pytest.mark.rpc @pytest.mark.init @pytest.mark.parametrize("log_enabled,api_logging_enabled", [(False, False), (True, True)]) -def test_check_logs(log_enabled: bool, api_logging_enabled: bool): +def test_check_logs(log_enabled: bool, api_logging_enabled: bool, close_status_backend_containers): backend = StatusBackend() data_dir = os.path.join(backend.data_dir, "data") diff --git a/tests-functional/tests/test_local_backup.py b/tests-functional/tests/test_local_backup.py new file mode 100644 index 0000000000..6eadc82721 --- /dev/null +++ b/tests-functional/tests/test_local_backup.py @@ -0,0 +1,466 @@ +import os +from clients.status_backend import StatusBackend +import pytest +from resources.constants import Account, user_1 +from resources.test_data import profile_showcase_utils + + +test_one_to_one_chat_id = ( + "0x043329fc08727f15c4ec9a17bf7d6a3dc44e9d0d8f782a55804f3660b28827194a365dc1765cf96b6fa5cd666b9ee5298e8ac82f51f7952c4110cbf321d4f63864" +) + + +@pytest.mark.rpc +class TestLocalBackup: + + @pytest.mark.init + def test_local_backup(self, tmp_path): + await_signals = [ + "mediaserver.started", + "node.started", + "node.ready", + "node.login", + ] + + backend_client = StatusBackend(await_signals) + assert backend_client is not None + + # Init and login + backend_client.init_status_backend() + backend_client.create_account_and_login() + backend_client.wait_for_login() + backend_client.wakuext_service.start_messenger() + + assert backend_client.mnemonic != "" + + user_mnemonic = backend_client.mnemonic + + # Change settings + backend_client.rpc_valid_request("wakuext_setDisplayName", ["myname"]) + + # Move image to the container and apply it to the first backend client + backend_client.import_data( + os.path.abspath(os.path.join(os.path.dirname(__file__), "../resources/images/test-image-200x200.jpg")), "/tmp/images/" + ) + backend_client.rpc_valid_request( + "multiaccounts_storeIdentityImage", [backend_client.key_uid, "/tmp/images/test-image-200x200.jpg", 0, 0, 200, 200] + ) + + backend_client.rpc_valid_request("settings_saveSetting", ["bio", "new bio"]) + backend_client.rpc_valid_request("settings_saveSetting", ["preferred-name", "new-prefered-name"]) + backend_client.rpc_valid_request("settings_saveSetting", ["url-unfurling-mode", 2]) + backend_client.rpc_valid_request("settings_saveSetting", ["messages-from-contacts-only", True]) + backend_client.rpc_valid_request("settings_saveSetting", ["currency", "eth"]) + backend_client.rpc_valid_request("settings_saveSetting", ["mnemonic", ""]) # Clear mnemonic setting + + profile_showcase_preferences = profile_showcase_utils.dummy_profile_showcase_preferences(False) + backend_client.rpc_valid_request("wakuext_setProfileShowcasePreferences", [profile_showcase_preferences]) + + # Add watchonly account + backend_client.rpc_valid_request( + "accounts_addAccount", + [ + "", + { + "address": "0xE04DC5f84918F567E9Fc8D0c38B26E3A7D013f7b", + "key-uid": "", + "wallet": False, + "chat": False, # this refers to Status chat account, set when the Status account is created, cannot be changed later + "type": "watch", + "path": "", + "public-key": "", + "name": "test-watchonly-account", + "emoji": "🕵️", + "colorId": "green", + "hidden": True, + }, + ], + ) + + # Add contacts + backend_client.rpc_valid_request( + "wakuext_sendContactRequest", + [ + { + "id": "zQ3shnZxb3McGZqKgKYBioaRUzJACqoes1m2ivYPBRAWEnVR2", + "message": "Test message", + } + ], + ) + backend_client.rpc_valid_request( + "wakuext_sendContactRequest", + [ + { + "id": "zQ3shVMbHwBhLapryZRYhJh6Temcpd3sqZH2X8zXkCsoHjFjK", + "message": "Test message", + } + ], + ) + + # Create a community + backend_client.rpc_valid_request( + "wakuext_createCommunity", + [ + { + "name": "Test Community", + "description": "This is a test community", + "image": "", + "imageAx": 0, + "imageAy": 0, + "imageBx": 0, + "imageBy": 0, + "Membership": 1, + "introMessage": "Welcome to the test community!", + "outroMessage": "Thank you for joining the test community!", + "ensOnly": False, + "color": "#00FF00", + "tags": [], + "historyArchiveSupportEnabled": False, + "pinMessageAllMembersEnabled": False, + } + ], + ) + + # Create another community + response = backend_client.rpc_valid_request( + "wakuext_createCommunity", + [ + { + "name": "Test Community 2", + "description": "This is another test community", + "image": "", + "imageAx": 0, + "imageAy": 0, + "imageBx": 0, + "imageBy": 0, + "Membership": 1, + "introMessage": "Welcome to the second test community!", + "outroMessage": "Thank you for joining the second test community!", + "ensOnly": False, + "color": "#FF0000", + "tags": [], + "historyArchiveSupportEnabled": False, + "pinMessageAllMembersEnabled": False, + } + ], + ) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Community creation failed" + communities = result.get("communities", []) + assert communities is not None, "Community was not created (None)" + assert len(communities) == 1, "Community was not created (empty)" + community_id = communities[0].get("id", "") + assert community_id != "", "Community ID was not returned" + + # Leave community + backend_client.rpc_valid_request("wakuext_leaveCommunity", [community_id]) + + # Create chats + response = backend_client.rpc_valid_request("wakuext_createGroupChatWithMembers", [None, "test-group-chat", []]) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Group chat creation failed" + chats = result.get("chats", []) + assert chats is not None, "Group chat was not created (None)" + assert len(chats) == 1, "Group chat was not created (empty)" + group_chat_id = chats[0].get("id", "") + assert group_chat_id != "", "Group chat ID was not returned" + + backend_client.rpc_valid_request( + "wakuext_createOneToOneChat", + [{"id": test_one_to_one_chat_id}], + ) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "One-to-one chat creation failed" + chats = result.get("chats", []) + assert chats is not None, "One-to-one chat was not created (None)" + assert len(chats) == 1, "One-to-one chat was not created (empty)" + + # Validate settings on the first backend client + response = backend_client.rpc_valid_request("settings_getSettings", []) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Settings were not set" + assert result.get("display-name") == "myname", "Display name setting was not set" + assert result.get("bio") == "new bio", "Bio setting was not set" + assert result.get("preferred-name") == "new-prefered-name", "Preferred name setting was not set" + assert result.get("url-unfurling-mode") == 2, "URL unfurling mode setting was not set" + assert result.get("messages-from-contacts-only") is True, "Messages from contacts only setting was not set" + assert result.get("currency") == "eth", "Currency setting was not set" + assert result.get("mnemonic-removed?") is True, "Mnemonic setting was not set" + + # Validate profile showcase preferences + response = backend_client.rpc_valid_request("wakuext_getProfileShowcasePreferences", []) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Profile showcase preferences were not set" + assert result.get("clock") > 0, "Clock is 0 in the profile showcase preferences" + profile_showcase_preferences["clock"] = result.get("clock") # override clock for simpler comparison + assert result == profile_showcase_preferences, "Profile showcase preferences were not set correctly" + + # Validate watchonly account + response = backend_client.rpc_valid_request("accounts_getAccounts", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Accounts were not restored" + assert len(result) == 3, "Watchonly account was not restored" + assert result[2].get("name") == "test-watchonly-account", "Watchonly account name was not set correctly" + assert result[2].get("emoji") == "🕵️", "Watchonly account emoji was not set correctly" + assert result[2].get("type") == "watch", "Watchonly account type was not set correctly" + + # Validate contacts + response = backend_client.rpc_valid_request("wakuext_contacts", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Contacts were not restored" + assert len(result) == 2, "Contacts were not restored" + + # Validate communities + response = backend_client.rpc_valid_request("wakuext_communities", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Communities were not restored" + assert len(result) == 2, "Communities were not restored correctly" + assert result[0].get("name") == "Test Community", "Community name was not restored correctly" + assert result[0].get("description") == "This is a test community", "Community description was not restored correctly" + assert result[1].get("name") == "Test Community 2", "Second community name was not restored correctly" + assert result[1].get("description") == "This is another test community", "Second community description was not restored correctly" + assert not result[1].get("joined"), "Second community was not left correctly" + + # Validate chats + response = backend_client.rpc_valid_request("wakuext_chats", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Chats were not restored" + group_chat_recovered = False + one_on_one_chat_recovered = False + for chat in result: + if chat.get("id") == group_chat_id: + assert chat.get("name") == "test-group-chat", "Group chat name was not restored correctly" + group_chat_recovered = True + elif chat.get("id") == test_one_to_one_chat_id: + one_on_one_chat_recovered = True + + assert group_chat_recovered, "Group chat was not restored correctly" + assert one_on_one_chat_recovered, "One-to-one chat was not restored correctly" + + # Perform the backup + response = backend_client.api_valid_request("PerformLocalBackup", "") + jsonResponse = response.json() + backup_path = jsonResponse.get("filePath", "") + + # Extract the backup file from the container + backup_file = backend_client.extract_data(backup_path) + assert backup_file is not None + + # Create a new installation + backend_client2 = StatusBackend(await_signals) + assert backend_client2 is not None + + # Init and login + backend_client2.init_status_backend() + backend_client2.restore_account_and_login( + user=Account( + passphrase=user_mnemonic, + password=backend_client.password, + # The private key and address are not needed for mnemonic recovery + private_key="", + address="", + ) + ) + backend_client2.wait_for_login() + backend_client2.wakuext_service.start_messenger() + + # Import the backup file into the new container + backend_client2.import_data(backup_file, "/usr/status-user/backups") + + # Import the backup file + response = backend_client2.api_valid_request("LoadLocalBackup", {"filePath": backup_path}) + + # Validate profile settings + response = backend_client2.rpc_valid_request("multiaccounts_getIdentityImages", [backend_client2.key_uid]) + jsonResponse = response.json() + result = jsonResponse.get("result", {}) + assert result is not None, "Identity images were not restored" + assert len(result) == 2, "Identity image was not restored" + + # Validate settings + response = backend_client2.rpc_valid_request("settings_getSettings", []) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Settings were not restored" + # FIXME display name doesn't work because we set the display name when creating the account + # and the clock is somehow too low, so the display name is not updated + # assert result.get("display-name") == "myname", "Display name setting was not restored" + assert result.get("bio") == "new bio", "Bio setting was not restored" + assert result.get("preferred-name") == "new-prefered-name", "Preferred name setting was not restored" + assert result.get("url-unfurling-mode") == 2, "URL unfurling mode setting was not restored" + assert result.get("messages-from-contacts-only") is True, "Messages from contacts only setting was not restored" + assert result.get("currency") == "eth", "Currency setting was not restored" + assert result.get("mnemonic-removed?") is True, "Mnemonic setting was not restored" + + # Validate profile showcase preferences + response = backend_client2.rpc_valid_request("wakuext_getProfileShowcasePreferences", []) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Profile showcase preferences were not restored" + assert result.get("clock") > 0, "Clock is 0 in the restored profile showcase preferences" + profile_showcase_preferences["clock"] = result.get("clock") # override clock for simpler comparison + assert result == profile_showcase_preferences, "Profile showcase preferences were not restored correctly" + + # Validate watchonly account + response = backend_client2.rpc_valid_request("accounts_getAccounts", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Accounts were not restored" + assert len(result) == 3, "Watchonly account was not restored" + assert result[2].get("name") == "test-watchonly-account", "Watch only account name was not restored correctly" + assert result[2].get("emoji") == "🕵️", "Watch only account emoji was not restored correctly" + assert result[2].get("type") == "watch", "Watch only account type was not restored correctly" + + # Validate contacts + response = backend_client2.rpc_valid_request("wakuext_contacts", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Contacts were not restored" + assert len(result) == 2, "Contacts were not restored correctly" + + # Validate communities + response = backend_client2.rpc_valid_request("wakuext_joinedCommunities", []) + jsonResponse = response.json() + result = jsonResponse.get("result", {}) + assert result is not None, "Communities were not restored" + assert len(result) == 1, "Communities were not restored correctly" + assert result[0].get("name") == "Test Community", "Community name was not restored correctly" + assert result[0].get("description") == "This is a test community", "Community description was not restored correctly" + + # Validate chats + response = backend_client2.rpc_valid_request("wakuext_chats", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Chats were not restored" + group_chat_recovered = False + one_on_one_chat_recovered = False + for chat in result: + if chat.get("id") == group_chat_id: + assert chat.get("name") == "test-group-chat", "Group chat name was not restored correctly" + group_chat_recovered = True + elif chat.get("id") == test_one_to_one_chat_id: + one_on_one_chat_recovered = True + assert group_chat_recovered, "Group chat was not restored correctly" + assert one_on_one_chat_recovered, "One-to-one chat was not restored correctly" + + def test_local_backup_backwards_compatibility(self, tmp_path): + await_signals = [ + "mediaserver.started", + "node.started", + "node.ready", + "node.login", + ] + backend_client = StatusBackend(await_signals) + assert backend_client is not None + # Restore the account with a hardcoded mnemonic to get the same private key + backend_client.init_status_backend() + backend_client.restore_account_and_login( + user=Account( + # Hardcoded mnemonic for backwards compatibility test + # Do not change this mnemonic, the backup file was created with it + passphrase="flush okay stadium refuse shrug fit actual stairs puzzle brisk flat moral", + password=user_1.password, + # The private key and address are not needed for mnemonic recovery + private_key="", + address="", + ) + ) + backend_client.wait_for_login() + backend_client.wakuext_service.start_messenger() + + # Import the backup file into the container + backend_client.import_data( + os.path.abspath(os.path.join(os.path.dirname(__file__), "../resources/test_data/test_old_user_data.bkp")), "/usr/status-user/backups" + ) + + # Import the backup file + # This is the old backup file that does not contain the BackedUpProfile protobuf + # This means that the display name, identity image and profile showcase preferences will not be restored + response = backend_client.api_valid_request( + "LoadLocalBackup", {"filePath": os.path.join("/usr/status-user/backups", "test_old_user_data.bkp")} + ) + + # This "old" backup file does not contain the identity image, so we expect it to be empty + response = backend_client.rpc_valid_request("multiaccounts_getIdentityImages", [backend_client.key_uid]) + jsonResponse = response.json() + result = jsonResponse.get("result", {}) + assert result is None, "Identity images shouldn't be restored from the old backup file" + + # Profile showcase preferences were not set in the old backup file, so we expect it to be empty + response = backend_client.rpc_valid_request("wakuext_getProfileShowcasePreferences", []) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Profile showcase preferences were not restored" + assert result.get("clock") == 0, "Clock should be 0 as it was not set in the old backup file" + assert result.get("accounts") is None, "Accounts should not be set in the old backup file" + assert len(result.get("collectibles")) == 0, "Collectibles should not be set in the old backup file" + assert result.get("communities") is None, "Communities should not be set in the old backup file" + assert len(result.get("socialLinks")) == 0, "Social links should not be set in the old backup file" + assert len(result.get("unverifiedTokens")) == 0, "Unverified tokens should not be set in the old backup file" + assert len(result.get("verifiedTokens")) == 0, "Verified tokens should not be set in the old backup file" + + # The rest of the data should be restored correctly, so we can check the settings, watchonly account, contacts, communities and chats + # Validate settings + response = backend_client.rpc_valid_request("settings_getSettings", []) + jsonResponse = response.json() + result = response.json().get("result", {}) + assert result is not None, "Settings were not restored" + assert result.get("bio") == "new bio", "Bio setting was not restored" + assert result.get("preferred-name") == "new-prefered-name", "Preferred name setting was not restored" + assert result.get("url-unfurling-mode") == 2, "URL unfurling mode setting was not restored" + assert result.get("messages-from-contacts-only") is True, "Messages from contacts only setting was not restored" + assert result.get("currency") == "eth", "Currency setting was not restored" + assert result.get("mnemonic-removed?") is True, "Mnemonic setting was not restored" + + # Validate watchonly account + response = backend_client.rpc_valid_request("accounts_getAccounts", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Accounts were not restored" + assert len(result) == 3, "Watchonly account was not restored" + assert result[2].get("name") == "test-watchonly-account", "Watch only account name was not restored correctly" + assert result[2].get("emoji") == "🕵️", "Watch only account emoji was not restored correctly" + assert result[2].get("type") == "watch", "Watch only account type was not restored correctly" + + # Validate contacts + response = backend_client.rpc_valid_request("wakuext_contacts", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Contacts were not restored" + assert len(result) == 2, "Contacts were not restored correctly" + + # Validate communities + response = backend_client.rpc_valid_request("wakuext_joinedCommunities", []) + jsonResponse = response.json() + result = jsonResponse.get("result", {}) + assert result is not None, "Communities were not restored" + assert len(result) == 1, "Communities were not restored correctly" + assert result[0].get("name") == "Test Community", "Community name was not restored correctly" + assert result[0].get("description") == "This is a test community", "Community description was not restored correctly" + + # Validate chats + response = backend_client.rpc_valid_request("wakuext_chats", []) + jsonResponse = response.json() + result = jsonResponse.get("result", []) + assert result is not None, "Chats were not restored" + # Chat ids are hardcoded becuase they are in the backup file, so we can check them directly + test_group_chat_id = "1fb5f429-1e23-4156-b216-2799fa430742-0x045b1f2d9bfbbeee1f6995a2086de353399074073d213079d3e0dc2ddc1593e7c50e56aead4a42e25a76effa4208f842f9356f1a5c16aaf16c179ed020277a9901" # noqa: E501 + group_chat_recovered = False + one_on_one_chat_recovered = False + for chat in result: + if chat.get("id") == test_group_chat_id: + assert chat.get("name") == "test-group-chat", "Group chat name was not restored correctly" + group_chat_recovered = True + elif chat.get("id") == test_one_to_one_chat_id: + one_on_one_chat_recovered = True + assert group_chat_recovered, "Group chat was not restored correctly" + assert one_on_one_chat_recovered, "One-to-one chat was not restored correctly" diff --git a/tests-functional/tests/test_local_pairing.py b/tests-functional/tests/test_local_pairing.py new file mode 100644 index 0000000000..b9577bdc59 --- /dev/null +++ b/tests-functional/tests/test_local_pairing.py @@ -0,0 +1,323 @@ +import pytest + +from clients.services.wakuext import ActivityCenterNotificationType, ContactRequestState +from clients.signals import SignalType, LocalPairingEventType, LocalPairingEventAction +from clients.status_backend import StatusBackend +from resources.constants import Account +from steps.messenger import MessengerSteps + + +def check_server_sender_events(events): + assert len(events) == 8 + + assert events[0]["action"] == events[1]["action"] == LocalPairingEventAction.ACTION_PAIRING_ACCOUNT.value + assert events[0]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + assert events[1]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + + assert events[2]["action"] == events[3]["action"] == LocalPairingEventAction.ACTION_SYNC_DEVICE.value + assert events[2]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + assert events[3]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + + assert ( + events[4]["action"] + == events[5]["action"] + == events[6]["action"] + == events[7]["action"] + == LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value + ) + assert events[4]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + assert events[5]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + assert events[6]["type"] == LocalPairingEventType.EVENT_RECEIVED_INSTALLATION.value + assert events[7]["type"] == LocalPairingEventType.EVENT_PROCESS_SUCCESS.value + + for event in events: + assert "error" not in event or not event["error"] + + +def check_client_sender_events(events): + assert len(events) == 6 + + assert events[0]["action"] == LocalPairingEventAction.ACTION_CONNECT.value + assert events[0]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + + assert events[1]["action"] == LocalPairingEventAction.ACTION_PAIRING_ACCOUNT.value + assert events[1]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + + assert events[2]["action"] == LocalPairingEventAction.ACTION_SYNC_DEVICE.value + assert events[2]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + + assert events[3]["action"] == events[4]["action"] == events[5]["action"] == LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value + assert events[3]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + assert events[4]["type"] == LocalPairingEventType.EVENT_RECEIVED_INSTALLATION.value + assert events[5]["type"] == LocalPairingEventType.EVENT_PROCESS_SUCCESS.value + + for event in events: + assert "error" not in event or not event["error"] + + +def check_client_receiver_events(events): + assert len(events) == 8 + + assert events[0]["action"] == LocalPairingEventAction.ACTION_CONNECT.value + assert events[0]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + + assert events[1]["action"] == events[2]["action"] == events[3]["action"] == LocalPairingEventAction.ACTION_PAIRING_ACCOUNT.value + assert events[1]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + assert events[2]["type"] == LocalPairingEventType.EVENT_RECEIVED_ACCOUNT.value + assert events[3]["type"] == LocalPairingEventType.EVENT_PROCESS_SUCCESS.value + + # NOTE: We check events 4 and 6, for some reason they are out of order (but always the same) + assert events[4]["action"] == events[6]["action"] == LocalPairingEventAction.ACTION_SYNC_DEVICE.value + assert events[4]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + assert events[6]["type"] == LocalPairingEventType.EVENT_PROCESS_SUCCESS.value + + assert events[5]["action"] == LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value + assert events[5]["type"] == LocalPairingEventType.EVENT_RECEIVED_INSTALLATION.value + + assert events[7]["action"] == LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value + assert events[7]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + + for event in events: + assert "error" not in event or not event["error"] + + +def check_server_receiver_events(events): + assert len(events) == 10 + + assert ( + events[0]["action"] + == events[1]["action"] + == events[2]["action"] + == events[3]["action"] + == LocalPairingEventAction.ACTION_PAIRING_ACCOUNT.value + ) + assert events[0]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + assert events[1]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + assert events[2]["type"] == LocalPairingEventType.EVENT_RECEIVED_ACCOUNT.value + assert events[3]["type"] == LocalPairingEventType.EVENT_PROCESS_SUCCESS.value + + assert events[4]["action"] == events[5]["action"] == events[7]["action"] == LocalPairingEventAction.ACTION_SYNC_DEVICE.value + assert events[4]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + assert events[5]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + assert events[7]["type"] == LocalPairingEventType.EVENT_PROCESS_SUCCESS.value + + assert events[6]["action"] == events[8]["action"] == events[9]["action"] == LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value + assert events[6]["type"] == LocalPairingEventType.EVENT_RECEIVED_INSTALLATION.value + assert events[8]["type"] == LocalPairingEventType.EVENT_CONNECTION_SUCCESS.value + assert events[9]["type"] == LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value + + for event in events: + assert "error" not in event or not event["error"] + + +def wait_for_action_of_type(backend: StatusBackend, action, type): + backend.wait_for_signal_predicate( + SignalType.LOCAL_PAIRING.value, + lambda signal: signal.get("event", {}).get("action") == action and signal.get("event", {}).get("type") == type, + ) + + +def pair_server_as_sender(sender, receiver): + connection_string = sender.get_connection_string_for_bootstrapping_another_device() + response = receiver.input_connection_string_for_bootstrapping(connection_string) + assert response["error"] is None + assert response["keyUID"] == sender.key_uid + + wait_for_action_of_type(sender, LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value, LocalPairingEventType.EVENT_PROCESS_SUCCESS.value) + wait_for_action_of_type(receiver, LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value, LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value) + + +def pair_server_as_receiver(sender, receiver): + connection_string = receiver.get_connection_string_for_being_bootstrapped() + response = sender.input_connection_string_for_bootstrapping_another_device(connection_string) + assert response.get("error") in (None, "") + + wait_for_action_of_type(sender, LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value, LocalPairingEventType.EVENT_PROCESS_SUCCESS.value) + wait_for_action_of_type(receiver, LocalPairingEventAction.ACTION_PAIRING_INSTALLATION.value, LocalPairingEventType.EVENT_TRANSFER_SUCCESS.value) + + +def login_paired_device(backend: StatusBackend, key_uid, password): + user = Account( + password=password, + address="", + private_key="", + passphrase="", + ) + backend.init_status_backend() + backend.login(key_uid, user) + backend.wait_for_login() + backend.wakuext_service.start_messenger() + + +@pytest.mark.rpc +class TestLocalPairing(MessengerSteps): + + await_signals = [ + SignalType.MESSAGES_NEW.value, + SignalType.MESSAGE_DELIVERED.value, + SignalType.NODE_LOGIN.value, + SignalType.NODE_LOGOUT.value, + SignalType.LOCAL_PAIRING.value, + ] + + @pytest.fixture(autouse=True) + def setup_cleanup(self, close_status_backend_containers): + """Automatically cleanup containers after each test""" + yield + + def initialize_backend(self, await_signals, privileged=True, **kwargs): + backend = StatusBackend(await_signals, privileged=privileged) + backend.init_status_backend() + backend.create_account_and_login(**kwargs) + backend.wait_for_login() + backend.wakuext_service.start_messenger() + return backend + + def test_pairing_server_as_sender(self): + # Create users + alice = self.initialize_backend(self.await_signals, False) + bob = self.initialize_backend(self.await_signals, False) + + bob_second_device = StatusBackend(self.await_signals) + bob_second_device.init_status_backend() + + # Make contacts before local pairing + self.make_contacts(alice, bob) + + # Create community before local pairing + self.create_community(bob) + + # Local pairing + pair_server_as_sender(bob, bob_second_device) + + # Check sender signals + events = bob.get_all_events(signal_type=SignalType.LOCAL_PAIRING.value) + check_server_sender_events(events) + + # Check receiver signals + events = bob_second_device.get_all_events(signal_type=SignalType.LOCAL_PAIRING.value) + check_client_receiver_events(events) + + # Login on the second device + login_paired_device(bob_second_device, bob.key_uid, bob.password) + + # Check that contact is synced + response = bob_second_device.wakuext_service.get_contacts() + + contacts = response["result"] + assert len(contacts) == 1 + assert contacts[0]["id"] == alice.public_key + + # Checking the paired devices using accounts_hasPairedDevices method + alice_response = alice.accounts_service.has_paired_devices() + assert alice_response.get("result") is False + bob_response = bob.accounts_service.has_paired_devices() + assert bob_response.get("result") is True + + def test_pairing_server_as_receiver(self): + # Create users + alice = self.initialize_backend(self.await_signals, False) + bob = self.initialize_backend(self.await_signals, False) + bob_second_device = StatusBackend(self.await_signals) + bob_second_device.init_status_backend() + + # Make contacts before local pairing + self.make_contacts(alice, bob) + + # Create community before local pairing + self.create_community(bob) + + # Local pairing + pair_server_as_receiver(bob, bob_second_device) + + # Check sender signals + events = bob.get_all_events(signal_type=SignalType.LOCAL_PAIRING.value) + check_client_sender_events(events) + + # Check receiver signals + events = bob_second_device.get_all_events(signal_type=SignalType.LOCAL_PAIRING.value) + check_server_receiver_events(events) + + # Check that contact is synced + response = bob_second_device.wakuext_service.get_contacts() + + contacts = response["result"] + assert len(contacts) == 1 + assert contacts[0]["id"] == alice.public_key + + # Checking the paired devices using accounts_hasPairedDevices method + alice_response = alice.accounts_service.has_paired_devices() + assert alice_response.get("result") is False + bob_response = bob.accounts_service.has_paired_devices() + assert bob_response.get("result") is True + + def test_pairing_three_devices(self): + # Create users + bob1 = self.initialize_backend(self.await_signals, False) + bob2 = StatusBackend(self.await_signals) + bob2.init_status_backend() + bob3 = StatusBackend(self.await_signals) + bob3.init_status_backend() + user_accepted = self.initialize_backend(self.await_signals, False) + user_pending = self.initialize_backend(self.await_signals, False) + user_declined = self.initialize_backend(self.await_signals, False) + + # Setup contacts before local pairing + self.make_contacts(user_accepted, bob1) + self.send_contact_request_and_wait_for_signal_to_be_received(user_pending, bob1) + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(user_declined, bob1) + bob1.wakuext_service.decline_contact_request(message_id) + + # Pair second device + pair_server_as_sender(bob1, bob2) + + # Login on the second device + login_paired_device(bob2, bob1.key_uid, bob1.password) + + # Pair third device from second device + pair_server_as_sender(bob2, bob3) + + # Login on the third device + login_paired_device(bob3, bob1.key_uid, bob1.password) + + # Check that contacts and notifications are synced on all devices + for bob_another_device in [bob2, bob3]: + response = bob_another_device.wakuext_service.get_contacts() + contacts = response["result"] + assert len(contacts) == 3 + contacts_dict = {contact["id"]: contact for contact in contacts} + assert contacts_dict[user_accepted.public_key]["mutual"] is True + assert contacts_dict[user_accepted.public_key]["contactRequestState"] is ContactRequestState.MUTUAL.value + assert contacts_dict[user_pending.public_key]["mutual"] is False + assert contacts_dict[user_pending.public_key]["contactRequestState"] is ContactRequestState.RECEIVED.value + assert contacts_dict[user_declined.public_key]["mutual"] is False + assert contacts_dict[user_declined.public_key]["contactRequestState"] is ContactRequestState.DISMISSED.value + + # Paired device will get notifications of requests that are not fulfilled (not mutual) + notifications = bob_another_device.wakuext_service.get_activity_center_notifications( + activity_types=[ActivityCenterNotificationType.NOTIFICATION_TYPE_CONTACT_REQUEST] + )["result"]["notifications"] + assert len(notifications) == 2 + notifications_dict = {notification["chatId"]: notification for notification in notifications} + user_pending_notification = notifications_dict[user_pending.public_key] + assert user_pending_notification["read"] is False + assert user_pending_notification["accepted"] is False + assert user_pending_notification["dismissed"] is False + user_declined_notification = notifications_dict[user_declined.public_key] + assert user_declined_notification["read"] is True + assert user_declined_notification["accepted"] is False + assert user_declined_notification["dismissed"] is True + + def test_pairing_receiver_must_be_logged_out(self): + sender = self.initialize_backend(self.await_signals, False) + receiver = self.initialize_backend(self.await_signals, False) + + # Client receiver must be logged out + connection_string = sender.get_connection_string_for_bootstrapping_another_device() + response = receiver.input_connection_string_for_bootstrapping(connection_string) + assert response["error"] is not None + + # Server receiver must be logged out + connection_string = receiver.get_connection_string_for_being_bootstrapped() + response = sender.input_connection_string_for_bootstrapping_another_device(connection_string) + assert response["error"] is not None diff --git a/tests-functional/tests/test_logging.py b/tests-functional/tests/test_logging.py index 099a543ab3..db1764a467 100644 --- a/tests-functional/tests/test_logging.py +++ b/tests-functional/tests/test_logging.py @@ -7,6 +7,11 @@ @pytest.mark.rpc class TestLogging: + @pytest.fixture(autouse=True) + def setup_cleanup(self, close_status_backend_containers): + """Automatically cleanup containers after each test""" + yield + @pytest.mark.init def test_logging(self, tmp_path): await_signals = [ @@ -39,7 +44,7 @@ def test_logging(self, tmp_path): r"ERROR\s+test1\.test2\.test3\s+", ] - key_uid = str(backend_client.find_key_uid()) + key_uid = str(backend_client.key_uid) formatted_key_uid = f"{key_uid[:4]}..{key_uid[-4:]}" profile_log_file_name = f"{formatted_key_uid}.log" log_path = os.path.join(backend_client.data_dir, profile_log_file_name) diff --git a/tests-functional/tests/test_move_wallet_account.py b/tests-functional/tests/test_move_wallet_account.py new file mode 100644 index 0000000000..a3942069f0 --- /dev/null +++ b/tests-functional/tests/test_move_wallet_account.py @@ -0,0 +1,66 @@ +import copy +import pytest +from resources.constants import new_account_data_1 + + +@pytest.mark.rpc +class TestMoveWalletAccount: + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + self.account = backend_new_profile("sender") + self.account_data = copy.deepcopy(new_account_data_1) + + def test_move_non_profile_wallet_accounts(self): + # Add new account + path = "m/44'/60'/0'/0/1" + derived_addresses_response = self.account.wallet_service.get_derived_addresses_for_mnemonic(self.account.mnemonic, [path]) + derived_addresses = derived_addresses_response.json()["result"] + self.account_data["key-uid"] = self.account.key_uid # keyuid of profile keypair + self.account_data["path"] = path + self.account_data["address"] = derived_addresses[0].get("address") + self.account_data["public-key"] = derived_addresses[0].get("public-key") + self.account.accounts_service.add_account(self.account.password, self.account_data) + + # Get all accounts to determine positions + accounts_response = self.account.accounts_service.get_accounts() + accounts_before = [acc for acc in accounts_response.get("result", [])] + assert len(accounts_before) >= 3, "Need at least two accounts to test move" + + # Move wallet account from position 1 to position 2 + move_accounts_response = self.account.accounts_service.move_wallet_account( + accounts_before[1].get("position"), accounts_before[2].get("position") + ) + assert "result" in move_accounts_response + assert move_accounts_response.get("result") is None + + # Fetch the accounts again + accounts_response_after = self.account.accounts_service.get_accounts() + accounts_after = [acc for acc in accounts_response_after.get("result", [])] + + # Checking the positions are still incremental after move + assert accounts_before[0]["position"] == -1 + assert accounts_before[1]["position"] == 0 + assert accounts_before[2]["position"] == 1 + assert accounts_after[0]["position"] == -1 + assert accounts_after[1]["position"] == 0 + assert accounts_after[2]["position"] == 1 + + # Make the positions equal so we can verify that entire account objects match after move + # Ex Account at position 1 becomes position 2 + accounts_before[1]["position"] = accounts_before[2]["position"] = accounts_after[1]["position"] = accounts_after[2]["position"] = 0 + + assert accounts_before[1] == accounts_after[2] + assert accounts_before[2] == accounts_after[1] + + def test_move_profile_account_isnt_allowed(self): + # Get all accounts to determine positions + accounts_response = self.account.accounts_service.get_accounts() + accounts_before = [acc for acc in accounts_response.get("result", [])] + assert len(accounts_before) >= 2, "Need at least two accounts to test move" + + # Move wallet account from position 0 to position 1 + move_accounts_response = self.account.accounts_service.move_wallet_account( + accounts_before[0].get("position"), accounts_before[1].get("position") + ) + assert move_accounts_response.get("error").get("message") == "accounts: trying to move account to a wrong position" diff --git a/tests-functional/tests/test_push_notification_server.py b/tests-functional/tests/test_push_notification_server.py new file mode 100644 index 0000000000..451845ec8a --- /dev/null +++ b/tests-functional/tests/test_push_notification_server.py @@ -0,0 +1,87 @@ +import time +import uuid + +import pytest + +from clients.gorush_stub import GorushStub +from clients.push_notification_server import PushNotificationServer +from clients.services.wakuext import PushNotificationRegistrationTokenType +from steps.messenger import MessengerSteps +from utils import keys + +APN_TOPIC = "im.status.ethereum" +DEFAULT_PUSH_MESSAGE = "You have a new message" + + +@pytest.fixture +def gorush_stub(): + """ + Fixture that provides a GorushStub instance + + The instance is automatically closed after the test + """ + gorush = GorushStub(address="0.0.0.0", port=0) # Use port 0 to get a random available port + yield gorush + gorush.close() + + +@pytest.fixture +def push_notification_server(gorush_stub): + """ + Fixture that provides a PushNotificationServer connected to a GorushStub + + The PushNotificationServer is automatically stopped after the test + """ + server = PushNotificationServer(gorush_port=gorush_stub.server.server_port) + yield server, gorush_stub + if server.container: + server.container.stop() + + +def expect_push_notification(gorush, sender, receiver): + requests = gorush.wait_for_requests() + assert len(requests) == 1, "Expected 1 push notification to be received" + + push = requests[0] + assert len(push["tokens"]) == 1 and push["tokens"][0] == receiver.device_id, "Expected only Bob device_id in push notification tokens" + assert push["platform"] == receiver.device_platform.value + assert push["message"] == DEFAULT_PUSH_MESSAGE + assert push["data"]["publicKey"] == keys.shake256(bytes.fromhex(receiver.compressed_public_key()[2:])) + assert push["data"]["chatId"] == keys.shake256(sender.public_key.encode("utf-8")) + + +@pytest.mark.rpc +class TestPushNotificationServer(MessengerSteps): + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two backends (alice and bob) for each test function""" + self.sender = backend_new_profile("alice") + self.receiver = backend_new_profile("bob") + + def test_push_notification_delivery(self, push_notification_server): + server, gorush = push_notification_server + alice = self.sender + bob = self.receiver + + # Register devices + alice.device_platform = PushNotificationRegistrationTokenType.APN_TOKEN + alice.wakuext_service.register_for_push_notifications(alice.device_id, APN_TOPIC, alice.device_platform) + + bob.device_platform = PushNotificationRegistrationTokenType.FIREBASE_TOKEN + bob.wakuext_service.register_for_push_notifications(bob.device_id, APN_TOPIC, bob.device_platform) + + # There is currently no way to reliably check if the devices have been registered, so we just wait a few seconds + time.sleep(10) + + # Make contacts, this should force delivery of a push notification + self.make_contacts(alice, bob) + expect_push_notification(gorush, alice, bob) + + # Send a message from Alice to Bob + alice.wakuext_service.send_one_to_one_message(bob.public_key, f"Message {uuid.uuid4()}") + expect_push_notification(gorush, alice, bob) + + # Send a message from Bob to Alice + bob.wakuext_service.send_one_to_one_message(alice.public_key, f"Message {uuid.uuid4()}") + expect_push_notification(gorush, bob, alice) diff --git a/tests-functional/tests/test_resolve_suggested_path.py b/tests-functional/tests/test_resolve_suggested_path.py new file mode 100644 index 0000000000..9e1a4599c1 --- /dev/null +++ b/tests-functional/tests/test_resolve_suggested_path.py @@ -0,0 +1,20 @@ +import pytest + + +@pytest.mark.rpc +class TestResolveSuggestedPath: + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + self.account = backend_new_profile("sender") + + @pytest.mark.parametrize( + "key_uid", ["0x9d26312bace61a229c1db5a43d8f9b93d80d25398476405d66479df1504f0438", "0xC43f4Ab94eC965a3EE9815C5Df07383057d261A8", "test"] + ) + def test_resolve_suggested_path_for_random_key(self, key_uid): + response = self.account.accounts_service.resolve_suggested_path_for_keypair(key_uid) + assert response.get("result") == "m/44'/60'/0'/0/0" + + def test_resolve_suggested_path_for_used_key(self): + response = self.account.accounts_service.resolve_suggested_path_for_keypair(self.account.key_uid) + assert response.get("result") == "m/44'/60'/0'/0/1" diff --git a/tests-functional/tests/test_router.py b/tests-functional/tests/test_router.py index 4d4f941d14..645d957d77 100644 --- a/tests-functional/tests/test_router.py +++ b/tests-functional/tests/test_router.py @@ -1,18 +1,20 @@ import uuid as uuid_lib - import pytest -import logging + import resources.constants as constants +from clients.anvil import Anvil +from web3.types import Wei -from steps.status_backend import StatusBackendSteps from clients.signals import SignalType from utils import wallet_utils +from resources.constants import user_1 @pytest.mark.rpc @pytest.mark.transaction @pytest.mark.wallet -class TestRouter(StatusBackendSteps): +class TestRouter: + await_signals = [ SignalType.NODE_LOGIN.value, SignalType.WALLET.value, @@ -22,9 +24,14 @@ class TestRouter(StatusBackendSteps): SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value, ] + @pytest.fixture(autouse=True) + def setup_backend(self, backend_recovered_profile): + self.rpc_client = backend_recovered_profile(name="main_user", user=user_1) + def test_tx_from_route(self): uuid = str(uuid_lib.uuid4()) amount_in = "0xde0b6b3a7640000" + amount_in_wei = Wei(1000000000000000000) params = { "uuid": uuid, @@ -36,13 +43,13 @@ def test_tx_from_route(self): "tokenID": "ETH", "tokenIDIsOwnerToken": False, "toTokenID": "", - "disabledFromChainIDs": [1, 10, 42161], - "disabledToChainIDs": [1, 10, 42161], + "fromChainID": 31337, + "toChainID": 31337, "gasFeeMode": 1, } routes = wallet_utils.get_suggested_routes(self.rpc_client, **params) - assert len(routes["Best"]) > 0 + assert len(routes["Route"]) > 0 wallet_router_sign_transactions = wallet_utils.build_transactions_from_route(self.rpc_client, uuid) if wallet_router_sign_transactions is None: raise ValueError("wallet_router_sign_transactions is None") @@ -53,7 +60,13 @@ def test_tx_from_route(self): transaction_hashes = wallet_router_sign_transactions["signingDetails"]["hashes"] tx_signatures = wallet_utils.sign_messages(self.rpc_client, transaction_hashes, constants.user_1.address) tx_status = wallet_utils.send_router_transactions_with_signatures(self.rpc_client, uuid, tx_signatures) - wallet_utils.check_tx_details(self.rpc_client, tx_status["hash"], self.network_id, constants.user_2.address, amount_in) + + # Check tx details + tx_data = Anvil().get_transaction(tx_status["hash"]) + + assert tx_data.get("value", 0) == int(amount_in, 16) + assert tx_data.get("value", 0) == amount_in_wei + assert tx_data.get("to", "").upper() == constants.user_2.address.upper() def test_setting_different_fee_modes(self): uuid = str(uuid_lib.uuid4()) @@ -70,53 +83,53 @@ def test_setting_different_fee_modes(self): "tokenID": "ETH", "tokenIDIsOwnerToken": False, "toTokenID": "", - "disabledFromChainIDs": [1, 10, 42161], - "disabledToChainIDs": [1, 10, 42161], + "fromChainID": 31337, + "toChainID": 31337, "gasFeeMode": gas_fee_mode, } - logging.info("Step: getting the best route") + # Step: getting the best route routes = wallet_utils.get_suggested_routes(self.rpc_client, **router_input_params) - assert len(routes["Best"]) > 0 - wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Best"][0]["ApprovalRequired"], routes["Best"]) + assert len(routes["Route"]) > 0 + wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Route"][0]["ApprovalRequired"], routes["Route"]) - logging.info("Step: update gas fee mode without providing path tx identity params via wallet_setFeeMode endpoint") + # Step: update gas fee mode without providing path tx identity params via wallet_setFeeMode endpoint method = "wallet_setFeeMode" response = self.rpc_client.rpc_request(method, [None, gas_fee_mode]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: update gas fee mode with incomplete details for path tx identity params via wallet_setFeeMode endpoint") + # Step: update gas fee mode with incomplete details for path tx identity params via wallet_setFeeMode endpoint tx_identity_params = { "routerInputParamsUuid": uuid, } response = self.rpc_client.rpc_request(method, [tx_identity_params, gas_fee_mode]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: update gas fee mode to low") + # Step: update gas fee mode to low gas_fee_mode = constants.gas_fee_mode_low tx_identity_params = { "routerInputParamsUuid": uuid, - "pathName": routes["Best"][0]["ProcessorName"], - "chainID": routes["Best"][0]["FromChain"]["chainId"], - "isApprovalTx": routes["Best"][0]["ApprovalRequired"], + "pathName": routes["Route"][0]["ProcessorName"], + "chainID": routes["Route"][0]["FromChain"]["chainId"], + "isApprovalTx": routes["Route"][0]["ApprovalRequired"], } self.rpc_client.prepare_wait_for_signal("wallet.suggested.routes", 1) _ = self.rpc_client.rpc_valid_request(method, [tx_identity_params, gas_fee_mode]) response = self.rpc_client.wait_for_signal("wallet.suggested.routes") routes = response["event"] - assert len(routes["Best"]) > 0 - wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Best"][0]["ApprovalRequired"], routes["Best"]) + assert len(routes["Route"]) > 0 + wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Route"][0]["ApprovalRequired"], routes["Route"]) - logging.info("Step: update gas fee mode to high") + # Step: update gas fee mode to high gas_fee_mode = constants.gas_fee_mode_high self.rpc_client.prepare_wait_for_signal("wallet.suggested.routes", 1) _ = self.rpc_client.rpc_valid_request(method, [tx_identity_params, gas_fee_mode]) response = self.rpc_client.wait_for_signal("wallet.suggested.routes") routes = response["event"] - assert len(routes["Best"]) > 0 - wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Best"][0]["ApprovalRequired"], routes["Best"]) + assert len(routes["Route"]) > 0 + wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Route"][0]["ApprovalRequired"], routes["Route"]) - logging.info("Step: try to set custom gas fee mode via wallet_setFeeMode endpoint") + # Step: try to set custom gas fee mode via wallet_setFeeMode endpoint gas_fee_mode = constants.gas_fee_mode_custom response = self.rpc_client.rpc_request(method, [tx_identity_params, gas_fee_mode]) self.rpc_client.verify_is_json_rpc_error(response) @@ -136,34 +149,34 @@ def test_setting_custom_fee_mode(self): "tokenID": "ETH", "tokenIDIsOwnerToken": False, "toTokenID": "", - "disabledFromChainIDs": [1, 10, 42161], - "disabledToChainIDs": [1, 10, 42161], + "fromChainID": 31337, + "toChainID": 31337, "gasFeeMode": gas_fee_mode, } - logging.info("Step: getting the best route") + # Step: getting the best route routes = wallet_utils.get_suggested_routes(self.rpc_client, **router_input_params) - assert len(routes["Best"]) > 0 - wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Best"][0]["ApprovalRequired"], routes["Best"]) + assert len(routes["Route"]) > 0 + wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Route"][0]["ApprovalRequired"], routes["Route"]) - logging.info("Step: try to set custom tx details with empty params via wallet_setCustomTxDetails endpoint") + # Step: try to set custom tx details with empty params via wallet_setCustomTxDetails endpoint method = "wallet_setCustomTxDetails" response = self.rpc_client.rpc_request(method, [None, None]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: try to set custom tx details with incomplete details for path tx identity params via wallet_setCustomTxDetails endpoint") + # Step: try to set custom tx details with incomplete details for path tx identity params via wallet_setCustomTxDetails endpoint tx_identity_params = { "routerInputParamsUuid": uuid, } response = self.rpc_client.rpc_request(method, [tx_identity_params, None]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: try to set custom tx details providing other than the custom gas fee mode via wallet_setCustomTxDetails endpoint") + # Step: try to set custom tx details providing other than the custom gas fee mode via wallet_setCustomTxDetails endpoint tx_identity_params = { "routerInputParamsUuid": uuid, - "pathName": routes["Best"][0]["ProcessorName"], - "chainID": routes["Best"][0]["FromChain"]["chainId"], - "isApprovalTx": routes["Best"][0]["ApprovalRequired"], + "pathName": routes["Route"][0]["ProcessorName"], + "chainID": routes["Route"][0]["FromChain"]["chainId"], + "isApprovalTx": routes["Route"][0]["ApprovalRequired"], } tx_custom_params = { "gasFeeMode": constants.gas_fee_mode_low, @@ -171,14 +184,14 @@ def test_setting_custom_fee_mode(self): response = self.rpc_client.rpc_request(method, [tx_identity_params, tx_custom_params]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: try to set custom tx details without providing maxFeesPerGas via wallet_setCustomTxDetails endpoint") + # Step: try to set custom tx details without providing maxFeesPerGas via wallet_setCustomTxDetails endpoint tx_custom_params = { "gasFeeMode": gas_fee_mode, } response = self.rpc_client.rpc_request(method, [tx_identity_params, tx_custom_params]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: try to set custom tx details without providing PriorityFee via wallet_setCustomTxDetails endpoint") + # Step: try to set custom tx details without providing PriorityFee via wallet_setCustomTxDetails endpoint tx_custom_params = { "gasFeeMode": gas_fee_mode, "maxFeesPerGas": "0x77359400", @@ -186,7 +199,7 @@ def test_setting_custom_fee_mode(self): response = self.rpc_client.rpc_request(method, [tx_identity_params, tx_custom_params]) self.rpc_client.verify_is_json_rpc_error(response) - logging.info("Step: try to set custom tx details via wallet_setCustomTxDetails endpoint") + # Step: try to set custom tx details via wallet_setCustomTxDetails endpoint gas_fee_mode = constants.gas_fee_mode_custom tx_nonce = 4 tx_gas_amount = 30000 @@ -194,9 +207,9 @@ def test_setting_custom_fee_mode(self): tx_priority_fee = "0x1DCD6500" tx_identity_params = { "routerInputParamsUuid": uuid, - "pathName": routes["Best"][0]["ProcessorName"], - "chainID": routes["Best"][0]["FromChain"]["chainId"], - "isApprovalTx": routes["Best"][0]["ApprovalRequired"], + "pathName": routes["Route"][0]["ProcessorName"], + "chainID": routes["Route"][0]["FromChain"]["chainId"], + "isApprovalTx": routes["Route"][0]["ApprovalRequired"], } tx_custom_params = { "gasFeeMode": gas_fee_mode, @@ -209,10 +222,10 @@ def test_setting_custom_fee_mode(self): _ = self.rpc_client.rpc_valid_request(method, [tx_identity_params, tx_custom_params]) response = self.rpc_client.wait_for_signal("wallet.suggested.routes") routes = response["event"] - assert len(routes["Best"]) > 0 - tx_nonce_int = int(routes["Best"][0]["TxNonce"], 16) + assert len(routes["Route"]) > 0 + tx_nonce_int = int(routes["Route"][0]["TxNonce"], 16) assert tx_nonce_int == tx_nonce - assert routes["Best"][0]["TxGasAmount"] == tx_gas_amount - assert routes["Best"][0]["TxMaxFeesPerGas"].upper() == tx_max_fees_per_gas.upper() - assert routes["Best"][0]["TxPriorityFee"].upper() == tx_priority_fee.upper() - wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Best"][0]["ApprovalRequired"], routes["Best"]) + assert routes["Route"][0]["TxGasAmount"] == tx_gas_amount + assert routes["Route"][0]["TxMaxFeesPerGas"].upper() == tx_max_fees_per_gas.upper() + assert routes["Route"][0]["TxPriorityFee"].upper() == tx_priority_fee.upper() + wallet_utils.check_fees_for_path(constants.processor_name_transfer, gas_fee_mode, routes["Route"][0]["ApprovalRequired"], routes["Route"]) diff --git a/tests-functional/tests/test_token_preferences.py b/tests-functional/tests/test_token_preferences.py new file mode 100644 index 0000000000..8c2feba218 --- /dev/null +++ b/tests-functional/tests/test_token_preferences.py @@ -0,0 +1,61 @@ +import pytest + + +@pytest.mark.rpc +class TestTokenPreferences: + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + self.account = backend_new_profile("sender") + + def test_update_with_valid_token_preferences(self): + token_preferences_before = self.account.accounts_service.get_token_preferences() + assert "result" in token_preferences_before + assert token_preferences_before.get("result") is None + + new_token_preferences = [ + {"communityId": "123", "groupPosition": 2, "key": "0x1234567890abcdef1234567890abcdef12345678", "position": 3, "visible": True} + ] + update_response = self.account.accounts_service.update_token_preferences(new_token_preferences) + assert "result" in update_response + assert update_response.get("result") is None + + token_preferences_after = self.account.accounts_service.get_token_preferences() + assert token_preferences_after.get("result") == new_token_preferences + + def test_update_with_invalid_token_preferences(self): + new_token_preferences = [{"key": "0x1234567890abcdef1234567890abcdef12345678", "foo": "bar"}] + self.account.accounts_service.update_token_preferences(new_token_preferences) + token_preferences_after = self.account.accounts_service.get_token_preferences() + assert len(token_preferences_after) + + # missing fields are assigned default values + # extra fields are ignored + # exiting fields are updated + token_preference = token_preferences_after.get("result")[0] + assert token_preference.get("communityId") == "" + assert token_preference.get("groupPosition") == 0 + assert token_preference.get("key") == new_token_preferences[0]["key"] + assert token_preference.get("position") == 0 + assert token_preference.get("visible") is False + + def test_overwrite_existing_token_preferences(self): + new_token_preferences1 = [ + {"communityId": "123", "groupPosition": 2, "key": "0x1234567890abcdef1234567890abcdef12345678", "position": 3, "visible": True} + ] + self.account.accounts_service.update_token_preferences(new_token_preferences1) + new_token_preferences2 = [ + {"communityId": "567", "groupPosition": 1, "key": "0x1234567890abcdef1234567890abcdef12345676", "position": 1, "visible": False} + ] + self.account.accounts_service.update_token_preferences(new_token_preferences2) + token_preferences_after = self.account.accounts_service.get_token_preferences() + assert token_preferences_after.get("result") == new_token_preferences2 + + def test_add_multiple_token_preferences(self): + new_token_preferences = [ + {"communityId": "123", "groupPosition": 2, "key": "0x1234567890abcdef1234567890abcdef12345678", "position": 3, "visible": True}, + {"communityId": "567", "groupPosition": 1, "key": "0x1234567890abcdef1234567890abcdef12345676", "position": 1, "visible": False}, + ] + self.account.accounts_service.update_token_preferences(new_token_preferences) + token_preferences_after = self.account.accounts_service.get_token_preferences() + assert token_preferences_after.get("result") == new_token_preferences diff --git a/tests-functional/tests/test_update_keypair_name.py b/tests-functional/tests/test_update_keypair_name.py new file mode 100644 index 0000000000..34ccff8882 --- /dev/null +++ b/tests-functional/tests/test_update_keypair_name.py @@ -0,0 +1,43 @@ +import pytest +from resources.constants import user_1 + + +@pytest.mark.rpc +class TestUpdateKeypairName: + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + self.account = backend_new_profile("sender") + + def test_update_name_for_profile_keypair_isnt_allowed(self): + new_name = "Updated Keypair Name" + response = self.account.accounts_service.update_keypair_name(self.account.key_uid, new_name) + assert response.get("error").get("message") == "cannot change profile keypair name" + + def test_update_keypair_name_for_seed_account(self): + wallet_account_details = { + "name": "SeedImportedAccount", + "path": "m/44'/60'/0'/0/0", + "emoji": "🔑", + "colorId": "primary", + } + self.account.accounts_service.add_keypair_via_seed_phrase( + user_1.passphrase, self.account.password, "SeedImportedKeypair", wallet_account_details + ) + + keypairs_response = self.account.accounts_service.get_account_keypairs() + keypairs = keypairs_response.get("result", []) + assert len(keypairs) > 0 + seed_key_uid = keypairs[1].get("key-uid") + new_name = "Updated Keypair Name" + + response = self.account.accounts_service.update_keypair_name(seed_key_uid, new_name) + assert "result" in response + assert response.get("result") is None + + # Verify the keypair name was updated by fetching keypairs again + keypairs_response_after = self.account.accounts_service.get_account_keypairs() + keypairs_after = keypairs_response_after.get("result", []) + updated_keypair = next((kp for kp in keypairs_after if kp.get("key-uid") == seed_key_uid), None) + assert updated_keypair is not None + assert updated_keypair.get("name") == new_name diff --git a/tests-functional/tests/test_verify_password.py b/tests-functional/tests/test_verify_password.py new file mode 100644 index 0000000000..28069d8cca --- /dev/null +++ b/tests-functional/tests/test_verify_password.py @@ -0,0 +1,18 @@ +import pytest + + +@pytest.mark.rpc +class TestVerifyPassword: + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + self.account = backend_new_profile("sender") + + def test_verify_correct_password(self): + response = self.account.accounts_service.verify_password(self.account.password) + assert response.get("result") is True + + @pytest.mark.parametrize("password", ["testpassword", ""]) + def test_verify_wrong_password(self, password): + response = self.account.accounts_service.verify_password(password) + assert response.get("result") is False diff --git a/tests-functional/tests/test_wakuext_chats.py b/tests-functional/tests/test_wakuext_chats.py index d441fd10fc..105bd7e6e2 100644 --- a/tests-functional/tests/test_wakuext_chats.py +++ b/tests-functional/tests/test_wakuext_chats.py @@ -5,72 +5,72 @@ from steps.messenger import MessengerSteps -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) @pytest.mark.rpc +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["waku_light_client_False", "waku_light_client_True"]) +@pytest.mark.parametrize("backend_factory", [{"privileged": False}], indirect=True, ids=["privileged_False"]) class TestChatActions(MessengerSteps): - def test_all_chats(self, setup_two_unprivileged_nodes): - self.make_contacts() - private_group_id = self.join_private_group() + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile, waku_light_client): + """Initialize two backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client) + + def test_all_chats(self): + self.make_contacts(self.sender, self.receiver) + private_group_id = self.join_private_group(admin=self.sender, member=self.receiver) self.sender.wakuext_service.send_chat_message(private_group_id, "test_message") - self.send_multiple_one_to_one_messages(1) + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) response = self.sender.wakuext_service.chats() - self.sender.verify_json_schema(response, method="wakuext_chats") - chats = response.get("result", []) assert len(chats) == 2 assert chats[0].get("chatType", 0) == ChatType.ONE_TO_ONE.value assert chats[1].get("chatType", 0) == ChatType.PRIVATE_GROUP_CHAT.value - def test_chat_by_chat_id(self, setup_two_unprivileged_nodes): - sent_texts, _ = self.send_multiple_one_to_one_messages(1) + def test_chat_by_chat_id(self): + sent_texts, _ = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) chat_id = self.receiver.public_key response = self.sender.wakuext_service.chat(chat_id) - self.sender.verify_json_schema(response, method="wakuext_chat") - chat = response.get("result", {}) assert chat.get("chatType", 0) == ChatType.ONE_TO_ONE.value assert chat.get("lastMessage", {}).get("text", "") == sent_texts[0] - def test_chats_preview(self, setup_two_unprivileged_nodes): + def test_chats_preview(self): # One to one - self.make_contacts() - self.send_multiple_one_to_one_messages(1) + self.make_contacts(self.sender, self.receiver) + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) one_to_one_chat_id = self.receiver.public_key # Group - private_group_chat_id = self.join_private_group() + private_group_chat_id = self.join_private_group(admin=self.sender, member=self.receiver) self.sender.wakuext_service.send_group_chat_message(private_group_chat_id, "test_message_group") # Community self.create_community(self.sender) - community_chat_id = self.join_community(self.receiver) + community_chat_id = self.join_community(member=self.receiver, admin=self.sender) self.sender.wakuext_service.send_chat_message(community_chat_id, "test_message_community") response = self.sender.wakuext_service.chats_preview(ChatPreviewFilterType.Community.value) - self.sender.verify_json_schema(response, method="wakuext_chatsPreview") - chats_previews = response.get("result", []) assert len(chats_previews) == 1 assert chats_previews[0].get("id", "") == community_chat_id response = self.sender.wakuext_service.chats_preview(ChatPreviewFilterType.NonCommunity.value) - self.sender.verify_json_schema(response, method="wakuext_chatsPreview") chats_previews = response.get("result", []) assert len(chats_previews) == 2 assert chats_previews[0].get("id", "") == one_to_one_chat_id assert chats_previews[1].get("id", "") == private_group_chat_id - def test_active_chats(self, setup_two_unprivileged_nodes): - self.make_contacts() - self.send_multiple_one_to_one_messages(1) + def test_active_chats(self): + self.make_contacts(self.sender, self.receiver) + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) one_to_one_chat_id = self.receiver.public_key - private_group_chat_id = self.join_private_group() + private_group_chat_id = self.join_private_group(admin=self.sender, member=self.receiver) response = self.sender.wakuext_service.active_chats() - self.sender.verify_json_schema(response, method="wakuext_chats") + # TODO: Add more assertions on response chats = response.get("result", []) assert len(chats) == 2 @@ -82,8 +82,8 @@ def test_active_chats(self, setup_two_unprivileged_nodes): assert len(chats) == 1 assert chats[0].get("id", 0) == one_to_one_chat_id - def test_mute_chat(self, setup_two_unprivileged_nodes): - self.send_multiple_one_to_one_messages(1) + def test_mute_chat(self): + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) chat_id = self.receiver.public_key response = self.sender.wakuext_service.mute_chat(chat_id) @@ -95,6 +95,8 @@ def test_mute_chat(self, setup_two_unprivileged_nodes): assert chat.get("muted", False) is True assert chat.get("muteTill", "") == result + @pytest.mark.skip(reason="Skipping mute chat tests due to failing on local build") + # TODO: check in nightly build locally @pytest.mark.parametrize( "mute_type, time_delta", [ @@ -109,8 +111,8 @@ def test_mute_chat(self, setup_two_unprivileged_nodes): (MuteType.MUTE_FOR24_HR.value, timedelta(hours=24)), ], ) - def test_mute_chat_v2(self, mute_type, time_delta, setup_two_unprivileged_nodes): - self.send_multiple_one_to_one_messages(1) + def test_mute_chat_v2(self, mute_type, time_delta): + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) chat_id = self.receiver.public_key response = self.sender.wakuext_service.mute_chat_v2(chat_id, mute_type) @@ -134,8 +136,8 @@ def test_mute_chat_v2(self, mute_type, time_delta, setup_two_unprivileged_nodes) # MuteType.UNMUTED.value, ], ) - def test_unmute_mute_chat_v2_till_unmuted(self, mute_type, setup_two_unprivileged_nodes): - self.send_multiple_one_to_one_messages(1) + def test_unmute_mute_chat_v2_till_unmuted(self, mute_type): + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) chat_id = self.receiver.public_key response = self.sender.wakuext_service.mute_chat_v2(chat_id, mute_type) @@ -149,8 +151,8 @@ def test_unmute_mute_chat_v2_till_unmuted(self, mute_type, setup_two_unprivilege chat = response.get("result", {}) assert chat.get("muted", True) is False - def test_clear_history(self, setup_two_unprivileged_nodes): - self.send_multiple_one_to_one_messages(1) + def test_clear_history(self): + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) chat_id = self.receiver.public_key response = self.sender.wakuext_service.chat(chat_id) @@ -158,8 +160,7 @@ def test_clear_history(self, setup_two_unprivileged_nodes): assert isinstance(last_message, dict) response = self.sender.wakuext_service.clear_history(chat_id) - self.sender.verify_json_schema(response, method="wakuext_clearHistory") - + # TODO: Add more assertions on response last_message = response.get("result", {}).get("chats", [])[0].get("lastMessage", -1) assert last_message is None @@ -170,18 +171,18 @@ def test_clear_history(self, setup_two_unprivileged_nodes): (True, dict), ], ) - def test_deactivate_chat(self, preserve_history, expected, setup_two_unprivileged_nodes): - self.send_multiple_one_to_one_messages(1) + def test_deactivate_chat(self, preserve_history, expected): + self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) chat_id = self.receiver.public_key response = self.sender.wakuext_service.deactivate_chat(chat_id, preserve_history) - self.sender.verify_json_schema(response, method="wakuext_deactivateChat") + # TODO: Add more assertions on response chat = response.get("result", {}).get("chats", [])[0] assert chat.get("active", -1) is False assert isinstance(chat.get("lastMessage", -1), expected) - def test_save_chat(self, setup_two_unprivileged_nodes): + def test_save_chat(self): chat_id = "123" response = self.sender.wakuext_service.save_chat(chat_id, active=True) assert response.get("result", -1) is None @@ -191,11 +192,9 @@ def test_save_chat(self, setup_two_unprivileged_nodes): assert chat.get("id", "") == chat_id assert chat.get("active", -1) is True - def test_create_one_to_one_chat(self, setup_two_unprivileged_nodes): + def test_create_one_to_one_chat(self): chat_id = self.receiver.public_key response = self.sender.wakuext_service.create_one_to_one_chat(chat_id, ens_name="") - self.sender.verify_json_schema(response, method="wakuext_createOneToOneChat") - chats = response.get("result", {}).get("chats", []) assert len(chats) == 1 chat = chats[0] diff --git a/tests-functional/tests/test_wakuext_contact_requests.py b/tests-functional/tests/test_wakuext_contact_requests.py index fb71fe79f2..562f4e2448 100644 --- a/tests-functional/tests/test_wakuext_contact_requests.py +++ b/tests-functional/tests/test_wakuext_contact_requests.py @@ -1,17 +1,23 @@ from uuid import uuid4 import pytest -from steps.messenger import MessengerSteps from resources.enums import MessageContentType +from steps.messenger import MessengerSteps @pytest.mark.rpc -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) class TestContactRequests(MessengerSteps): - def test_send_contact_request(self, setup_two_unprivileged_nodes): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile, waku_light_client): + """Initialize two backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client=waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client=waku_light_client) + + def test_send_contact_request(self): message_text = "test_send_contact_request" response = self.sender.wakuext_service.send_contact_request(self.receiver.public_key, message_text) - self.sender.verify_json_schema(response, "wakuext_sendContactRequest") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -24,9 +30,9 @@ def test_send_contact_request(self, setup_two_unprivileged_nodes): assert len(sent_request_messages) == 1, f"Expected one message with contentType {MessageContentType.SYSTEM_MESSAGE_MUTUAL_EVENT_SENT.value}" assert sent_request_messages[0].get("text") == f"You sent a contact request to @{self.receiver.public_key}" - def test_add_contact(self, setup_two_unprivileged_nodes): + def test_add_contact(self): response = self.sender.wakuext_service.add_contact(self.receiver.public_key, self.receiver.display_name) - self.sender.verify_json_schema(response, "wakuext_addContact") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -40,10 +46,10 @@ def test_add_contact(self, setup_two_unprivileged_nodes): assert len(sent_request_messages) == 1, f"Expected one message with contentType {MessageContentType.SYSTEM_MESSAGE_MUTUAL_EVENT_SENT.value}" assert sent_request_messages[0].get("text") == f"You sent a contact request to @{self.receiver.public_key}" - def test_accept_contact_request(self, setup_two_unprivileged_nodes): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() + def test_accept_contact_request(self): + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.accept_contact_request(message_id) - self.sender.verify_json_schema(response, "wakuext_acceptContactRequest") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -61,10 +67,10 @@ def test_accept_contact_request(self, setup_two_unprivileged_nodes): ), f"Expected one message with contentType {MessageContentType.SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED.value}" assert accept_request_messages[0].get("text") == f"You accepted @{self.sender.public_key}'s contact request" - def test_decline_contact_request(self, setup_two_unprivileged_nodes): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() + def test_decline_contact_request(self): + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.decline_contact_request(message_id) - self.sender.verify_json_schema(response, "wakuext_declineContactRequest") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -74,10 +80,10 @@ def test_decline_contact_request(self, setup_two_unprivileged_nodes): assert len(contact_request_messages) == 1, f"Expected one message with contentType {MessageContentType.CONTACT_REQUEST.value}" assert contact_request_messages[0].get("text") == "contact_request" - def test_accept_latest_contact_request_for_contact(self, setup_two_unprivileged_nodes): - self.send_contact_request_and_wait_for_signal_to_be_received() + def test_accept_latest_contact_request_for_contact(self): + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.accept_latest_contact_request_for_contact(self.sender.public_key) - self.sender.verify_json_schema(response, "wakuext_acceptLatestContactRequestForContact") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -95,10 +101,10 @@ def test_accept_latest_contact_request_for_contact(self, setup_two_unprivileged_ ), f"Expected one message with contentType {MessageContentType.SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED.value}" assert accept_request_messages[0].get("text") == f"You accepted @{self.sender.public_key}'s contact request" - def test_dismiss_latest_contact_request_for_contact(self, setup_two_unprivileged_nodes): - self.send_contact_request_and_wait_for_signal_to_be_received() + def test_dismiss_latest_contact_request_for_contact(self): + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.dismiss_latest_contact_request_for_contact(self.sender.public_key) - self.sender.verify_json_schema(response, "wakuext_dismissLatestContactRequestForContact") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -108,19 +114,19 @@ def test_dismiss_latest_contact_request_for_contact(self, setup_two_unprivileged assert len(contact_request_messages) == 1, f"Expected one message with contentType {MessageContentType.CONTACT_REQUEST.value}" assert contact_request_messages[0].get("text") == "contact_request" - def test_get_latest_contact_request_for_contact(self, setup_two_unprivileged_nodes): - self.send_contact_request_and_wait_for_signal_to_be_received() + def test_get_latest_contact_request_for_contact(self): + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.receiver.wakuext_service.get_latest_contact_request_for_contact(self.sender.public_key) - self.sender.verify_json_schema(response, "wakuext_getLatestContactRequestForContact") + # TODO: Add more assertions on response contact_request_message = self.get_message_by_content_type(response, content_type=MessageContentType.CONTACT_REQUEST.value) assert len(contact_request_message) == 1, f"Expected one message with contentType {MessageContentType.CONTACT_REQUEST.value}" assert contact_request_message[0].get("text") == "contact_request" - def test_retract_contact_request(self, setup_two_unprivileged_nodes): - self.send_contact_request_and_wait_for_signal_to_be_received() + def test_retract_contact_request(self): + self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) response = self.sender.wakuext_service.retract_contact_request(self.receiver.public_key) - self.sender.verify_json_schema(response, "wakuext_retractContactRequest") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -133,11 +139,11 @@ def test_retract_contact_request(self, setup_two_unprivileged_nodes): ), f"Expected one message with contentType {MessageContentType.SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED.value}" assert retract_request_messages[0].get("text") == f"You removed @{self.receiver.public_key} as a contact" - def test_remove_contact(self, setup_two_unprivileged_nodes): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() + def test_remove_contact(self): + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) self.accept_contact_request_and_wait_for_signal_to_be_received(message_id) response = self.sender.wakuext_service.remove_contact(self.receiver.public_key) - self.sender.verify_json_schema(response, "wakuext_removeContact") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" @@ -150,12 +156,12 @@ def test_remove_contact(self, setup_two_unprivileged_nodes): ), f"Expected one message with contentType {MessageContentType.SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED.value}" assert retract_request_messages[0].get("text") == f"You removed @{self.receiver.public_key} as a contact" - def test_set_contact_local_nickname(self, setup_two_unprivileged_nodes): - message_id = self.send_contact_request_and_wait_for_signal_to_be_received() + def test_set_contact_local_nickname(self): + message_id = self.send_contact_request_and_wait_for_signal_to_be_received(self.sender, self.receiver) self.accept_contact_request_and_wait_for_signal_to_be_received(message_id) nickname = str(uuid4()) response = self.sender.wakuext_service.set_contact_local_nickname(self.receiver.public_key, nickname) - self.sender.verify_json_schema(response, "wakuext_setContactLocalNickname") + # TODO: Add more assertions on response contacts = response.get("result", {}).get("contacts", []) assert len(contacts) >= 1, "Expected response to have at least one contact" diff --git a/tests-functional/tests/test_wakuext_group_chats.py b/tests-functional/tests/test_wakuext_group_chats.py new file mode 100644 index 0000000000..c08cdadd50 --- /dev/null +++ b/tests-functional/tests/test_wakuext_group_chats.py @@ -0,0 +1,198 @@ +from uuid import uuid4 +import pytest +from steps.messenger import MessengerSteps +from resources.enums import MessageContentType + + +@pytest.mark.rpc +class TestCreatePrivateGroups(MessengerSteps): + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + self.make_contacts(self.sender, self.receiver) + + def test_create_group_chat_with_members(self): + private_group_name = f"private_group_{uuid4()}" + create_group_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], private_group_name) + # TODO: Add more assertions on response + + self.get_message_by_content_type( + create_group_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.sender.public_key} created the group {private_group_name}", + )[0] + self.get_message_by_content_type( + create_group_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.sender.public_key} has added @{self.receiver.public_key}", + )[0] + + def test_leave_group_chat(self): + create_group_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"private_group_{uuid4()}") + + group_id = create_group_response.get("result", {}).get("chats", [])[0].get("id") + members_before_leave = create_group_response.get("result", {}).get("chats", [])[0].get("members", []) + assert len(members_before_leave) == 2 + assert self.sender.public_key in str(members_before_leave) + + leave_group_response = self.sender.wakuext_service.leave_group_chat(group_id, True) + # TODO: Add more assertions on response + + self.get_message_by_content_type( + leave_group_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.sender.public_key} left the group", + )[0] + + members_after_leave = leave_group_response.get("result", {}).get("chats", [])[0].get("members", []) + assert len(members_after_leave) == 1 + assert self.sender.public_key not in str(members_after_leave) + + def test_send_group_chat_invitation_request(self, backend_new_profile): + third_node = backend_new_profile("third_node") + self.make_contacts(self.sender, third_node) + + create_group_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"private_group_{uuid4()}") + group_id = create_group_response.get("result", {}).get("chats", [])[0].get("id") + + invitation_message = f"Please join {uuid4()}" + invite_response = self.sender.wakuext_service.send_group_chat_invitation_request(group_id, third_node.public_key, invitation_message) + # TODO: Add more assertions on response + + invitations = invite_response.get("result", {}).get("invitations", []) + assert len(invitations) == 1 + assert invitations[0].get("chatId", "") == group_id + assert invitations[0].get("from", "") == self.sender.public_key + assert invitations[0].get("introductionMessage", "") == invitation_message + assert invitations[0].get("state", 0) == 1 + + def test_create_group_chat_from_invitation(self): + invitation_group = f"Group name {uuid4()}" + group_id = str(uuid4()) + create_from_inv = self.receiver.wakuext_service.create_group_chat_from_invitation(invitation_group, group_id, self.sender.public_key) + # TODO: Add more assertions on response + + chats = create_from_inv.get("result", {}).get("chats", []) + assert len(chats) == 1 + assert chats[0].get("id", "") == group_id + assert chats[0].get("invitationAdmin", "") == self.sender.public_key + assert chats[0].get("name", "") == invitation_group + + def test_add_members_to_group_chat(self, backend_new_profile): + third_node = backend_new_profile("third_node") + self.make_contacts(self.sender, third_node) + + create_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"add_members_group_{uuid4()}") + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + add_members_response = self.sender.wakuext_service.add_members_to_group_chat(group_id, [third_node.public_key]) + # TODO: Add more assertions on response + + self.get_message_by_content_type( + add_members_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.sender.public_key} has added @{third_node.public_key}", + )[0] + + def test_remove_member_from_group_chat(self): + create_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"group_{uuid4()}") + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + remove_member_response = self.sender.wakuext_service.remove_member_from_group_chat(group_id, self.receiver.public_key) + # TODO: Add more assertions on response + + self.get_message_by_content_type( + remove_member_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.receiver.public_key} left the group", + )[0] + + def test_remove_members_from_group_chat(self, backend_new_profile): + third_node = backend_new_profile("third_node") + self.make_contacts(self.sender, third_node) + + create_response = self.sender.wakuext_service.create_group_chat_with_members( + [self.receiver.public_key, third_node.public_key], f"add_members_group_{uuid4()}" + ) + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + remove_members_response = self.sender.wakuext_service.remove_members_from_group_chat( + group_id, [self.receiver.public_key, third_node.public_key] + ) + # TODO: Add more assertions on response + + self.get_message_by_content_type( + remove_members_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.receiver.public_key} left the group", + )[0] + self.get_message_by_content_type( + remove_members_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{third_node.public_key} left the group", + )[0] + + def test_confirm_joining_group(self): + create_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"confirm_join_group_{uuid4()}") + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + confirm_response = self.sender.wakuext_service.confirm_joining_group(group_id) + # TODO: Add more assertions on response + + chats = confirm_response.get("result", {}).get("chats", []) + assert len(chats) == 1 + assert len(chats[0].get("members", [])) == 2 + + def test_change_group_chat_name(self): + initial_group_name = "initial_group_name" + create_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], initial_group_name) + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + new_group_name = f"new_group_name_{uuid4()}" + change_name_response = self.sender.wakuext_service.change_group_chat_name(group_id, new_group_name) + # TODO: Add more assertions on response + + self.get_message_by_content_type( + change_name_response, + content_type=MessageContentType.SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP.value, + message_pattern=f"@{self.sender.public_key} changed the group's name to {new_group_name}", + )[0] + + chats = change_name_response.get("result", {}).get("chats", []) + assert chats[0].get("name", "") == new_group_name + + @pytest.mark.skip(reason="waiting for https://github.com/status-im/status-go/issues/6752 resolution") + def test_get_group_chat_invitations(self, backend_new_profile): + third_node = backend_new_profile("third_node") + self.make_contacts(self.sender, third_node) + + create_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"group_{uuid4()}") + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + self.sender.wakuext_service.send_group_chat_invitation_request(group_id, third_node.public_key, f"Please join {uuid4()}") + third_node.wakuext_service.get_group_chat_invitations() + # TODO: Add more assertions on response + + def test_send_group_chat_invitation_rejection(self, backend_new_profile): + third_node = backend_new_profile("third_node") + self.make_contacts(self.sender, third_node) + + create_response = self.sender.wakuext_service.create_group_chat_with_members([self.receiver.public_key], f"group_{uuid4()}") + group_id = create_response.get("result", {}).get("chats", [])[0].get("id") + + invitation_message = f"Please join {uuid4()}" + send_invitation_response = self.sender.wakuext_service.send_group_chat_invitation_request(group_id, third_node.public_key, invitation_message) + + invitation_id = send_invitation_response.get("result", {}).get("invitations", [])[0].get("id") + reject_response = self.sender.wakuext_service.send_group_chat_invitation_rejection(invitation_id) + # TODO: Add more assertions on response + + invitations = reject_response.get("result", {}).get("invitations", []) + assert len(invitations) == 1 + assert invitations[0].get("chatId", "") == group_id + assert invitations[0].get("from", "") == self.sender.public_key + assert invitations[0].get("introductionMessage", "") == invitation_message + assert invitations[0].get("state", 0) == 2 diff --git a/tests-functional/tests/test_wakuext_message_reactions.py b/tests-functional/tests/test_wakuext_message_reactions.py index cbefda7a59..54fa06abae 100644 --- a/tests-functional/tests/test_wakuext_message_reactions.py +++ b/tests-functional/tests/test_wakuext_message_reactions.py @@ -7,17 +7,23 @@ from steps.messenger import MessengerSteps -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) @pytest.mark.rpc class TestMessageReactions(MessengerSteps): - def test_one_to_one_message_reactions(self, setup_two_unprivileged_nodes): - self.make_contacts() + + @pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) + def test_one_to_one_message_reactions(self, backend_new_profile, waku_light_client): + """Test message reactions with different wakuV2LightClient configurations""" + # Initialize two backends (sender and receiver) for this test + self.sender = backend_new_profile("sender", waku_light_client=waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client=waku_light_client) + + self.make_contacts(self.sender, self.receiver) response = self.sender.wakuext_service.send_one_to_one_message(self.receiver.public_key, "test_message") message = self.get_message_by_content_type(response, content_type=MessageContentType.TEXT_PLAIN.value)[0] message_id, sender_chat_id = message["id"], message["chatId"] receiver_chat_id = self.receiver.wakuext_service.rpc_request(method="chats").json()["result"][0]["id"] response = self.receiver.wakuext_service.rpc_request(method="sendEmojiReaction", params=[receiver_chat_id, message_id, 1]).json() - self.sender.verify_json_schema(response, "wakuext_sendEmojiReaction") + # TODO: Add more assertions on response self.sender.find_signal_containing_pattern( SignalType.MESSAGES_NEW.value, event_pattern="emojiReactions", @@ -28,7 +34,7 @@ def test_one_to_one_message_reactions(self, setup_two_unprivileged_nodes): method="emojiReactionsByChatIDMessageID", params=[sender_chat_id, message_id], ).json() - self.sender.verify_json_schema(response, "wakuext_emojiReactionsByChatIDMessageID") + # TODO: Add more assertions on response result = response["result"] assert all( ( @@ -46,7 +52,7 @@ def test_one_to_one_message_reactions(self, setup_two_unprivileged_nodes): emoji_id, ], ).json() - self.sender.verify_json_schema(response, "wakuext_sendEmojiReactionRetraction") + # TODO: Add more assertions on response assert response["result"]["chats"][0]["id"] == receiver_chat_id self.sender.find_signal_containing_pattern( @@ -83,7 +89,7 @@ def test_one_to_one_message_reactions(self, setup_two_unprivileged_nodes): ) time.sleep(10) response = self.sender.wakuext_service.rpc_request(method="emojiReactionsByChatID", params=[sender_chat_id, None, 20]).json() - self.sender.verify_json_schema(response, "wakuext_emojiReactionsByChatID") + # TODO: Add more assertions on response result = response["result"] assert len(result) == 2 for item in result: diff --git a/tests-functional/tests/test_wakuext_messages_fetching.py b/tests-functional/tests/test_wakuext_messages_fetching.py index 4fe9cd05d0..4c755b8adf 100644 --- a/tests-functional/tests/test_wakuext_messages_fetching.py +++ b/tests-functional/tests/test_wakuext_messages_fetching.py @@ -3,24 +3,30 @@ from steps.messenger import MessengerSteps -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) @pytest.mark.rpc +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) class TestFetchingChatMessages(MessengerSteps): - def test_chat_messages(self, setup_two_unprivileged_nodes): - sent_texts, _ = self.send_multiple_one_to_one_messages(1) + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile, waku_light_client): + """Initialize two backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client=waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client=waku_light_client) + + def test_chat_messages(self): + sent_texts, _ = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.chat_messages(sender_chat_id) - - self.sender.verify_json_schema(response, method="wakuext_chatMessages") + # TODO: Add more assertions on response messages = response.get("result", {}).get("messages", []) assert len(messages) == 1 actual_text = messages[0].get("text", "") assert actual_text == sent_texts[0] - def test_chat_messages_with_pagination(self, setup_two_unprivileged_nodes): - sent_texts, _ = self.send_multiple_one_to_one_messages(5) + def test_chat_messages_with_pagination(self): + sent_texts, _ = self.send_multiple_one_to_one_messages(5, sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key # Page 1 @@ -44,13 +50,12 @@ def test_chat_messages_with_pagination(self, setup_two_unprivileged_nodes): assert messages_page2[1].get("text", "") == sent_texts[0] assert cursor2 == "" - def test_message_by_message_id(self, setup_two_unprivileged_nodes): - sent_texts, responses = self.send_multiple_one_to_one_messages(1) + def test_message_by_message_id(self): + sent_texts, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") response = self.sender.wakuext_service.message_by_message_id(message_id) - - self.sender.verify_json_schema(response, method="wakuext_messageByMessageID") + # TODO: Add more assertions on response actual_text = response.get("result", {}).get("text", "") assert actual_text == sent_texts[0] @@ -63,38 +68,37 @@ def test_message_by_message_id(self, setup_two_unprivileged_nodes): # ("TEST_MESSAGE_", True, 0), # Skipped due to https://github.com/status-im/status-go/issues/6359 ], ) - def test_all_messages_from_chat_which_match_term(self, searchTerm, caseSensitive, expectedCount, setup_two_unprivileged_nodes): - self.send_multiple_one_to_one_messages(3) + def test_all_messages_from_chat_which_match_term(self, searchTerm, caseSensitive, expectedCount): + self.send_multiple_one_to_one_messages(3, sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.all_messages_from_chat_which_match_term(sender_chat_id, searchTerm, caseSensitive) - - self.sender.verify_json_schema(response, method="wakuext_allMessagesFromChatWhichMatchTerm") + # TODO: Add more assertions on response messages = response.get("result", {}).get("messages", []) assert len(messages) == expectedCount - def test_all_messages_from_chats_and_communities_which_match_term(self, setup_two_unprivileged_nodes): + def test_all_messages_from_chats_and_communities_which_match_term(self): # One to one - self.make_contacts() - sent_texts_one_to_one, _ = self.send_multiple_one_to_one_messages(1) + self.make_contacts(self.sender, self.receiver) + sent_texts_one_to_one, _ = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) one_to_one_chat_id = self.receiver.public_key # Group - private_group_chat_id = self.join_private_group() + private_group_chat_id = self.join_private_group(admin=self.sender, member=self.receiver) text_group = "test_message_group" response = self.sender.wakuext_service.send_group_chat_message(private_group_chat_id, text_group) # Community self.create_community(self.sender) - community_chat_id = self.join_community(self.receiver) + community_chat_id = self.join_community(member=self.receiver, admin=self.sender) text_community = "test_message_community" response = self.sender.wakuext_service.send_chat_message(community_chat_id, text_community) response = self.sender.wakuext_service.all_messages_from_chats_and_communities_which_match_term( [self.community_id], [one_to_one_chat_id, private_group_chat_id], "TEST_MESSAGE", False ) - self.sender.verify_json_schema(response, method="wakuext_allMessagesFromChatsAndCommunitiesWhichMatchTerm") + # TODO: Add more assertions on response messages = response.get("result", {}).get("messages", []) actual_texts = [message.get("text", "") for message in messages] @@ -103,19 +107,19 @@ def test_all_messages_from_chats_and_communities_which_match_term(self, setup_tw assert text_community in actual_texts @pytest.mark.skip(reason="Skipped due to https://github.com/status-im/status-go/issues/6359") - def test_all_messages_from_chats_and_communities_which_match_term_case_sensitive(self, setup_two_unprivileged_nodes): + def test_all_messages_from_chats_and_communities_which_match_term_case_sensitive(self): # One to one - self.make_contacts() - _, _ = self.send_multiple_one_to_one_messages(1) + self.make_contacts(self.sender, self.receiver) + _, _ = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) one_to_one_chat_id = self.receiver.public_key # Group - private_group_chat_id = self.join_private_group() + private_group_chat_id = self.join_private_group(admin=self.sender, member=self.receiver) self.sender.wakuext_service.send_group_chat_message(private_group_chat_id, "test_message_group") # Community self.create_community(self.sender) - community_chat_id = self.join_community(self.receiver) + community_chat_id = self.join_community(member=self.receiver, admin=self.sender) self.sender.wakuext_service.send_chat_message(community_chat_id, "test_message_community") response = self.sender.wakuext_service.all_messages_from_chats_and_communities_which_match_term( @@ -125,16 +129,16 @@ def test_all_messages_from_chats_and_communities_which_match_term_case_sensitive messages = response.get("result", {}).get("messages", []) assert len(messages) == 0 - def test_first_unseen_message(self, setup_two_unprivileged_nodes): - _, responses = self.send_multiple_one_to_one_messages(1) + def test_first_unseen_message(self): + _, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") response = self.sender.wakuext_service.mark_message_as_unread(sender_chat_id, message_id) - self.sender.verify_json_schema(response, method="wakuext_markMessageAsUnread") + # TODO: Add more assertions on response response = self.sender.wakuext_service.first_unseen_message_id(sender_chat_id) - self.sender.verify_json_schema(response, method="wakuext_firstUnseenMessageID") + # TODO: Add more assertions on response result = response.get("result", "") assert result == message_id diff --git a/tests-functional/tests/test_wakuext_messages_interacting.py b/tests-functional/tests/test_wakuext_messages_interacting.py index 19680e8fc2..e012408f11 100644 --- a/tests-functional/tests/test_wakuext_messages_interacting.py +++ b/tests-functional/tests/test_wakuext_messages_interacting.py @@ -1,16 +1,20 @@ import pytest - from steps.messenger import MessengerSteps - from clients.services.wakuext import SendPinMessagePayload -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) @pytest.mark.rpc +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) class TestInteractingWithChatMessages(MessengerSteps): - def test_pinned_messages(self, setup_two_unprivileged_nodes): - sent_texts, responses = self.send_multiple_one_to_one_messages(1) + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile, waku_light_client): + """Initialize two backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client=waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client=waku_light_client) + + def test_pinned_messages(self): + sent_texts, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) # pin message = responses[0].get("result", {}).get("messages", [])[0] @@ -21,11 +25,11 @@ def test_pinned_messages(self, setup_two_unprivileged_nodes): } response = self.sender.wakuext_service.send_pin_message(pin_message_payload) - self.sender.verify_json_schema(response, method="wakuext_sendPinMessage") + # TODO: Add more assertions on response sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.chat_pinned_messages(sender_chat_id) - self.sender.verify_json_schema(response, method="wakuext_chatPinnedMessages") + # TODO: Add more assertions on response pinned_messages = response.get("result", {}).get("pinnedMessages", []) assert len(pinned_messages) == 1 @@ -40,8 +44,8 @@ def test_pinned_messages(self, setup_two_unprivileged_nodes): pinned_messages = response.get("result", {}).get("pinnedMessages", []) assert pinned_messages is None - def test_pinned_messages_with_pagination(self, setup_two_unprivileged_nodes): - sent_texts, responses = self.send_multiple_one_to_one_messages(5) + def test_pinned_messages_with_pagination(self): + sent_texts, responses = self.send_multiple_one_to_one_messages(5, sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key for response in responses: @@ -74,8 +78,8 @@ def test_pinned_messages_with_pagination(self, setup_two_unprivileged_nodes): assert pinned_messages_page2[1].get("message", {}).get("text", "") == sent_texts[0] assert cursor2 == "" - def test_edit_message(self, setup_two_unprivileged_nodes): - sent_texts, responses = self.send_multiple_one_to_one_messages(1) + def test_edit_message(self): + sent_texts, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") response = self.sender.wakuext_service.message_by_message_id(message_id) @@ -84,37 +88,37 @@ def test_edit_message(self, setup_two_unprivileged_nodes): new_text = "test_message_edited" response = self.sender.wakuext_service.edit_message(message_id, new_text) - self.sender.verify_json_schema(response, method="wakuext_editMessage") + # TODO: Add more assertions on response response = self.sender.wakuext_service.message_by_message_id(message_id) actual_text = response.get("result", {}).get("text", "") assert actual_text == new_text - def test_delete_message(self, setup_two_unprivileged_nodes): - _, responses = self.send_multiple_one_to_one_messages(1) + def test_delete_message(self): + _, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") response = self.sender.wakuext_service.message_by_message_id(message_id) assert response.get("result", {}) != {} response = self.sender.wakuext_service.delete_message(message_id) - self.sender.verify_json_schema(response, method="wakuext_deleteMessage") + # TODO: Add more assertions on response - response = self.sender.wakuext_service.message_by_message_id(message_id, skip_validation=True) + response = self.sender.wakuext_service.message_by_message_id(message_id) error_code = response.get("error", {}).get("code", 0) error_message = response.get("error", {}).get("message", "") assert error_code == -32000 assert error_message == "record not found" - def test_delete_message_and_send(self, setup_two_unprivileged_nodes): - _, responses = self.send_multiple_one_to_one_messages(1) + def test_delete_message_and_send(self): + _, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") response = self.sender.wakuext_service.message_by_message_id(message_id) assert response.get("result", {}) != {} response = self.sender.wakuext_service.delete_message_and_send(message_id) - self.sender.verify_json_schema(response, method="wakuext_deleteMessageAndSend") + # TODO: Add more assertions on response removed_messages = response.get("result", {}).get("removedMessages", []) assert len(removed_messages) == 1 assert removed_messages[0].get("messageId") == message_id @@ -124,8 +128,8 @@ def test_delete_message_and_send(self, setup_two_unprivileged_nodes): assert message.get("id", "") == message_id assert message.get("deleted", None) is True - def test_delete_messages_by_chat_id(self, setup_two_unprivileged_nodes): - _, _ = self.send_multiple_one_to_one_messages(3) + def test_delete_messages_by_chat_id(self): + _, _ = self.send_multiple_one_to_one_messages(3, sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.chat_messages(sender_chat_id) @@ -133,14 +137,14 @@ def test_delete_messages_by_chat_id(self, setup_two_unprivileged_nodes): assert len(messages) == 3 response = self.sender.wakuext_service.delete_messages_by_chat_id(sender_chat_id) - self.sender.verify_json_schema(response, method="wakuext_deleteMessagesByChatID") + # TODO: Add more assertions on response response = self.sender.wakuext_service.chat_messages(sender_chat_id) messages = response.get("result", {}).get("messages", []) assert messages is None - def test_delete_message_for_me_and_sync(self, setup_two_unprivileged_nodes): - _, responses = self.send_multiple_one_to_one_messages(1) + def test_delete_message_for_me_and_sync(self): + _, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") local_chat_id = responses[0].get("result", {}).get("messages", [])[0].get("localChatId", "") @@ -148,7 +152,7 @@ def test_delete_message_for_me_and_sync(self, setup_two_unprivileged_nodes): assert response.get("result", {}) != {} response = self.sender.wakuext_service.delete_message_for_me_and_sync(local_chat_id, message_id) - self.sender.verify_json_schema(response, method="wakuext_deleteMessageForMeAndSync") + # TODO: Add more assertions on response response = self.sender.wakuext_service.message_by_message_id(message_id) message = response.get("result", {}) @@ -157,13 +161,13 @@ def test_delete_message_for_me_and_sync(self, setup_two_unprivileged_nodes): # TODO: assert sync action - def test_update_message_outgoing_status(self, setup_two_unprivileged_nodes): - _, responses = self.send_multiple_one_to_one_messages(1) + def test_update_message_outgoing_status(self): + _, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") new_status = "delivered" response = self.sender.wakuext_service.update_message_outgoing_status(message_id, new_status) - self.sender.verify_json_schema(response, method="wakuext_updateMessageOutgoingStatus") + # TODO: Add more assertions on response response = self.sender.wakuext_service.message_by_message_id(message_id) outgoing_status = response.get("result", {}).get("outgoingStatus", "") diff --git a/tests-functional/tests/test_wakuext_messages_light_client.py b/tests-functional/tests/test_wakuext_messages_light_client.py deleted file mode 100644 index 407f3416d6..0000000000 --- a/tests-functional/tests/test_wakuext_messages_light_client.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest -from steps.messenger import MessengerSteps - - -@pytest.mark.rpc -@pytest.mark.skip -@pytest.mark.usefixtures("setup_two_privileged_nodes") -class TestLightClientMessaging(MessengerSteps): - - @pytest.fixture(scope="function", autouse=False) - def setup_two_unprivileged_nodes(self, request): - request.cls.sender = self.sender = self.initialize_backend(self.await_signals, False) - request.cls.receiver = self.receiver = self.initialize_backend(self.await_signals, False) - for user in self.sender, self.receiver: - key_uid = user.node_login_event["event"]["account"]["key-uid"] - user.wakuext_service.set_light_client(True) - user.logout() - user.wait_for_logout() - user.login(key_uid) - user.prepare_wait_for_signal("node.login", 1) - user.wait_for_login() diff --git a/tests-functional/tests/test_wakuext_messages_sending.py b/tests-functional/tests/test_wakuext_messages_sending.py index a71be90c63..d871d65578 100644 --- a/tests-functional/tests/test_wakuext_messages_sending.py +++ b/tests-functional/tests/test_wakuext_messages_sending.py @@ -7,12 +7,19 @@ from steps.messenger import MessengerSteps -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) @pytest.mark.rpc +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) class TestSendingChatMessages(MessengerSteps): - def test_send_one_to_one_message(self, setup_two_unprivileged_nodes): - sent_texts, responses = self.send_multiple_one_to_one_messages(1) - self.receiver.verify_json_schema(responses[0], method="wakuext_sendOneToOneMessage") + + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile, waku_light_client): + """Initialize two backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client=waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client=waku_light_client) + + def test_send_one_to_one_message(self): + sent_texts, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) + # TODO: Add more assertions on response chat = responses[0]["result"]["chats"][0] assert chat["id"] == self.receiver.public_key @@ -24,13 +31,13 @@ def test_send_one_to_one_message(self, setup_two_unprivileged_nodes): actual_text = messages[0].get("text", "") assert actual_text == sent_texts[0] - def test_send_chat_message_community(self, setup_two_unprivileged_nodes): + def test_send_chat_message_community(self): self.create_community(self.sender) - community_chat_id = self.join_community(self.receiver) + community_chat_id = self.join_community(member=self.receiver, admin=self.sender) text = "test_message" response = self.sender.wakuext_service.send_chat_message(community_chat_id, text) - self.sender.verify_json_schema(response, method="wakuext_sendChatMessage") + # TODO: Add more assertions on response response = self.sender.wakuext_service.chat_messages(community_chat_id) messages = response.get("result", {}).get("messages", []) @@ -38,9 +45,9 @@ def test_send_chat_message_community(self, setup_two_unprivileged_nodes): actual_text = messages[0].get("text", "") assert actual_text == text - def test_send_chat_message_private_group(self, setup_two_unprivileged_nodes): - self.make_contacts() - private_group_id = self.join_private_group() + def test_send_chat_message_private_group(self): + self.make_contacts(self.sender, self.receiver) + private_group_id = self.join_private_group(admin=self.sender, member=self.receiver) text = "test_message" response = self.sender.wakuext_service.send_chat_message(private_group_id, text) @@ -50,16 +57,16 @@ def test_send_chat_message_private_group(self, setup_two_unprivileged_nodes): actual_text = expected_message.get("text", "") assert actual_text == text - def test_send_chat_messages_same_chat(self, setup_two_unprivileged_nodes): + def test_send_chat_messages_same_chat(self): self.create_community(self.sender) - community_chat_id = self.join_community(self.receiver) + community_chat_id = self.join_community(member=self.receiver, admin=self.sender) payload = [ SendChatMessagePayload(chat_id=community_chat_id, text=f"test_message_{i}", content_type=MessageContentType.TEXT_PLAIN.value) for i in range(5) ] response = self.sender.wakuext_service.send_chat_messages(payload) - self.sender.verify_json_schema(response, method="wakuext_sendChatMessage") # the same schema as for sendChatMessage + # TODO: Add more assertions on response response = self.sender.wakuext_service.chat_messages(community_chat_id) messages = response.get("result", {}).get("messages", []) @@ -70,14 +77,14 @@ def test_send_chat_messages_same_chat(self, setup_two_unprivileged_nodes): expected_texts.reverse() assert actual_texts == expected_texts - def test_send_chat_messages_different_chats(self, setup_two_unprivileged_nodes): + def test_send_chat_messages_different_chats(self): # Group - self.make_contacts() - private_group_chat_id = self.join_private_group() + self.make_contacts(self.sender, self.receiver) + private_group_chat_id = self.join_private_group(admin=self.sender, member=self.receiver) # Community self.create_community(self.sender) - community_chat_id = self.join_community(self.receiver) + community_chat_id = self.join_community(member=self.receiver, admin=self.sender) payload = [ SendChatMessagePayload(chat_id=private_group_chat_id, text="test_message_group", content_type=MessageContentType.TEXT_PLAIN.value), @@ -90,13 +97,13 @@ def test_send_chat_messages_different_chats(self, setup_two_unprivileged_nodes): messages = response.get("result", {}).get("messages", []) assert len(messages) == 2 - def test_send_group_message(self, setup_two_unprivileged_nodes): - self.make_contacts() - private_group_id = self.join_private_group() + def test_send_group_message(self): + self.make_contacts(self.sender, self.receiver) + private_group_id = self.join_private_group(admin=self.sender, member=self.receiver) text = "test_message_group" response = self.sender.wakuext_service.send_group_chat_message(private_group_id, text) - self.sender.verify_json_schema(response, method="wakuext_sendGroupChatMessage") + # TODO: Add more assertions on response response = self.sender.wakuext_service.chat_messages(private_group_id) expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.TEXT_PLAIN.value)[0] @@ -106,10 +113,10 @@ def test_send_group_message(self, setup_two_unprivileged_nodes): # Using delete_message is a workaround that might be considered an incorrect behaviour # TODO: create more realistic scenario where the message is intercepted in the network and not delivered, # use community messages to avoid 1-1 and group chats reliability mechanisms on protocol level - def test_resend_one_to_one_message(self, setup_two_unprivileged_nodes): - self.make_contacts() + def test_resend_one_to_one_message(self): + self.make_contacts(self.sender, self.receiver) - _, responses = self.send_multiple_one_to_one_messages(1) + _, responses = self.send_multiple_one_to_one_messages(1, sender=self.sender, receiver=self.receiver) message_id = responses[0].get("result", {}).get("messages", [])[0].get("id", "") receiver_chat_id = self.sender.public_key diff --git a/tests-functional/tests/test_wakuext_messages_transactions.py b/tests-functional/tests/test_wakuext_messages_transactions.py index 7fe45509c9..a4a2d85d5f 100644 --- a/tests-functional/tests/test_wakuext_messages_transactions.py +++ b/tests-functional/tests/test_wakuext_messages_transactions.py @@ -6,8 +6,8 @@ from steps.messenger import MessengerSteps -@pytest.mark.parametrize("setup_two_unprivileged_nodes", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) @pytest.mark.rpc +@pytest.mark.parametrize("waku_light_client", [False, True], indirect=True, ids=["wakuV2LightClient_False", "wakuV2LightClient_True"]) class TestTransactionsChatMessages(MessengerSteps): REQUEST_TRANSACTION_TEXT = "Request transaction" REQUEST_TRANSACTION_DECLINED_TEXT = "Transaction request declined" @@ -16,6 +16,12 @@ class TestTransactionsChatMessages(MessengerSteps): REQUEST_ADDRESS_FOR_TRANSACTION_ACCEPTED_TEXT = "Request address for transaction accepted" TRANSACTION_SENT_TEXT = "Transaction sent" + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile, waku_light_client): + """Initialize two backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender", waku_light_client=waku_light_client) + self.receiver = backend_new_profile("receiver", waku_light_client=waku_light_client) + @pytest.fixture def transaction_data(self): return { @@ -38,12 +44,12 @@ def assert_transaction_command_response(self, response, expected_text: str, para print(parameter, expected_value) assert command_parameters.get(parameter, "") == expected_value - def test_request_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_request_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) response = self.sender.wakuext_service.request_transaction( self.receiver.public_key, transaction_data["value"], transaction_data["contract"], transaction_data["address"] ) - self.receiver.verify_json_schema(response, method="wakuext_requestTransaction") + # TODO: Add more assertions on response self.assert_transaction_command_response( response, @@ -51,8 +57,8 @@ def test_request_transaction(self, transaction_data, setup_two_unprivileged_node [("value", transaction_data["value"]), ("contract", transaction_data["contract"]), ("address", transaction_data["address"])], ) - def test_decline_request_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_decline_request_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.request_transaction( sender_chat_id, transaction_data["value"], transaction_data["contract"], transaction_data["address"] @@ -62,7 +68,7 @@ def test_decline_request_transaction(self, transaction_data, setup_two_unprivile self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=self.REQUEST_TRANSACTION_TEXT, timeout=5) response = self.receiver.wakuext_service.decline_request_transaction(message_id) - self.receiver.verify_json_schema(response, method="wakuext_requestTransaction") # same schema + # TODO: Add more assertions on response self.assert_transaction_command_response( response, @@ -70,8 +76,8 @@ def test_decline_request_transaction(self, transaction_data, setup_two_unprivile [("value", transaction_data["value"]), ("contract", transaction_data["contract"]), ("address", transaction_data["address"])], ) - def test_accept_request_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_accept_request_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.request_transaction( sender_chat_id, transaction_data["value"], transaction_data["contract"], transaction_data["address"] @@ -81,7 +87,7 @@ def test_accept_request_transaction(self, transaction_data, setup_two_unprivileg self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=self.REQUEST_TRANSACTION_TEXT, timeout=5) response = self.receiver.wakuext_service.accept_request_transaction(transaction_data["tx_hash"], message_id, transaction_data["signature"]) - self.receiver.verify_json_schema(response, method="wakuext_acceptRequestTransaction") + # TODO: Add more assertions on response self.assert_transaction_command_response( response, @@ -95,12 +101,12 @@ def test_accept_request_transaction(self, transaction_data, setup_two_unprivileg ], ) - def test_request_address_for_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_request_address_for_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) response = self.sender.wakuext_service.request_address_for_transaction( self.receiver.public_key, transaction_data["from"], transaction_data["value"], transaction_data["contract"] ) - self.receiver.verify_json_schema(response, method="wakuext_requestTransaction") # same schema + # TODO: Add more assertions on response self.assert_transaction_command_response( response, @@ -108,8 +114,8 @@ def test_request_address_for_transaction(self, transaction_data, setup_two_unpri [("value", transaction_data["value"]), ("contract", transaction_data["contract"]), ("from", transaction_data["from"])], ) - def test_decline_request_address_for_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_decline_request_address_for_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.request_address_for_transaction( sender_chat_id, transaction_data["from"], transaction_data["value"], transaction_data["contract"] @@ -121,7 +127,7 @@ def test_decline_request_address_for_transaction(self, transaction_data, setup_t ) response = self.receiver.wakuext_service.decline_request_address_for_transaction(message_id) - self.receiver.verify_json_schema(response, method="wakuext_requestTransaction") # same schema + # TODO: Add more assertions on response self.assert_transaction_command_response( response, @@ -129,8 +135,8 @@ def test_decline_request_address_for_transaction(self, transaction_data, setup_t [("value", transaction_data["value"]), ("contract", transaction_data["contract"])], ) - def test_accept_request_address_for_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_accept_request_address_for_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.request_address_for_transaction( sender_chat_id, transaction_data["from"], transaction_data["value"], transaction_data["contract"] @@ -142,7 +148,7 @@ def test_accept_request_address_for_transaction(self, transaction_data, setup_tw ) response = self.receiver.wakuext_service.accept_request_address_for_transaction(message_id, transaction_data["address"]) - self.receiver.verify_json_schema(response, method="wakuext_requestTransaction") # same schema + # TODO: Add more assertions on response self.assert_transaction_command_response( response, @@ -150,13 +156,13 @@ def test_accept_request_address_for_transaction(self, transaction_data, setup_tw [("value", transaction_data["value"]), ("contract", transaction_data["contract"]), ("address", transaction_data["address"])], ) - def test_send_transaction(self, transaction_data, setup_two_unprivileged_nodes): - self.make_contacts() + def test_send_transaction(self, transaction_data): + self.make_contacts(sender=self.sender, receiver=self.receiver) sender_chat_id = self.receiver.public_key response = self.sender.wakuext_service.send_transaction( sender_chat_id, transaction_data["value"], transaction_data["contract"], transaction_data["tx_hash"], transaction_data["signature"] ) - self.receiver.verify_json_schema(response, method="wakuext_sendTransaction") + # TODO: Add more assertions on response self.assert_transaction_command_response( response, diff --git a/tests-functional/tests/test_wakuext_profile.py b/tests-functional/tests/test_wakuext_profile.py index 49a9c73d95..26e9f426ee 100644 --- a/tests-functional/tests/test_wakuext_profile.py +++ b/tests-functional/tests/test_wakuext_profile.py @@ -5,10 +5,15 @@ from clients.signals import SignalType from steps.messenger import MessengerSteps -from steps.status_backend import StatusBackendSteps -class TestProfile(StatusBackendSteps): +class TestProfile: + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_new_profile): + """Initialize one backend for each test function""" + self.rpc_client = backend_new_profile("rpc_client") + @pytest.mark.parametrize( "method, params", [ @@ -72,7 +77,6 @@ def test_settings_(self, method, setting_name, default_value, changed_value): "method, setting_name, set_value", [ ("settings_saveSetting", "mnemonic-removed?", True), - ("settings_saveSetting", "push-notifications-server-enabled?", True), ("settings_saveSetting", "push-notifications-from-contacts-only?", True), ("settings_saveSetting", "push-notifications-block-mentions?", True), ("settings_saveSetting", "remember-syncing-choice?", True), @@ -129,18 +133,23 @@ def test_omitempty_true_(self, method, setting_name, set_value): assert setting_name not in response.json()["result"] -@pytest.mark.usefixtures("setup_two_unprivileged_nodes") @pytest.mark.rpc class TestUserStatus(MessengerSteps): + @pytest.fixture(autouse=True) + def setup_backends(self, backend_new_profile): + """Initialize two unprivileged backends (sender and receiver) for each test function""" + self.sender = backend_new_profile("sender") + self.receiver = backend_new_profile("receiver") + def test_status_updates(self): - self.make_contacts() + self.make_contacts(sender=self.sender, receiver=self.receiver) statuses = [[1, "text_1"], [2, "text_2"], [3, "text_3"], [4, "text_4"]] for new_status, custom_text in statuses: response = self.sender.wakuext_service.set_user_status(new_status, custom_text) - self.sender.verify_json_schema(response, method="wakuext_setUserStatus") + # TODO: Add more assertions on response self.receiver.find_signal_containing_pattern( SignalType.MESSAGES_NEW.value, @@ -149,7 +158,7 @@ def test_status_updates(self): ) response = self.receiver.wakuext_service.status_updates() - self.sender.verify_json_schema(response, method="wakuext_statusUpdates") + # TODO: Add more assertions on response statusUpdate = response.get("result", {}).get("statusUpdates", [])[0] assert statusUpdate.get("statusType", -1) == new_status diff --git a/tests-functional/tests/test_wakuext_rpc.py b/tests-functional/tests/test_wakuext_rpc.py index 8757638852..c3da3d032e 100644 --- a/tests-functional/tests/test_wakuext_rpc.py +++ b/tests-functional/tests/test_wakuext_rpc.py @@ -1,9 +1,13 @@ import random import pytest -from steps.status_backend import StatusBackendSteps -class TestRpc(StatusBackendSteps): +class TestRpc: + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_new_profile): + """Initialize one backend for each test function""" + self.rpc_client = backend_new_profile("rpc_client") @pytest.mark.parametrize( "method, params", @@ -14,5 +18,5 @@ class TestRpc(StatusBackendSteps): def test_valid_rpc_requests(self, method, params): _id = str(random.randint(1, 8888)) - response = self.rpc_client.rpc_valid_request(method, params, _id) - self.rpc_client.verify_json_schema(response.json(), method) + self.rpc_client.rpc_valid_request(method, params, _id) + # TODO: Add more assertions on response diff --git a/tests-functional/tests/test_wakuext_savedAddress.py b/tests-functional/tests/test_wakuext_savedAddress.py index 1bae2ee0b7..29ac3e6630 100644 --- a/tests-functional/tests/test_wakuext_savedAddress.py +++ b/tests-functional/tests/test_wakuext_savedAddress.py @@ -1,12 +1,14 @@ import pytest -import logging - -from steps.status_backend import StatusBackendSteps @pytest.mark.rpc @pytest.mark.wallet -class TestSavedAddresses(StatusBackendSteps): +class TestSavedAddresses: + + @pytest.fixture(autouse=True) + def setup(self, backend_new_profile): + """Initialize backend for each test function""" + self.rpc_client = backend_new_profile("rpc_client") @pytest.mark.parametrize( "method, params", @@ -55,22 +57,22 @@ class TestSavedAddresses(StatusBackendSteps): def test_add_saved_address(self, method, params): """Test adding saved addresses and verifying their presence in the lists.""" - logging.info("Step: Adding item in mainnet mode") + # Step: Adding item in mainnet mode self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request("wakuext_getSavedAddresses", []) + # TODO: Add more assertions on response - logging.info("Step: Verifying the item is in the saved addresses list") - self.rpc_client.verify_json_schema(response.json(), "wakuext_getSavedAddresses") + # Step: Verifying the item is in the saved addresses list assert any(params[0].items() <= item.items() for item in response.json()["result"]), f"{params[0]['name']} not found in getSavedAddresses" - logging.info("Step: Checking if the item is listed under mainnet saved addresses") + # Step: Checking if the item is listed under mainnet saved addresses response = self.rpc_client.rpc_valid_request("wakuext_getSavedAddressesPerMode", [False]) - self.rpc_client.verify_json_schema(response.json(), "wakuext_getSavedAddressesPerMode") + # TODO: Add more assertions on response assert any( params[0].items() <= item.items() for item in response.json()["result"] ), f"{params[0]['name']} not found in getSavedAddressesPerMode" - logging.info("Step: Ensuring the item is NOT in the testnet saved addresses list") + # Step: Ensuring the item is NOT in the testnet saved addresses list response = self.rpc_client.rpc_valid_request("wakuext_getSavedAddressesPerMode", [True]) assert response.json()["result"] is None, "wakuext_getSavedAddressesPerMode for test mode is not empty" @@ -87,16 +89,16 @@ def test_delete_saved_address(self): } ] - logging.info("Step: Adding item in testnet mode") + # Step: Adding item in testnet mode self.rpc_client.rpc_valid_request("wakuext_upsertSavedAddress", params) - logging.info("Step: Verifying the item exists in testnet saved addresses") + # Step: Verifying the item exists in testnet saved addresses response = self.rpc_client.rpc_valid_request("wakuext_getSavedAddressesPerMode", [is_test]) assert any( params[0].items() <= item.items() for item in response.json()["result"] ), f"{params[0]['name']} not found in getSavedAddressesPerMode" - logging.info("Step: Deleting the item and verifying removal") + # Step: Deleting the item and verifying removal self.rpc_client.rpc_valid_request("wakuext_deleteSavedAddress", [address, is_test]) response = self.rpc_client.rpc_valid_request("wakuext_getSavedAddressesPerMode", [is_test]) assert response.json()["result"] is None, "getSavedAddressesPerMode for test mode is not empty" @@ -127,15 +129,15 @@ def test_remaining_capacity_for_saved_addresses(self): "0x09B69c2F46E7F63131C54BAfae242EEc2C600762", ] - logging.info("Step: Checking remaining capacity") + # Step: Checking remaining capacity response = self.rpc_client.rpc_valid_request("wakuext_remainingCapacityForSavedAddresses", [is_test]) remaining_capacity = response.json()["result"] - logging.info("Step: adding addresses to fill capacity") + # Step: adding addresses to fill capacity for i in range(remaining_capacity): self.rpc_client.rpc_valid_request("wakuext_upsertSavedAddress", [{"address": addresses[i], "name": f"test{i}", "isTest": is_test}]) - logging.info("Step: Verifying that capacity is now 0") + # Step: Verifying that capacity is now 0 response = self.rpc_client.rpc_request("wakuext_remainingCapacityForSavedAddresses", [is_test]) self.rpc_client.verify_is_json_rpc_error(response) assert response.json()["error"]["message"] == "no more save addresses can be added" diff --git a/tests-functional/tests/test_wallet_activity_session.py b/tests-functional/tests/test_wallet_activity_session.py index 07c980d81a..34ce25944e 100644 --- a/tests-functional/tests/test_wallet_activity_session.py +++ b/tests-functional/tests/test_wallet_activity_session.py @@ -5,8 +5,13 @@ import pytest from resources.constants import user_1, user_2 -from steps.wallet import WalletSteps from clients.signals import SignalType +from clients.anvil import Anvil +from clients.smart_contract_runner import SmartContractRunner +from clients.contract_deployers.snt import SNTDeployer, SNTV2_ABI, SNT_TOKEN_CONTROLLER_ABI +from resources.constants import DEPLOYER_ACCOUNT +from clients.contract_deployers.communities import CommunitiesDeployer +from web3 import Web3 EventActivityFilteringDone = "wallet-activity-filtering-done" EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated" @@ -22,7 +27,7 @@ def validate_entry(entry, tx_data): @pytest.mark.rpc @pytest.mark.activity @pytest.mark.xdist_group(name="WalletSteps") -class TestWalletActivitySession(WalletSteps): +class TestWalletActivitySession: await_signals = [ SignalType.NODE_LOGIN.value, SignalType.WALLET.value, @@ -32,7 +37,43 @@ class TestWalletActivitySession(WalletSteps): SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value, ] - def setup_method(self): + @staticmethod + def _token_list_to_token_overrides(token_list): + token_overrides = [] + for token_symbol, token_address in token_list.items(): + token_overrides.append( + { + "symbol": token_symbol, + "address": token_address, + } + ) + return token_overrides + + def get_snt_contract(self): + return self.anvil_client.eth.contract(address=self.snt_deployer.snt_contract_address, abi=SNTV2_ABI) + + def get_snt_token_controller(self): + return self.anvil_client.eth.contract(address=self.snt_deployer.snt_token_controller_address, abi=SNT_TOKEN_CONTROLLER_ABI) + + def mint_snt(self, address, amount): + snt_controller = self.get_snt_token_controller() + tx_hash = snt_controller.functions.generateTokens(address, amount).transact() + self.anvil_client.eth.wait_for_transaction_receipt(tx_hash) + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_recovered_profile): + # Setup contracts and deployers + self.anvil_client = Anvil() + self.anvil_client.eth.default_account = Web3.to_checksum_address(DEPLOYER_ACCOUNT.address) + self.smart_contract_runner = SmartContractRunner() + self.snt_deployer = SNTDeployer(self.smart_contract_runner) + self.communities_deployer = CommunitiesDeployer(self.smart_contract_runner) + self.erc20_token_list = {"SNT": self.snt_deployer.snt_contract_address} + token_overrides = self._token_list_to_token_overrides(self.erc20_token_list) + + # Create backend + self.rpc_client = backend_recovered_profile(name="rpc_client", user=user_1, token_overrides=token_overrides) + self.request_id = str(random.randint(1, 8888)) self.mint_snt(user_1.address, 1000000000000000000000000) @@ -50,8 +91,8 @@ def test_wallet_start_activity_filter_session(self): "tokenID": "ETH", "tokenIDIsOwnerToken": False, "toTokenID": "", - "disabledFromChainIDs": [1, 10, 42161, 8453, 56], - "disabledToChainIDs": [1, 10, 42161, 8453, 56], + "fromChainID": 31337, + "toChainID": 31337, "gasFeeMode": 1, # params for building tx from route "slippagePercentage": 0, @@ -65,7 +106,7 @@ def test_wallet_start_activity_filter_session(self): method = "wallet_startActivityFilterSessionV2" params = [ [user_1.address], - [self.network_id], + [self.rpc_client.network_id], # type: ignore { "period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], diff --git a/tests-functional/tests/test_wallet_assets.py b/tests-functional/tests/test_wallet_assets.py new file mode 100644 index 0000000000..b57f5d0ee5 --- /dev/null +++ b/tests-functional/tests/test_wallet_assets.py @@ -0,0 +1,80 @@ +import uuid as uuid_lib +import json +import pytest +import resources.constants as constants + +from clients.signals import SignalType, WalletEventType +from utils import wallet_utils +from clients.services.wallet import WalletService + + +@pytest.mark.rpc +@pytest.mark.assets +@pytest.mark.wallet +class TestWalletAssets: + await_signals = [ + SignalType.NODE_LOGIN.value, + SignalType.WALLET.value, + SignalType.WALLET_SUGGESTED_ROUTES.value, + SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value, + SignalType.WALLET_ROUTER_SENDING_TRANSACTIONS_STARTED.value, + SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value, + ] + + @pytest.fixture(autouse=True) + def setup_backend(self, backend_recovered_profile): + self.rpc_client = backend_recovered_profile(name="rpc_client", user=constants.user_1) + self.wallet_service = WalletService(self.rpc_client) + self.wallet_service.start_wallet() + + def test_balance_refresh_ticker_after_sending_transaction(self): + uuid = str(uuid_lib.uuid4()) + amount_in = "0xde0b6b3a7640000" + + input_params = { + "uuid": uuid, + "sendType": 0, + "addrFrom": constants.user_1.address, + "addrTo": constants.user_2.address, + "amountIn": amount_in, + "amountOut": "0x0", + "tokenID": "ETH", + "tokenIDIsOwnerToken": False, + "toTokenID": "", + "fromChainID": 31337, + "toChainID": 31337, + "gasFeeMode": 1, + # params for building tx from route + "slippagePercentage": 0, + } + + # Prepare to send tx + routes = wallet_utils.get_suggested_routes(self.rpc_client, **input_params) + assert "Route" in routes, f"No route found: {routes}" + build_tx = wallet_utils.build_transactions_from_route(self.rpc_client, input_params.get("uuid")) + tx_signatures = wallet_utils.sign_messages(self.rpc_client, build_tx["signingDetails"]["hashes"], input_params.get("addrFrom")) + + # Send tx, listen to reload tick signal + method = "wallet_sendRouterTransactionsWithSignatures" + params = [{"uuid": uuid, "Signatures": tx_signatures}] + + def accept_fn(signal): + match signal["event"]["type"]: + case WalletEventType.TRANSACTIONS_PENDING_TRANSACTION_STATUS_CHANGED.value: + tx_status = json.loads(signal["event"]["message"].replace("'", '"')) + return tx_status["status"] == "Success" + case WalletEventType.WALLET_TICK_RELOAD.value: + return True + case _: + return False + + self.rpc_client.prepare_wait_for_signal( + SignalType.WALLET.value, + 2, + accept_fn, + ) + _ = self.rpc_client.rpc_valid_request(method, params) + signals = self.rpc_client.wait_for_signal(SignalType.WALLET.value) + + # Verify + assert len(signals) == 2 diff --git a/tests-functional/tests/test_wallet_rpc.py b/tests-functional/tests/test_wallet_rpc.py index f7098e7dc2..b888661105 100644 --- a/tests-functional/tests/test_wallet_rpc.py +++ b/tests-functional/tests/test_wallet_rpc.py @@ -1,13 +1,14 @@ import random - import pytest - -from steps.status_backend import StatusBackendSteps +from resources.constants import user_1 @pytest.mark.wallet @pytest.mark.rpc -class TestRpc(StatusBackendSteps): +class TestRpc: + @pytest.fixture(autouse=True) + def setup_backend(self, backend_recovered_profile): + self.rpc_client = backend_recovered_profile(name="main_user", user=user_1) @pytest.mark.parametrize( "method, params", @@ -83,5 +84,5 @@ class TestRpc(StatusBackendSteps): def test_(self, method, params): _id = str(random.randint(1, 8888)) - response = self.rpc_client.rpc_valid_request(method, params, _id) - self.rpc_client.verify_json_schema(response.json(), method) + self.rpc_client.rpc_valid_request(method, params, _id) + # TODO: Add more assertions on response diff --git a/tests-functional/tests/test_wallet_signals.py b/tests-functional/tests/test_wallet_signals.py index fdb99bc050..2b5dd41e86 100644 --- a/tests-functional/tests/test_wallet_signals.py +++ b/tests-functional/tests/test_wallet_signals.py @@ -1,31 +1,28 @@ import json import random - import pytest from resources.constants import user_1 -from steps.status_backend import StatusBackendSteps +from clients.signals import SignalType @pytest.mark.wallet @pytest.mark.rpc -class TestWalletSignals(StatusBackendSteps): - - @classmethod - def setup_class(cls, skip_login=False): - cls.await_signals.append("wallet") - super().setup_class() +class TestWalletSignals: + await_signals = [SignalType.NODE_LOGIN.value, SignalType.WALLET.value] - def setup_method(self): + @pytest.fixture(autouse=True) + def setup_backend(self, backend_recovered_profile): self.request_id = str(random.randint(1, 8888)) + self.rpc_client = backend_recovered_profile(name="rpc_client", user=user_1) - @pytest.mark.skip + @pytest.mark.skip # TODO: returns empty response in most of the cases, so needs to be fixed with attention of required signals in signal_response def test_wallet_get_owned_collectibles_async(self): method = "wallet_getOwnedCollectiblesAsync" params = [ 0, [ - self.network_id, + self.rpc_client.network_id, # type: ignore ], [user_1.address], None, @@ -35,8 +32,8 @@ def test_wallet_get_owned_collectibles_async(self): {"fetch-type": 2, "max-cache-age-seconds": 3600}, ] self.rpc_client.rpc_valid_request(method, params, self.request_id) - signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60) - self.rpc_client.verify_json_schema(signal_response, method) + signal_response = self.rpc_client.wait_for_signal(SignalType.WALLET.value, timeout=60) + # TODO: Add more assertions on response assert signal_response["event"]["type"] == "wallet-owned-collectibles-filtering-done" message = json.loads(signal_response["event"]["message"].replace("'", '"')) assert user_1.address in message["ownershipStatus"].keys() diff --git a/tests-functional/utils/config.py b/tests-functional/utils/config.py new file mode 100644 index 0000000000..df75eb6360 --- /dev/null +++ b/tests-functional/utils/config.py @@ -0,0 +1,20 @@ +from typing import List, Iterator +from dataclasses import field + + +class Config: + status_backend_port_range: List[int] = field(default_factory=list) + base_dir: str = "" + + status_backend_urls: Iterator[str] | None = None + password: str = "" # FIXME: remove + docker_project_name: str = "" + docker_image: str = "" + codecov_dir: str = "" + logs_dir: str = "" + benchmark_results_dir: str = "" + logout: bool = False + waku_fleets_config: str = "" + waku_fleet: str = "" + push_fleets_config: str = "" + disable_override_networks: bool = False diff --git a/tests-functional/utils/keys.py b/tests-functional/utils/keys.py new file mode 100644 index 0000000000..00d78e1dfc --- /dev/null +++ b/tests-functional/utils/keys.py @@ -0,0 +1,18 @@ +from hashlib import shake_256 + + +def compress_public_key(public_key): + if not public_key.startswith("0x"): + public_key = "0x" + public_key + if len(public_key) != 132: + raise ValueError("Invalid public key") + x = public_key[4:68] # Extract X coordinate (first 32 bytes after prefix) + y = public_key[68:132] # Extract Y coordinate (last 32 bytes) + prefix = "03" if int(y, 16) % 2 else "02" # Add prefix 02 for even Y, 03 for odd Y + return "0x" + prefix + x + + +def shake256(msg): + h = shake_256() + h.update(msg) + return "0x" + h.hexdigest(64) diff --git a/tests-functional/utils/schema_builder.py b/tests-functional/utils/schema_builder.py deleted file mode 100644 index c77964a0b2..0000000000 --- a/tests-functional/utils/schema_builder.py +++ /dev/null @@ -1,22 +0,0 @@ -import json -import os - -from genson import SchemaBuilder - -from conftest import option - - -class CustomSchemaBuilder(SchemaBuilder): - - def __init__(self, schema_name): - super().__init__() - self.path = f"{option.base_dir}/schemas/{schema_name}" - - def create_schema(self, response_json): - builder = SchemaBuilder() - builder.add_object(response_json) - schema = builder.to_schema() - - os.makedirs(os.path.dirname(self.path), exist_ok=True) - with open(self.path, "w") as file: - json.dump(schema, file, sort_keys=True, indent=4, ensure_ascii=False) diff --git a/tests-functional/utils/wallet_utils.py b/tests-functional/utils/wallet_utils.py index 22001658d5..74bc0b2a15 100644 --- a/tests-functional/utils/wallet_utils.py +++ b/tests-functional/utils/wallet_utils.py @@ -1,15 +1,9 @@ import json import logging -import jsonschema import resources.constants as constants from clients.signals import SignalType, WalletEventType -from conftest import option - - -def verify_json_schema(response, method): - with open(f"{option.base_dir}/schemas/{method}", "r") as schema: - jsonschema.validate(instance=response, schema=json.load(schema)) +from utils.config import Config def get_suggested_routes(rpc_client, **kwargs): @@ -61,7 +55,7 @@ def sign_messages(rpc_client, hashes, address): for hash in hashes: method = "wallet_signMessage" - params = [hash, address, option.password] + params = [hash, address, Config.password] response = rpc_client.rpc_valid_request(method, params) @@ -80,17 +74,6 @@ def sign_messages(rpc_client, hashes, address): return tx_signatures -def check_tx_details(rpc_client, tx_hash, network_id, address_to, expected_amount_in): - method = "ethclient_transactionByHash" - params = [network_id, tx_hash] - - response = rpc_client.rpc_valid_request(method, params) - tx_details = response.json()["result"]["tx"] - - assert tx_details["value"] == expected_amount_in - assert tx_details["to"].upper() == address_to.upper() - - def check_fees(fee_mode, base_fee, max_priority_fee_per_gas, max_fee_per_gas, suggested_fee_levels): assert base_fee.startswith("0x") assert max_priority_fee_per_gas.startswith("0x") @@ -169,7 +152,7 @@ def send_router_transactions_with_signatures(rpc_client, uuid, tx_signatures): def send_router_transaction(rpc_client, **kwargs): routes = get_suggested_routes(rpc_client, **kwargs) - assert "Best" in routes, f"No best route found: {routes}" + assert "Route" in routes, f"No route found: {routes}" build_tx = build_transactions_from_route(rpc_client, kwargs.get("uuid")) diff --git a/tests-functional/waku_configs/pushfleetconfig.json b/tests-functional/waku_configs/pushfleetconfig.json new file mode 100644 index 0000000000..ce6d3580d7 --- /dev/null +++ b/tests-functional/waku_configs/pushfleetconfig.json @@ -0,0 +1,3 @@ +[ + "04b67a6ce39b7515b0f531e24afc849290bf6f98de2197c876363bc15ad92a21213fe5c7e0ac25c37920f5a23d92ca268af34ecc8b7c2a0357ea9a10fcd835a44d" +] \ No newline at end of file diff --git a/transactions/addrlock.go b/transactions/addrlock.go index 24940110bd..31db3c3e51 100644 --- a/transactions/addrlock.go +++ b/transactions/addrlock.go @@ -5,7 +5,7 @@ package transactions import ( "sync" - "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/crypto/types" ) // AddrLocker provides locks for addresses diff --git a/transactions/pendingtxtracker.go b/transactions/pendingtxtracker.go index 6176b56ca3..7962da0c4f 100644 --- a/transactions/pendingtxtracker.go +++ b/transactions/pendingtxtracker.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" ethrpc "github.com/ethereum/go-ethereum/rpc" - ethTypes "github.com/status-im/status-go/eth-node/types" + cryptotypes "github.com/status-im/status-go/crypto/types" "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/rpc" @@ -343,7 +343,7 @@ func (tm *PendingTxTracker) updateDBStatus(ctx context.Context, chainID common.C return res, nil } -func (tm *PendingTxTracker) updateTxDetails(txDetails *TxDetails, chainID uint64, txHash ethTypes.Hash) { +func (tm *PendingTxTracker) updateTxDetails(txDetails *TxDetails, chainID uint64, txHash cryptotypes.Hash) { if txDetails == nil { txDetails = &TxDetails{} } @@ -385,7 +385,7 @@ func (tm *PendingTxTracker) emitNotifications(chainID common.ChainID, changes [] Status: change.Status, } - tm.updateTxDetails(&payload.TxDetails, chainID.ToUint(), ethTypes.Hash(change.hash)) + tm.updateTxDetails(&payload.TxDetails, chainID.ToUint(), cryptotypes.Hash(change.hash)) jsonPayload, err := json.Marshal(payload) if err != nil { @@ -704,7 +704,7 @@ func (tm *PendingTxTracker) addPendingAndNotify(transaction *PendingTransaction) } func (tm *PendingTxTracker) notifyPendingTransactionListeners(payload PendingTxUpdatePayload, addresses []eth.Address, timestamp uint64) { - tm.updateTxDetails(&payload.TxDetails, payload.ChainID.ToUint(), ethTypes.Hash(payload.Hash)) + tm.updateTxDetails(&payload.TxDetails, payload.ChainID.ToUint(), cryptotypes.Hash(payload.Hash)) jsonPayload, err := json.Marshal(payload) if err != nil { diff --git a/transactions/rpc_wrapper.go b/transactions/rpc_wrapper.go index 87ea476bf1..d88564e8ae 100644 --- a/transactions/rpc_wrapper.go +++ b/transactions/rpc_wrapper.go @@ -9,7 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/crypto/types" + walletCommon "github.com/status-im/status-go/services/wallet/common" "github.com/status-im/status-go/rpc" ) @@ -48,7 +49,21 @@ func (w *rpcWrapper) SuggestGasPrice(ctx context.Context) (*big.Int, error) { // but it should provide a basis for setting a reasonable default. func (w *rpcWrapper) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { var hex hexutil.Uint64 - err := w.RPCClient.CallContext(ctx, &hex, w.chainID, "eth_estimateGas", toCallArg(msg)) + method := "eth_estimateGas" + if w.chainID == walletCommon.StatusNetworkSepolia { + method = "linea_estimateGas" + var result struct { + GasLimit hexutil.Uint64 `json:"gasLimit"` + } + + err := w.RPCClient.CallContext(ctx, &result, w.chainID, method, walletCommon.ToCallArg(msg)) + if err != nil { + return 0, err + } + return uint64(result.GasLimit), nil + } + + err := w.RPCClient.CallContext(ctx, &hex, w.chainID, method, walletCommon.ToCallArg(msg)) if err != nil { return 0, err } @@ -71,23 +86,3 @@ func (w *rpcWrapper) SendTransaction(ctx context.Context, tx *gethtypes.Transact } return w.SendRawTransaction(ctx, types.EncodeHex(data)) } - -func toCallArg(msg ethereum.CallMsg) interface{} { - arg := map[string]interface{}{ - "from": msg.From, - "to": msg.To, - } - if len(msg.Data) > 0 { - arg["data"] = types.HexBytes(msg.Data) - } - if msg.Value != nil { - arg["value"] = (*hexutil.Big)(msg.Value) - } - if msg.Gas != 0 { - arg["gas"] = hexutil.Uint64(msg.Gas) - } - if msg.GasPrice != nil { - arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) - } - return arg -} diff --git a/transactions/transactor.go b/transactions/transactor.go index 30898e0dd3..b20309dbf4 100644 --- a/transactions/transactor.go +++ b/transactions/transactor.go @@ -17,9 +17,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/status-im/status-go/account" - "github.com/status-im/status-go/eth-node/crypto" - "github.com/status-im/status-go/eth-node/types" + accsmanagement "github.com/status-im/status-go/accounts-management" + "github.com/status-im/status-go/accounts-management/generator" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/params" "github.com/status-im/status-go/rpc" @@ -53,8 +54,8 @@ func (e *ErrBadNonce) Error() string { type TransactorIface interface { NextNonce(ctx context.Context, rpcClient rpc.ClientInterface, chainID uint64, from types.Address) (uint64, error) EstimateGas(network *params.Network, from common.Address, to common.Address, value *big.Int, input []byte) (uint64, error) - SendTransaction(sendArgs wallettypes.SendTxArgs, verifiedAccount *account.SelectedExtKey, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) - SendTransactionWithChainID(chainID uint64, sendArgs wallettypes.SendTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) + SendTransaction(sendArgs wallettypes.SendTxArgs, verifiedAccount *generator.Account, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) + SendTransactionWithChainID(chainID uint64, sendArgs wallettypes.SendTxArgs, lastUsedNonce int64, verifiedAccount *generator.Account) (hash types.Hash, nonce uint64, err error) ValidateAndBuildTransaction(chainID uint64, sendArgs wallettypes.SendTxArgs, lastUsedNonce int64) (tx *gethtypes.Transaction, nonce uint64, err error) AddSignatureToTransaction(chainID uint64, tx *gethtypes.Transaction, sig []byte) (*gethtypes.Transaction, error) SendRawTransaction(chainID uint64, rawTx string) error @@ -124,12 +125,12 @@ func (t *Transactor) EstimateGas(network *params.Network, from common.Address, t } // SendTransaction is an implementation of eth_sendTransaction. It queues the tx to the sign queue. -func (t *Transactor) SendTransaction(sendArgs wallettypes.SendTxArgs, verifiedAccount *account.SelectedExtKey, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) { +func (t *Transactor) SendTransaction(sendArgs wallettypes.SendTxArgs, verifiedAccount *generator.Account, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) { hash, nonce, err = t.validateAndPropagate(t.rpcWrapper, verifiedAccount, sendArgs, lastUsedNonce) return } -func (t *Transactor) SendTransactionWithChainID(chainID uint64, sendArgs wallettypes.SendTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, nonce uint64, err error) { +func (t *Transactor) SendTransactionWithChainID(chainID uint64, sendArgs wallettypes.SendTxArgs, lastUsedNonce int64, verifiedAccount *generator.Account) (hash types.Hash, nonce uint64, err error) { wrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID) hash, nonce, err = t.validateAndPropagate(wrapper, verifiedAccount, sendArgs, lastUsedNonce) return @@ -348,12 +349,16 @@ func (t *Transactor) HashTransaction(args wallettypes.SendTxArgs) (validatedArgs } // make sure that only account which created the tx can complete it -func (t *Transactor) validateAccount(args wallettypes.SendTxArgs, selectedAccount *account.SelectedExtKey) error { +func (t *Transactor) validateAccount(args wallettypes.SendTxArgs, selectedAccount *generator.Account) error { if selectedAccount == nil { - return account.ErrNoAccountSelected + return accsmanagement.ErrNoAccountSelected } - if !bytes.Equal(args.From.Bytes(), selectedAccount.Address.Bytes()) { + if !args.Valid() { + return wallettypes.ErrInvalidSendTxArgs + } + + if !bytes.Equal(args.From.Bytes(), selectedAccount.Address().Bytes()) { return wallettypes.ErrInvalidTxSender } @@ -435,7 +440,7 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args wa return tx, nil } -func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *account.SelectedExtKey, args wallettypes.SendTxArgs, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) { +func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *generator.Account, args wallettypes.SendTxArgs, lastUsedNonce int64) (hash types.Hash, nonce uint64, err error) { symbol := args.Symbol if args.Version == wallettypes.SendTxArgsVersion1 { symbol = args.FromTokenID @@ -451,7 +456,7 @@ func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccoun } chainID := big.NewInt(int64(rpcWrapper.chainID)) - signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(chainID), selectedAccount.AccountKey.PrivateKey) + signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(chainID), selectedAccount.PrivateKey()) if err != nil { return hash, nonce, err } diff --git a/transactions/transactor_test.go b/transactions/transactor_test.go index 8c3cd55106..865526ac5e 100644 --- a/transactions/transactor_test.go +++ b/transactions/transactor_test.go @@ -7,6 +7,9 @@ import ( "testing" "time" + accsmanagement "github.com/status-im/status-go/accounts-management" + "github.com/status-im/status-go/accounts-management/generator" + accstypes "github.com/status-im/status-go/accounts-management/types" "github.com/status-im/status-go/rpc/chain" "github.com/status-im/status-go/rpc/chain/ethclient" "github.com/status-im/status-go/rpc/chain/rpclimiter" @@ -24,9 +27,8 @@ import ( "github.com/ethereum/go-ethereum/rlp" gethrpc "github.com/ethereum/go-ethereum/rpc" - "github.com/status-im/status-go/account" - "github.com/status-im/status-go/eth-node/crypto" - "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/crypto" + "github.com/status-im/status-go/crypto/types" "github.com/status-im/status-go/params" wallet_common "github.com/status-im/status-go/services/wallet/common" "github.com/status-im/status-go/services/wallet/wallettypes" @@ -68,7 +70,6 @@ func (s *TransactorSuite) SetupTest() { UpstreamChainID: chainID, Networks: nil, DB: db, - WalletFeed: nil, } rpcClient, _ := statusRpc.NewClient(config) @@ -102,12 +103,12 @@ var ( testNonce = hexutil.Uint64(10) ) -func (s *TransactorSuite) setupTransactionPoolAPI(args wallettypes.SendTxArgs, returnNonce, resultNonce hexutil.Uint64, account *account.SelectedExtKey, txErr error) { +func (s *TransactorSuite) setupTransactionPoolAPI(args wallettypes.SendTxArgs, returnNonce, resultNonce hexutil.Uint64, account *generator.Account, txErr error) { // Expect calls to gas functions only if there are no user defined values. // And also set the expected gas and gas price for RLP encoding the expected tx. var usedGas hexutil.Uint64 var usedGasPrice *big.Int - s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), gomock.Eq(common.Address(account.Address)), gethrpc.PendingBlockNumber).Return(&returnNonce, nil) + s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), gomock.Eq(common.Address(account.Address())), gethrpc.PendingBlockNumber).Return(&returnNonce, nil) if !args.IsDynamicFeeTx() { if args.GasPrice == nil { usedGasPrice = (*big.Int)(testGasPrice) @@ -129,7 +130,7 @@ func (s *TransactorSuite) setupTransactionPoolAPI(args wallettypes.SendTxArgs, r s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), data).Return(common.Hash{}, txErr) } -func (s *TransactorSuite) rlpEncodeTx(args wallettypes.SendTxArgs, config *params.NodeConfig, account *account.SelectedExtKey, nonce *hexutil.Uint64, gas hexutil.Uint64, gasPrice *big.Int) hexutil.Bytes { +func (s *TransactorSuite) rlpEncodeTx(args wallettypes.SendTxArgs, config *params.NodeConfig, account *generator.Account, nonce *hexutil.Uint64, gas hexutil.Uint64, gasPrice *big.Int) hexutil.Bytes { var txData gethtypes.TxData to := common.Address(*args.To) if args.IsDynamicFeeTx() { @@ -159,7 +160,7 @@ func (s *TransactorSuite) rlpEncodeTx(args wallettypes.SendTxArgs, config *param newTx := gethtypes.NewTx(txData) chainID := big.NewInt(int64(s.nodeConfig.NetworkID)) - signedTx, err := gethtypes.SignTx(newTx, gethtypes.NewLondonSigner(chainID), account.AccountKey.PrivateKey) + signedTx, err := gethtypes.SignTx(newTx, gethtypes.NewLondonSigner(chainID), account.PrivateKey()) s.NoError(err) data, err := signedTx.MarshalBinary() s.NoError(err) @@ -168,10 +169,7 @@ func (s *TransactorSuite) rlpEncodeTx(args wallettypes.SendTxArgs, config *param func (s *TransactorSuite) TestGasValues() { key, _ := gethcrypto.GenerateKey() - selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - AccountKey: &types.Key{PrivateKey: key}, - } + selectedAccount := generator.NewAccount(key, nil) testCases := []struct { name string gas *hexutil.Uint64 @@ -220,9 +218,10 @@ func (s *TransactorSuite) TestGasValues() { for _, testCase := range testCases { s.T().Run(testCase.name, func(t *testing.T) { s.SetupTest() + to := types.HexToAddress(utils.TestConfig.Account2.WalletAddress) args := wallettypes.SendTxArgs{ - From: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - To: account.ToAddress(utils.TestConfig.Account2.WalletAddress), + From: selectedAccount.Address(), + To: &to, Gas: testCase.gas, GasPrice: testCase.gasPrice, MaxFeePerGas: testCase.maxFeePerGas, @@ -237,7 +236,7 @@ func (s *TransactorSuite) TestGasValues() { } } -func (s *TransactorSuite) setupBuildTransactionMocks(args wallettypes.SendTxArgs, account *account.SelectedExtKey) { +func (s *TransactorSuite) setupBuildTransactionMocks(args wallettypes.SendTxArgs, account *accstypes.SelectedExtKey) { s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), gomock.Eq(common.Address(account.Address)), gethrpc.PendingBlockNumber).Return(&testNonce, nil) if !args.IsDynamicFeeTx() && args.GasPrice == nil { @@ -251,14 +250,14 @@ func (s *TransactorSuite) setupBuildTransactionMocks(args wallettypes.SendTxArgs func (s *TransactorSuite) TestBuildAndValidateTransaction() { key, _ := gethcrypto.GenerateKey() - selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - AccountKey: &types.Key{PrivateKey: key}, + selectedAccount := &accstypes.SelectedExtKey{ + Address: types.HexToAddress(utils.TestConfig.Account1.WalletAddress), + AccountKey: &accstypes.Key{PrivateKey: key}, } chainID := s.nodeConfig.NetworkID - fromAddress := account.FromAddress(utils.TestConfig.Account1.WalletAddress) - toAddress := account.ToAddress(utils.TestConfig.Account2.WalletAddress) + fromAddress := types.HexToAddress(utils.TestConfig.Account1.WalletAddress) + toAddress := types.HexToAddress(utils.TestConfig.Account2.WalletAddress) value := (*hexutil.Big)(big.NewInt(10)) expectedGasPrice := (*big.Int)(testGasPrice) @@ -271,7 +270,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { gas := hexutil.Uint64(21000) args := wallettypes.SendTxArgs{ From: fromAddress, - To: toAddress, + To: &toAddress, Gas: &gas, Value: value, MaxFeePerGas: testGasPrice, @@ -291,7 +290,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { s.SetupTest() args := wallettypes.SendTxArgs{ From: fromAddress, - To: toAddress, + To: &toAddress, Value: value, MaxFeePerGas: testGasPrice, MaxPriorityFeePerGas: testGasPrice, @@ -314,7 +313,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { gasPrice := (*hexutil.Big)(big.NewInt(10)) args := wallettypes.SendTxArgs{ From: fromAddress, - To: toAddress, + To: &toAddress, Value: value, Gas: &gas, GasPrice: gasPrice, @@ -332,7 +331,7 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { args := wallettypes.SendTxArgs{ From: fromAddress, - To: toAddress, + To: &toAddress, Value: value, } s.setupBuildTransactionMocks(args, selectedAccount) @@ -346,36 +345,34 @@ func (s *TransactorSuite) TestBuildAndValidateTransaction() { } func (s *TransactorSuite) TestArgsValidation() { + to := types.HexToAddress(utils.TestConfig.Account2.WalletAddress) args := wallettypes.SendTxArgs{ - From: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - To: account.ToAddress(utils.TestConfig.Account2.WalletAddress), + From: types.HexToAddress(utils.TestConfig.Account1.WalletAddress), + To: &to, Data: types.HexBytes([]byte{0x01, 0x02}), Input: types.HexBytes([]byte{0x02, 0x01}), } s.False(args.Valid()) - selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - } + selectedAccount := generator.NewAccount(nil, nil) _, _, err := s.manager.SendTransaction(args, selectedAccount, -1) s.EqualError(err, wallettypes.ErrInvalidSendTxArgs.Error()) } func (s *TransactorSuite) TestAccountMismatch() { + to := types.HexToAddress(utils.TestConfig.Account2.WalletAddress) args := wallettypes.SendTxArgs{ - From: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - To: account.ToAddress(utils.TestConfig.Account2.WalletAddress), + From: types.HexToAddress(utils.TestConfig.Account1.WalletAddress), + To: &to, } var err error // missing account _, _, err = s.manager.SendTransaction(args, nil, -1) - s.EqualError(err, account.ErrNoAccountSelected.Error()) + s.EqualError(err, accsmanagement.ErrNoAccountSelected.Error()) // mismatched accounts - selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(utils.TestConfig.Account2.WalletAddress), - } + selectedAccount := generator.NewAccount(nil, nil) _, _, err = s.manager.SendTransaction(args, selectedAccount, -1) s.EqualError(err, wallettypes.ErrInvalidTxSender.Error()) } diff --git a/vendor/github.com/BurntSushi/toml/.gitignore b/vendor/github.com/BurntSushi/toml/.gitignore deleted file mode 100644 index fe79e3adda..0000000000 --- a/vendor/github.com/BurntSushi/toml/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/toml.test -/toml-test diff --git a/vendor/github.com/BurntSushi/toml/COPYING b/vendor/github.com/BurntSushi/toml/COPYING deleted file mode 100644 index 01b5743200..0000000000 --- a/vendor/github.com/BurntSushi/toml/COPYING +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 TOML authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md deleted file mode 100644 index 3651cfa960..0000000000 --- a/vendor/github.com/BurntSushi/toml/README.md +++ /dev/null @@ -1,120 +0,0 @@ -TOML stands for Tom's Obvious, Minimal Language. This Go package provides a -reflection interface similar to Go's standard library `json` and `xml` packages. - -Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0). - -Documentation: https://godocs.io/github.com/BurntSushi/toml - -See the [releases page](https://github.com/BurntSushi/toml/releases) for a -changelog; this information is also in the git tag annotations (e.g. `git show -v0.4.0`). - -This library requires Go 1.13 or newer; add it to your go.mod with: - - % go get github.com/BurntSushi/toml@latest - -It also comes with a TOML validator CLI tool: - - % go install github.com/BurntSushi/toml/cmd/tomlv@latest - % tomlv some-toml-file.toml - -### Examples -For the simplest example, consider some TOML file as just a list of keys and -values: - -```toml -Age = 25 -Cats = [ "Cauchy", "Plato" ] -Pi = 3.14 -Perfection = [ 6, 28, 496, 8128 ] -DOB = 1987-07-05T05:45:00Z -``` - -Which can be decoded with: - -```go -type Config struct { - Age int - Cats []string - Pi float64 - Perfection []int - DOB time.Time -} - -var conf Config -_, err := toml.Decode(tomlData, &conf) -``` - -You can also use struct tags if your struct field name doesn't map to a TOML key -value directly: - -```toml -some_key_NAME = "wat" -``` - -```go -type TOML struct { - ObscureKey string `toml:"some_key_NAME"` -} -``` - -Beware that like other decoders **only exported fields** are considered when -encoding and decoding; private fields are silently ignored. - -### Using the `Marshaler` and `encoding.TextUnmarshaler` interfaces -Here's an example that automatically parses values in a `mail.Address`: - -```toml -contacts = [ - "Donald Duck ", - "Scrooge McDuck ", -] -``` - -Can be decoded with: - -```go -// Create address type which satisfies the encoding.TextUnmarshaler interface. -type address struct { - *mail.Address -} - -func (a *address) UnmarshalText(text []byte) error { - var err error - a.Address, err = mail.ParseAddress(string(text)) - return err -} - -// Decode it. -func decode() { - blob := ` - contacts = [ - "Donald Duck ", - "Scrooge McDuck ", - ] - ` - - var contacts struct { - Contacts []address - } - - _, err := toml.Decode(blob, &contacts) - if err != nil { - log.Fatal(err) - } - - for _, c := range contacts.Contacts { - fmt.Printf("%#v\n", c.Address) - } - - // Output: - // &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"} - // &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"} -} -``` - -To target TOML specifically you can implement `UnmarshalTOML` TOML interface in -a similar way. - -### More complex usage -See the [`_example/`](/_example) directory for a more complex example. diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go deleted file mode 100644 index 4d38f3bfce..0000000000 --- a/vendor/github.com/BurntSushi/toml/decode.go +++ /dev/null @@ -1,602 +0,0 @@ -package toml - -import ( - "bytes" - "encoding" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "math" - "os" - "reflect" - "strconv" - "strings" - "time" -) - -// Unmarshaler is the interface implemented by objects that can unmarshal a -// TOML description of themselves. -type Unmarshaler interface { - UnmarshalTOML(interface{}) error -} - -// Unmarshal decodes the contents of data in TOML format into a pointer v. -// -// See [Decoder] for a description of the decoding process. -func Unmarshal(data []byte, v interface{}) error { - _, err := NewDecoder(bytes.NewReader(data)).Decode(v) - return err -} - -// Decode the TOML data in to the pointer v. -// -// See [Decoder] for a description of the decoding process. -func Decode(data string, v interface{}) (MetaData, error) { - return NewDecoder(strings.NewReader(data)).Decode(v) -} - -// DecodeFile reads the contents of a file and decodes it with [Decode]. -func DecodeFile(path string, v interface{}) (MetaData, error) { - fp, err := os.Open(path) - if err != nil { - return MetaData{}, err - } - defer fp.Close() - return NewDecoder(fp).Decode(v) -} - -// Primitive is a TOML value that hasn't been decoded into a Go value. -// -// This type can be used for any value, which will cause decoding to be delayed. -// You can use [PrimitiveDecode] to "manually" decode these values. -// -// NOTE: The underlying representation of a `Primitive` value is subject to -// change. Do not rely on it. -// -// NOTE: Primitive values are still parsed, so using them will only avoid the -// overhead of reflection. They can be useful when you don't know the exact type -// of TOML data until runtime. -type Primitive struct { - undecoded interface{} - context Key -} - -// The significand precision for float32 and float64 is 24 and 53 bits; this is -// the range a natural number can be stored in a float without loss of data. -const ( - maxSafeFloat32Int = 16777215 // 2^24-1 - maxSafeFloat64Int = int64(9007199254740991) // 2^53-1 -) - -// Decoder decodes TOML data. -// -// TOML tables correspond to Go structs or maps; they can be used -// interchangeably, but structs offer better type safety. -// -// TOML table arrays correspond to either a slice of structs or a slice of maps. -// -// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the -// local timezone. -// -// [time.Duration] types are treated as nanoseconds if the TOML value is an -// integer, or they're parsed with time.ParseDuration() if they're strings. -// -// All other TOML types (float, string, int, bool and array) correspond to the -// obvious Go types. -// -// An exception to the above rules is if a type implements the TextUnmarshaler -// interface, in which case any primitive TOML value (floats, strings, integers, -// booleans, datetimes) will be converted to a []byte and given to the value's -// UnmarshalText method. See the Unmarshaler example for a demonstration with -// email addresses. -// -// # Key mapping -// -// TOML keys can map to either keys in a Go map or field names in a Go struct. -// The special `toml` struct tag can be used to map TOML keys to struct fields -// that don't match the key name exactly (see the example). A case insensitive -// match to struct names will be tried if an exact match can't be found. -// -// The mapping between TOML values and Go values is loose. That is, there may -// exist TOML values that cannot be placed into your representation, and there -// may be parts of your representation that do not correspond to TOML values. -// This loose mapping can be made stricter by using the IsDefined and/or -// Undecoded methods on the MetaData returned. -// -// This decoder does not handle cyclic types. Decode will not terminate if a -// cyclic type is passed. -type Decoder struct { - r io.Reader -} - -// NewDecoder creates a new Decoder. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{r: r} -} - -var ( - unmarshalToml = reflect.TypeOf((*Unmarshaler)(nil)).Elem() - unmarshalText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() - primitiveType = reflect.TypeOf((*Primitive)(nil)).Elem() -) - -// Decode TOML data in to the pointer `v`. -func (dec *Decoder) Decode(v interface{}) (MetaData, error) { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr { - s := "%q" - if reflect.TypeOf(v) == nil { - s = "%v" - } - - return MetaData{}, fmt.Errorf("toml: cannot decode to non-pointer "+s, reflect.TypeOf(v)) - } - if rv.IsNil() { - return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v)) - } - - // Check if this is a supported type: struct, map, interface{}, or something - // that implements UnmarshalTOML or UnmarshalText. - rv = indirect(rv) - rt := rv.Type() - if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map && - !(rv.Kind() == reflect.Interface && rv.NumMethod() == 0) && - !rt.Implements(unmarshalToml) && !rt.Implements(unmarshalText) { - return MetaData{}, fmt.Errorf("toml: cannot decode to type %s", rt) - } - - // TODO: parser should read from io.Reader? Or at the very least, make it - // read from []byte rather than string - data, err := ioutil.ReadAll(dec.r) - if err != nil { - return MetaData{}, err - } - - p, err := parse(string(data)) - if err != nil { - return MetaData{}, err - } - - md := MetaData{ - mapping: p.mapping, - keyInfo: p.keyInfo, - keys: p.ordered, - decoded: make(map[string]struct{}, len(p.ordered)), - context: nil, - data: data, - } - return md, md.unify(p.mapping, rv) -} - -// PrimitiveDecode is just like the other Decode* functions, except it decodes a -// TOML value that has already been parsed. Valid primitive values can *only* be -// obtained from values filled by the decoder functions, including this method. -// (i.e., v may contain more [Primitive] values.) -// -// Meta data for primitive values is included in the meta data returned by the -// Decode* functions with one exception: keys returned by the Undecoded method -// will only reflect keys that were decoded. Namely, any keys hidden behind a -// Primitive will be considered undecoded. Executing this method will update the -// undecoded keys in the meta data. (See the example.) -func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { - md.context = primValue.context - defer func() { md.context = nil }() - return md.unify(primValue.undecoded, rvalue(v)) -} - -// unify performs a sort of type unification based on the structure of `rv`, -// which is the client representation. -// -// Any type mismatch produces an error. Finding a type that we don't know -// how to handle produces an unsupported type error. -func (md *MetaData) unify(data interface{}, rv reflect.Value) error { - // Special case. Look for a `Primitive` value. - // TODO: #76 would make this superfluous after implemented. - if rv.Type() == primitiveType { - // Save the undecoded data and the key context into the primitive - // value. - context := make(Key, len(md.context)) - copy(context, md.context) - rv.Set(reflect.ValueOf(Primitive{ - undecoded: data, - context: context, - })) - return nil - } - - rvi := rv.Interface() - if v, ok := rvi.(Unmarshaler); ok { - return v.UnmarshalTOML(data) - } - if v, ok := rvi.(encoding.TextUnmarshaler); ok { - return md.unifyText(data, v) - } - - // TODO: - // The behavior here is incorrect whenever a Go type satisfies the - // encoding.TextUnmarshaler interface but also corresponds to a TOML hash or - // array. In particular, the unmarshaler should only be applied to primitive - // TOML values. But at this point, it will be applied to all kinds of values - // and produce an incorrect error whenever those values are hashes or arrays - // (including arrays of tables). - - k := rv.Kind() - - if k >= reflect.Int && k <= reflect.Uint64 { - return md.unifyInt(data, rv) - } - switch k { - case reflect.Ptr: - elem := reflect.New(rv.Type().Elem()) - err := md.unify(data, reflect.Indirect(elem)) - if err != nil { - return err - } - rv.Set(elem) - return nil - case reflect.Struct: - return md.unifyStruct(data, rv) - case reflect.Map: - return md.unifyMap(data, rv) - case reflect.Array: - return md.unifyArray(data, rv) - case reflect.Slice: - return md.unifySlice(data, rv) - case reflect.String: - return md.unifyString(data, rv) - case reflect.Bool: - return md.unifyBool(data, rv) - case reflect.Interface: - if rv.NumMethod() > 0 { /// Only empty interfaces are supported. - return md.e("unsupported type %s", rv.Type()) - } - return md.unifyAnything(data, rv) - case reflect.Float32, reflect.Float64: - return md.unifyFloat64(data, rv) - } - return md.e("unsupported type %s", rv.Kind()) -} - -func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { - tmap, ok := mapping.(map[string]interface{}) - if !ok { - if mapping == nil { - return nil - } - return md.e("type mismatch for %s: expected table but found %T", - rv.Type().String(), mapping) - } - - for key, datum := range tmap { - var f *field - fields := cachedTypeFields(rv.Type()) - for i := range fields { - ff := &fields[i] - if ff.name == key { - f = ff - break - } - if f == nil && strings.EqualFold(ff.name, key) { - f = ff - } - } - if f != nil { - subv := rv - for _, i := range f.index { - subv = indirect(subv.Field(i)) - } - - if isUnifiable(subv) { - md.decoded[md.context.add(key).String()] = struct{}{} - md.context = append(md.context, key) - - err := md.unify(datum, subv) - if err != nil { - return err - } - md.context = md.context[0 : len(md.context)-1] - } else if f.name != "" { - return md.e("cannot write unexported field %s.%s", rv.Type().String(), f.name) - } - } - } - return nil -} - -func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { - keyType := rv.Type().Key().Kind() - if keyType != reflect.String && keyType != reflect.Interface { - return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)", - keyType, rv.Type()) - } - - tmap, ok := mapping.(map[string]interface{}) - if !ok { - if tmap == nil { - return nil - } - return md.badtype("map", mapping) - } - if rv.IsNil() { - rv.Set(reflect.MakeMap(rv.Type())) - } - for k, v := range tmap { - md.decoded[md.context.add(k).String()] = struct{}{} - md.context = append(md.context, k) - - rvval := reflect.Indirect(reflect.New(rv.Type().Elem())) - - err := md.unify(v, indirect(rvval)) - if err != nil { - return err - } - md.context = md.context[0 : len(md.context)-1] - - rvkey := indirect(reflect.New(rv.Type().Key())) - - switch keyType { - case reflect.Interface: - rvkey.Set(reflect.ValueOf(k)) - case reflect.String: - rvkey.SetString(k) - } - - rv.SetMapIndex(rvkey, rvval) - } - return nil -} - -func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { - datav := reflect.ValueOf(data) - if datav.Kind() != reflect.Slice { - if !datav.IsValid() { - return nil - } - return md.badtype("slice", data) - } - if l := datav.Len(); l != rv.Len() { - return md.e("expected array length %d; got TOML array of length %d", rv.Len(), l) - } - return md.unifySliceArray(datav, rv) -} - -func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { - datav := reflect.ValueOf(data) - if datav.Kind() != reflect.Slice { - if !datav.IsValid() { - return nil - } - return md.badtype("slice", data) - } - n := datav.Len() - if rv.IsNil() || rv.Cap() < n { - rv.Set(reflect.MakeSlice(rv.Type(), n, n)) - } - rv.SetLen(n) - return md.unifySliceArray(datav, rv) -} - -func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { - l := data.Len() - for i := 0; i < l; i++ { - err := md.unify(data.Index(i).Interface(), indirect(rv.Index(i))) - if err != nil { - return err - } - } - return nil -} - -func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { - _, ok := rv.Interface().(json.Number) - if ok { - if i, ok := data.(int64); ok { - rv.SetString(strconv.FormatInt(i, 10)) - } else if f, ok := data.(float64); ok { - rv.SetString(strconv.FormatFloat(f, 'f', -1, 64)) - } else { - return md.badtype("string", data) - } - return nil - } - - if s, ok := data.(string); ok { - rv.SetString(s) - return nil - } - return md.badtype("string", data) -} - -func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { - rvk := rv.Kind() - - if num, ok := data.(float64); ok { - switch rvk { - case reflect.Float32: - if num < -math.MaxFloat32 || num > math.MaxFloat32 { - return md.parseErr(errParseRange{i: num, size: rvk.String()}) - } - fallthrough - case reflect.Float64: - rv.SetFloat(num) - default: - panic("bug") - } - return nil - } - - if num, ok := data.(int64); ok { - if (rvk == reflect.Float32 && (num < -maxSafeFloat32Int || num > maxSafeFloat32Int)) || - (rvk == reflect.Float64 && (num < -maxSafeFloat64Int || num > maxSafeFloat64Int)) { - return md.parseErr(errParseRange{i: num, size: rvk.String()}) - } - rv.SetFloat(float64(num)) - return nil - } - - return md.badtype("float", data) -} - -func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { - _, ok := rv.Interface().(time.Duration) - if ok { - // Parse as string duration, and fall back to regular integer parsing - // (as nanosecond) if this is not a string. - if s, ok := data.(string); ok { - dur, err := time.ParseDuration(s) - if err != nil { - return md.parseErr(errParseDuration{s}) - } - rv.SetInt(int64(dur)) - return nil - } - } - - num, ok := data.(int64) - if !ok { - return md.badtype("integer", data) - } - - rvk := rv.Kind() - switch { - case rvk >= reflect.Int && rvk <= reflect.Int64: - if (rvk == reflect.Int8 && (num < math.MinInt8 || num > math.MaxInt8)) || - (rvk == reflect.Int16 && (num < math.MinInt16 || num > math.MaxInt16)) || - (rvk == reflect.Int32 && (num < math.MinInt32 || num > math.MaxInt32)) { - return md.parseErr(errParseRange{i: num, size: rvk.String()}) - } - rv.SetInt(num) - case rvk >= reflect.Uint && rvk <= reflect.Uint64: - unum := uint64(num) - if rvk == reflect.Uint8 && (num < 0 || unum > math.MaxUint8) || - rvk == reflect.Uint16 && (num < 0 || unum > math.MaxUint16) || - rvk == reflect.Uint32 && (num < 0 || unum > math.MaxUint32) { - return md.parseErr(errParseRange{i: num, size: rvk.String()}) - } - rv.SetUint(unum) - default: - panic("unreachable") - } - return nil -} - -func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { - if b, ok := data.(bool); ok { - rv.SetBool(b) - return nil - } - return md.badtype("boolean", data) -} - -func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { - rv.Set(reflect.ValueOf(data)) - return nil -} - -func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) error { - var s string - switch sdata := data.(type) { - case Marshaler: - text, err := sdata.MarshalTOML() - if err != nil { - return err - } - s = string(text) - case encoding.TextMarshaler: - text, err := sdata.MarshalText() - if err != nil { - return err - } - s = string(text) - case fmt.Stringer: - s = sdata.String() - case string: - s = sdata - case bool: - s = fmt.Sprintf("%v", sdata) - case int64: - s = fmt.Sprintf("%d", sdata) - case float64: - s = fmt.Sprintf("%f", sdata) - default: - return md.badtype("primitive (string-like)", data) - } - if err := v.UnmarshalText([]byte(s)); err != nil { - return err - } - return nil -} - -func (md *MetaData) badtype(dst string, data interface{}) error { - return md.e("incompatible types: TOML value has type %T; destination has type %s", data, dst) -} - -func (md *MetaData) parseErr(err error) error { - k := md.context.String() - return ParseError{ - LastKey: k, - Position: md.keyInfo[k].pos, - Line: md.keyInfo[k].pos.Line, - err: err, - input: string(md.data), - } -} - -func (md *MetaData) e(format string, args ...interface{}) error { - f := "toml: " - if len(md.context) > 0 { - f = fmt.Sprintf("toml: (last key %q): ", md.context) - p := md.keyInfo[md.context.String()].pos - if p.Line > 0 { - f = fmt.Sprintf("toml: line %d (last key %q): ", p.Line, md.context) - } - } - return fmt.Errorf(f+format, args...) -} - -// rvalue returns a reflect.Value of `v`. All pointers are resolved. -func rvalue(v interface{}) reflect.Value { - return indirect(reflect.ValueOf(v)) -} - -// indirect returns the value pointed to by a pointer. -// -// Pointers are followed until the value is not a pointer. New values are -// allocated for each nil pointer. -// -// An exception to this rule is if the value satisfies an interface of interest -// to us (like encoding.TextUnmarshaler). -func indirect(v reflect.Value) reflect.Value { - if v.Kind() != reflect.Ptr { - if v.CanSet() { - pv := v.Addr() - pvi := pv.Interface() - if _, ok := pvi.(encoding.TextUnmarshaler); ok { - return pv - } - if _, ok := pvi.(Unmarshaler); ok { - return pv - } - } - return v - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - return indirect(reflect.Indirect(v)) -} - -func isUnifiable(rv reflect.Value) bool { - if rv.CanSet() { - return true - } - rvi := rv.Interface() - if _, ok := rvi.(encoding.TextUnmarshaler); ok { - return true - } - if _, ok := rvi.(Unmarshaler); ok { - return true - } - return false -} diff --git a/vendor/github.com/BurntSushi/toml/decode_go116.go b/vendor/github.com/BurntSushi/toml/decode_go116.go deleted file mode 100644 index 086d0b6866..0000000000 --- a/vendor/github.com/BurntSushi/toml/decode_go116.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build go1.16 -// +build go1.16 - -package toml - -import ( - "io/fs" -) - -// DecodeFS reads the contents of a file from [fs.FS] and decodes it with -// [Decode]. -func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) { - fp, err := fsys.Open(path) - if err != nil { - return MetaData{}, err - } - defer fp.Close() - return NewDecoder(fp).Decode(v) -} diff --git a/vendor/github.com/BurntSushi/toml/deprecated.go b/vendor/github.com/BurntSushi/toml/deprecated.go deleted file mode 100644 index b9e309717e..0000000000 --- a/vendor/github.com/BurntSushi/toml/deprecated.go +++ /dev/null @@ -1,29 +0,0 @@ -package toml - -import ( - "encoding" - "io" -) - -// TextMarshaler is an alias for encoding.TextMarshaler. -// -// Deprecated: use encoding.TextMarshaler -type TextMarshaler encoding.TextMarshaler - -// TextUnmarshaler is an alias for encoding.TextUnmarshaler. -// -// Deprecated: use encoding.TextUnmarshaler -type TextUnmarshaler encoding.TextUnmarshaler - -// PrimitiveDecode is an alias for MetaData.PrimitiveDecode(). -// -// Deprecated: use MetaData.PrimitiveDecode. -func PrimitiveDecode(primValue Primitive, v interface{}) error { - md := MetaData{decoded: make(map[string]struct{})} - return md.unify(primValue.undecoded, rvalue(v)) -} - -// DecodeReader is an alias for NewDecoder(r).Decode(v). -// -// Deprecated: use NewDecoder(reader).Decode(&value). -func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) } diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go deleted file mode 100644 index 81a7c0fe9f..0000000000 --- a/vendor/github.com/BurntSushi/toml/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package toml implements decoding and encoding of TOML files. -// -// This package supports TOML v1.0.0, as specified at https://toml.io -// -// There is also support for delaying decoding with the Primitive type, and -// querying the set of keys in a TOML document with the MetaData type. -// -// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator, -// and can be used to verify if TOML document is valid. It can also be used to -// print the type of each key. -package toml diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go deleted file mode 100644 index 9cd25d7571..0000000000 --- a/vendor/github.com/BurntSushi/toml/encode.go +++ /dev/null @@ -1,759 +0,0 @@ -package toml - -import ( - "bufio" - "encoding" - "encoding/json" - "errors" - "fmt" - "io" - "math" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/BurntSushi/toml/internal" -) - -type tomlEncodeError struct{ error } - -var ( - errArrayNilElement = errors.New("toml: cannot encode array with nil element") - errNonString = errors.New("toml: cannot encode a map with non-string key type") - errNoKey = errors.New("toml: top-level values must be Go maps or structs") - errAnything = errors.New("") // used in testing -) - -var dblQuotedReplacer = strings.NewReplacer( - "\"", "\\\"", - "\\", "\\\\", - "\x00", `\u0000`, - "\x01", `\u0001`, - "\x02", `\u0002`, - "\x03", `\u0003`, - "\x04", `\u0004`, - "\x05", `\u0005`, - "\x06", `\u0006`, - "\x07", `\u0007`, - "\b", `\b`, - "\t", `\t`, - "\n", `\n`, - "\x0b", `\u000b`, - "\f", `\f`, - "\r", `\r`, - "\x0e", `\u000e`, - "\x0f", `\u000f`, - "\x10", `\u0010`, - "\x11", `\u0011`, - "\x12", `\u0012`, - "\x13", `\u0013`, - "\x14", `\u0014`, - "\x15", `\u0015`, - "\x16", `\u0016`, - "\x17", `\u0017`, - "\x18", `\u0018`, - "\x19", `\u0019`, - "\x1a", `\u001a`, - "\x1b", `\u001b`, - "\x1c", `\u001c`, - "\x1d", `\u001d`, - "\x1e", `\u001e`, - "\x1f", `\u001f`, - "\x7f", `\u007f`, -) - -var ( - marshalToml = reflect.TypeOf((*Marshaler)(nil)).Elem() - marshalText = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() - timeType = reflect.TypeOf((*time.Time)(nil)).Elem() -) - -// Marshaler is the interface implemented by types that can marshal themselves -// into valid TOML. -type Marshaler interface { - MarshalTOML() ([]byte, error) -} - -// Encoder encodes a Go to a TOML document. -// -// The mapping between Go values and TOML values should be precisely the same as -// for [Decode]. -// -// time.Time is encoded as a RFC 3339 string, and time.Duration as its string -// representation. -// -// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to -// encoding the value as custom TOML. -// -// If you want to write arbitrary binary data then you will need to use -// something like base64 since TOML does not have any binary types. -// -// When encoding TOML hashes (Go maps or structs), keys without any sub-hashes -// are encoded first. -// -// Go maps will be sorted alphabetically by key for deterministic output. -// -// The toml struct tag can be used to provide the key name; if omitted the -// struct field name will be used. If the "omitempty" option is present the -// following value will be skipped: -// -// - arrays, slices, maps, and string with len of 0 -// - struct with all zero values -// - bool false -// -// If omitzero is given all int and float types with a value of 0 will be -// skipped. -// -// Encoding Go values without a corresponding TOML representation will return an -// error. Examples of this includes maps with non-string keys, slices with nil -// elements, embedded non-struct types, and nested slices containing maps or -// structs. (e.g. [][]map[string]string is not allowed but []map[string]string -// is okay, as is []map[string][]string). -// -// NOTE: only exported keys are encoded due to the use of reflection. Unexported -// keys are silently discarded. -type Encoder struct { - // String to use for a single indentation level; default is two spaces. - Indent string - - w *bufio.Writer - hasWritten bool // written any output to w yet? -} - -// NewEncoder create a new Encoder. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - w: bufio.NewWriter(w), - Indent: " ", - } -} - -// Encode writes a TOML representation of the Go value to the [Encoder]'s writer. -// -// An error is returned if the value given cannot be encoded to a valid TOML -// document. -func (enc *Encoder) Encode(v interface{}) error { - rv := eindirect(reflect.ValueOf(v)) - err := enc.safeEncode(Key([]string{}), rv) - if err != nil { - return err - } - return enc.w.Flush() -} - -func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) { - defer func() { - if r := recover(); r != nil { - if terr, ok := r.(tomlEncodeError); ok { - err = terr.error - return - } - panic(r) - } - }() - enc.encode(key, rv) - return nil -} - -func (enc *Encoder) encode(key Key, rv reflect.Value) { - // If we can marshal the type to text, then we use that. This prevents the - // encoder for handling these types as generic structs (or whatever the - // underlying type of a TextMarshaler is). - switch { - case isMarshaler(rv): - enc.writeKeyValue(key, rv, false) - return - case rv.Type() == primitiveType: // TODO: #76 would make this superfluous after implemented. - enc.encode(key, reflect.ValueOf(rv.Interface().(Primitive).undecoded)) - return - } - - k := rv.Kind() - switch k { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, - reflect.Uint64, - reflect.Float32, reflect.Float64, reflect.String, reflect.Bool: - enc.writeKeyValue(key, rv, false) - case reflect.Array, reflect.Slice: - if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) { - enc.eArrayOfTables(key, rv) - } else { - enc.writeKeyValue(key, rv, false) - } - case reflect.Interface: - if rv.IsNil() { - return - } - enc.encode(key, rv.Elem()) - case reflect.Map: - if rv.IsNil() { - return - } - enc.eTable(key, rv) - case reflect.Ptr: - if rv.IsNil() { - return - } - enc.encode(key, rv.Elem()) - case reflect.Struct: - enc.eTable(key, rv) - default: - encPanic(fmt.Errorf("unsupported type for key '%s': %s", key, k)) - } -} - -// eElement encodes any value that can be an array element. -func (enc *Encoder) eElement(rv reflect.Value) { - switch v := rv.Interface().(type) { - case time.Time: // Using TextMarshaler adds extra quotes, which we don't want. - format := time.RFC3339Nano - switch v.Location() { - case internal.LocalDatetime: - format = "2006-01-02T15:04:05.999999999" - case internal.LocalDate: - format = "2006-01-02" - case internal.LocalTime: - format = "15:04:05.999999999" - } - switch v.Location() { - default: - enc.wf(v.Format(format)) - case internal.LocalDatetime, internal.LocalDate, internal.LocalTime: - enc.wf(v.In(time.UTC).Format(format)) - } - return - case Marshaler: - s, err := v.MarshalTOML() - if err != nil { - encPanic(err) - } - if s == nil { - encPanic(errors.New("MarshalTOML returned nil and no error")) - } - enc.w.Write(s) - return - case encoding.TextMarshaler: - s, err := v.MarshalText() - if err != nil { - encPanic(err) - } - if s == nil { - encPanic(errors.New("MarshalText returned nil and no error")) - } - enc.writeQuoted(string(s)) - return - case time.Duration: - enc.writeQuoted(v.String()) - return - case json.Number: - n, _ := rv.Interface().(json.Number) - - if n == "" { /// Useful zero value. - enc.w.WriteByte('0') - return - } else if v, err := n.Int64(); err == nil { - enc.eElement(reflect.ValueOf(v)) - return - } else if v, err := n.Float64(); err == nil { - enc.eElement(reflect.ValueOf(v)) - return - } - encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n)) - } - - switch rv.Kind() { - case reflect.Ptr: - enc.eElement(rv.Elem()) - return - case reflect.String: - enc.writeQuoted(rv.String()) - case reflect.Bool: - enc.wf(strconv.FormatBool(rv.Bool())) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - enc.wf(strconv.FormatInt(rv.Int(), 10)) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - enc.wf(strconv.FormatUint(rv.Uint(), 10)) - case reflect.Float32: - f := rv.Float() - if math.IsNaN(f) { - enc.wf("nan") - } else if math.IsInf(f, 0) { - enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)]) - } else { - enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32))) - } - case reflect.Float64: - f := rv.Float() - if math.IsNaN(f) { - enc.wf("nan") - } else if math.IsInf(f, 0) { - enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)]) - } else { - enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64))) - } - case reflect.Array, reflect.Slice: - enc.eArrayOrSliceElement(rv) - case reflect.Struct: - enc.eStruct(nil, rv, true) - case reflect.Map: - enc.eMap(nil, rv, true) - case reflect.Interface: - enc.eElement(rv.Elem()) - default: - encPanic(fmt.Errorf("unexpected type: %T", rv.Interface())) - } -} - -// By the TOML spec, all floats must have a decimal with at least one number on -// either side. -func floatAddDecimal(fstr string) string { - if !strings.Contains(fstr, ".") { - return fstr + ".0" - } - return fstr -} - -func (enc *Encoder) writeQuoted(s string) { - enc.wf("\"%s\"", dblQuotedReplacer.Replace(s)) -} - -func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) { - length := rv.Len() - enc.wf("[") - for i := 0; i < length; i++ { - elem := eindirect(rv.Index(i)) - enc.eElement(elem) - if i != length-1 { - enc.wf(", ") - } - } - enc.wf("]") -} - -func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { - if len(key) == 0 { - encPanic(errNoKey) - } - for i := 0; i < rv.Len(); i++ { - trv := eindirect(rv.Index(i)) - if isNil(trv) { - continue - } - enc.newline() - enc.wf("%s[[%s]]", enc.indentStr(key), key) - enc.newline() - enc.eMapOrStruct(key, trv, false) - } -} - -func (enc *Encoder) eTable(key Key, rv reflect.Value) { - if len(key) == 1 { - // Output an extra newline between top-level tables. - // (The newline isn't written if nothing else has been written though.) - enc.newline() - } - if len(key) > 0 { - enc.wf("%s[%s]", enc.indentStr(key), key) - enc.newline() - } - enc.eMapOrStruct(key, rv, false) -} - -func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value, inline bool) { - switch rv.Kind() { - case reflect.Map: - enc.eMap(key, rv, inline) - case reflect.Struct: - enc.eStruct(key, rv, inline) - default: - // Should never happen? - panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String()) - } -} - -func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) { - rt := rv.Type() - if rt.Key().Kind() != reflect.String { - encPanic(errNonString) - } - - // Sort keys so that we have deterministic output. And write keys directly - // underneath this key first, before writing sub-structs or sub-maps. - var mapKeysDirect, mapKeysSub []string - for _, mapKey := range rv.MapKeys() { - k := mapKey.String() - if typeIsTable(tomlTypeOfGo(eindirect(rv.MapIndex(mapKey)))) { - mapKeysSub = append(mapKeysSub, k) - } else { - mapKeysDirect = append(mapKeysDirect, k) - } - } - - var writeMapKeys = func(mapKeys []string, trailC bool) { - sort.Strings(mapKeys) - for i, mapKey := range mapKeys { - val := eindirect(rv.MapIndex(reflect.ValueOf(mapKey))) - if isNil(val) { - continue - } - - if inline { - enc.writeKeyValue(Key{mapKey}, val, true) - if trailC || i != len(mapKeys)-1 { - enc.wf(", ") - } - } else { - enc.encode(key.add(mapKey), val) - } - } - } - - if inline { - enc.wf("{") - } - writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0) - writeMapKeys(mapKeysSub, false) - if inline { - enc.wf("}") - } -} - -const is32Bit = (32 << (^uint(0) >> 63)) == 32 - -func pointerTo(t reflect.Type) reflect.Type { - if t.Kind() == reflect.Ptr { - return pointerTo(t.Elem()) - } - return t -} - -func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { - // Write keys for fields directly under this key first, because if we write - // a field that creates a new table then all keys under it will be in that - // table (not the one we're writing here). - // - // Fields is a [][]int: for fieldsDirect this always has one entry (the - // struct index). For fieldsSub it contains two entries: the parent field - // index from tv, and the field indexes for the fields of the sub. - var ( - rt = rv.Type() - fieldsDirect, fieldsSub [][]int - addFields func(rt reflect.Type, rv reflect.Value, start []int) - ) - addFields = func(rt reflect.Type, rv reflect.Value, start []int) { - for i := 0; i < rt.NumField(); i++ { - f := rt.Field(i) - isEmbed := f.Anonymous && pointerTo(f.Type).Kind() == reflect.Struct - if f.PkgPath != "" && !isEmbed { /// Skip unexported fields. - continue - } - opts := getOptions(f.Tag) - if opts.skip { - continue - } - - frv := eindirect(rv.Field(i)) - - if is32Bit { - // Copy so it works correct on 32bit archs; not clear why this - // is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4 - // This also works fine on 64bit, but 32bit archs are somewhat - // rare and this is a wee bit faster. - copyStart := make([]int, len(start)) - copy(copyStart, start) - start = copyStart - } - - // Treat anonymous struct fields with tag names as though they are - // not anonymous, like encoding/json does. - // - // Non-struct anonymous fields use the normal encoding logic. - if isEmbed { - if getOptions(f.Tag).name == "" && frv.Kind() == reflect.Struct { - addFields(frv.Type(), frv, append(start, f.Index...)) - continue - } - } - - if typeIsTable(tomlTypeOfGo(frv)) { - fieldsSub = append(fieldsSub, append(start, f.Index...)) - } else { - fieldsDirect = append(fieldsDirect, append(start, f.Index...)) - } - } - } - addFields(rt, rv, nil) - - writeFields := func(fields [][]int) { - for _, fieldIndex := range fields { - fieldType := rt.FieldByIndex(fieldIndex) - fieldVal := rv.FieldByIndex(fieldIndex) - - opts := getOptions(fieldType.Tag) - if opts.skip { - continue - } - if opts.omitempty && isEmpty(fieldVal) { - continue - } - - fieldVal = eindirect(fieldVal) - - if isNil(fieldVal) { /// Don't write anything for nil fields. - continue - } - - keyName := fieldType.Name - if opts.name != "" { - keyName = opts.name - } - - if opts.omitzero && isZero(fieldVal) { - continue - } - - if inline { - enc.writeKeyValue(Key{keyName}, fieldVal, true) - if fieldIndex[0] != len(fields)-1 { - enc.wf(", ") - } - } else { - enc.encode(key.add(keyName), fieldVal) - } - } - } - - if inline { - enc.wf("{") - } - writeFields(fieldsDirect) - writeFields(fieldsSub) - if inline { - enc.wf("}") - } -} - -// tomlTypeOfGo returns the TOML type name of the Go value's type. -// -// It is used to determine whether the types of array elements are mixed (which -// is forbidden). If the Go value is nil, then it is illegal for it to be an -// array element, and valueIsNil is returned as true. -// -// The type may be `nil`, which means no concrete TOML type could be found. -func tomlTypeOfGo(rv reflect.Value) tomlType { - if isNil(rv) || !rv.IsValid() { - return nil - } - - if rv.Kind() == reflect.Struct { - if rv.Type() == timeType { - return tomlDatetime - } - if isMarshaler(rv) { - return tomlString - } - return tomlHash - } - - if isMarshaler(rv) { - return tomlString - } - - switch rv.Kind() { - case reflect.Bool: - return tomlBool - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, - reflect.Uint64: - return tomlInteger - case reflect.Float32, reflect.Float64: - return tomlFloat - case reflect.Array, reflect.Slice: - if isTableArray(rv) { - return tomlArrayHash - } - return tomlArray - case reflect.Ptr, reflect.Interface: - return tomlTypeOfGo(rv.Elem()) - case reflect.String: - return tomlString - case reflect.Map: - return tomlHash - default: - encPanic(errors.New("unsupported type: " + rv.Kind().String())) - panic("unreachable") - } -} - -func isMarshaler(rv reflect.Value) bool { - return rv.Type().Implements(marshalText) || rv.Type().Implements(marshalToml) -} - -// isTableArray reports if all entries in the array or slice are a table. -func isTableArray(arr reflect.Value) bool { - if isNil(arr) || !arr.IsValid() || arr.Len() == 0 { - return false - } - - ret := true - for i := 0; i < arr.Len(); i++ { - tt := tomlTypeOfGo(eindirect(arr.Index(i))) - // Don't allow nil. - if tt == nil { - encPanic(errArrayNilElement) - } - - if ret && !typeEqual(tomlHash, tt) { - ret = false - } - } - return ret -} - -type tagOptions struct { - skip bool // "-" - name string - omitempty bool - omitzero bool -} - -func getOptions(tag reflect.StructTag) tagOptions { - t := tag.Get("toml") - if t == "-" { - return tagOptions{skip: true} - } - var opts tagOptions - parts := strings.Split(t, ",") - opts.name = parts[0] - for _, s := range parts[1:] { - switch s { - case "omitempty": - opts.omitempty = true - case "omitzero": - opts.omitzero = true - } - } - return opts -} - -func isZero(rv reflect.Value) bool { - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint() == 0 - case reflect.Float32, reflect.Float64: - return rv.Float() == 0.0 - } - return false -} - -func isEmpty(rv reflect.Value) bool { - switch rv.Kind() { - case reflect.Array, reflect.Slice, reflect.Map, reflect.String: - return rv.Len() == 0 - case reflect.Struct: - if rv.Type().Comparable() { - return reflect.Zero(rv.Type()).Interface() == rv.Interface() - } - // Need to also check if all the fields are empty, otherwise something - // like this with uncomparable types will always return true: - // - // type a struct{ field b } - // type b struct{ s []string } - // s := a{field: b{s: []string{"AAA"}}} - for i := 0; i < rv.NumField(); i++ { - if !isEmpty(rv.Field(i)) { - return false - } - } - return true - case reflect.Bool: - return !rv.Bool() - case reflect.Ptr: - return rv.IsNil() - } - return false -} - -func (enc *Encoder) newline() { - if enc.hasWritten { - enc.wf("\n") - } -} - -// Write a key/value pair: -// -// key = -// -// This is also used for "k = v" in inline tables; so something like this will -// be written in three calls: -// -// ┌───────────────────┐ -// │ ┌───┐ ┌────┐│ -// v v v v vv -// key = {k = 1, k2 = 2} -func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { - /// Marshaler used on top-level document; call eElement() to just call - /// Marshal{TOML,Text}. - if len(key) == 0 { - enc.eElement(val) - return - } - enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) - enc.eElement(val) - if !inline { - enc.newline() - } -} - -func (enc *Encoder) wf(format string, v ...interface{}) { - _, err := fmt.Fprintf(enc.w, format, v...) - if err != nil { - encPanic(err) - } - enc.hasWritten = true -} - -func (enc *Encoder) indentStr(key Key) string { - return strings.Repeat(enc.Indent, len(key)-1) -} - -func encPanic(err error) { - panic(tomlEncodeError{err}) -} - -// Resolve any level of pointers to the actual value (e.g. **string → string). -func eindirect(v reflect.Value) reflect.Value { - if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface { - if isMarshaler(v) { - return v - } - if v.CanAddr() { /// Special case for marshalers; see #358. - if pv := v.Addr(); isMarshaler(pv) { - return pv - } - } - return v - } - - if v.IsNil() { - return v - } - - return eindirect(v.Elem()) -} - -func isNil(rv reflect.Value) bool { - switch rv.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return rv.IsNil() - default: - return false - } -} diff --git a/vendor/github.com/BurntSushi/toml/error.go b/vendor/github.com/BurntSushi/toml/error.go deleted file mode 100644 index efd68865bb..0000000000 --- a/vendor/github.com/BurntSushi/toml/error.go +++ /dev/null @@ -1,279 +0,0 @@ -package toml - -import ( - "fmt" - "strings" -) - -// ParseError is returned when there is an error parsing the TOML syntax such as -// invalid syntax, duplicate keys, etc. -// -// In addition to the error message itself, you can also print detailed location -// information with context by using [ErrorWithPosition]: -// -// toml: error: Key 'fruit' was already created and cannot be used as an array. -// -// At line 4, column 2-7: -// -// 2 | fruit = [] -// 3 | -// 4 | [[fruit]] # Not allowed -// ^^^^^ -// -// [ErrorWithUsage] can be used to print the above with some more detailed usage -// guidance: -// -// toml: error: newlines not allowed within inline tables -// -// At line 1, column 18: -// -// 1 | x = [{ key = 42 # -// ^ -// -// Error help: -// -// Inline tables must always be on a single line: -// -// table = {key = 42, second = 43} -// -// It is invalid to split them over multiple lines like so: -// -// # INVALID -// table = { -// key = 42, -// second = 43 -// } -// -// Use regular for this: -// -// [table] -// key = 42 -// second = 43 -type ParseError struct { - Message string // Short technical message. - Usage string // Longer message with usage guidance; may be blank. - Position Position // Position of the error - LastKey string // Last parsed key, may be blank. - - // Line the error occurred. - // - // Deprecated: use [Position]. - Line int - - err error - input string -} - -// Position of an error. -type Position struct { - Line int // Line number, starting at 1. - Start int // Start of error, as byte offset starting at 0. - Len int // Lenght in bytes. -} - -func (pe ParseError) Error() string { - msg := pe.Message - if msg == "" { // Error from errorf() - msg = pe.err.Error() - } - - if pe.LastKey == "" { - return fmt.Sprintf("toml: line %d: %s", pe.Position.Line, msg) - } - return fmt.Sprintf("toml: line %d (last key %q): %s", - pe.Position.Line, pe.LastKey, msg) -} - -// ErrorWithPosition returns the error with detailed location context. -// -// See the documentation on [ParseError]. -func (pe ParseError) ErrorWithPosition() string { - if pe.input == "" { // Should never happen, but just in case. - return pe.Error() - } - - var ( - lines = strings.Split(pe.input, "\n") - col = pe.column(lines) - b = new(strings.Builder) - ) - - msg := pe.Message - if msg == "" { - msg = pe.err.Error() - } - - // TODO: don't show control characters as literals? This may not show up - // well everywhere. - - if pe.Position.Len == 1 { - fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d:\n\n", - msg, pe.Position.Line, col+1) - } else { - fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d-%d:\n\n", - msg, pe.Position.Line, col, col+pe.Position.Len) - } - if pe.Position.Line > 2 { - fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, lines[pe.Position.Line-3]) - } - if pe.Position.Line > 1 { - fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, lines[pe.Position.Line-2]) - } - fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, lines[pe.Position.Line-1]) - fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col), strings.Repeat("^", pe.Position.Len)) - return b.String() -} - -// ErrorWithUsage returns the error with detailed location context and usage -// guidance. -// -// See the documentation on [ParseError]. -func (pe ParseError) ErrorWithUsage() string { - m := pe.ErrorWithPosition() - if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" { - lines := strings.Split(strings.TrimSpace(u.Usage()), "\n") - for i := range lines { - if lines[i] != "" { - lines[i] = " " + lines[i] - } - } - return m + "Error help:\n\n" + strings.Join(lines, "\n") + "\n" - } - return m -} - -func (pe ParseError) column(lines []string) int { - var pos, col int - for i := range lines { - ll := len(lines[i]) + 1 // +1 for the removed newline - if pos+ll >= pe.Position.Start { - col = pe.Position.Start - pos - if col < 0 { // Should never happen, but just in case. - col = 0 - } - break - } - pos += ll - } - - return col -} - -type ( - errLexControl struct{ r rune } - errLexEscape struct{ r rune } - errLexUTF8 struct{ b byte } - errLexInvalidNum struct{ v string } - errLexInvalidDate struct{ v string } - errLexInlineTableNL struct{} - errLexStringNL struct{} - errParseRange struct { - i interface{} // int or float - size string // "int64", "uint16", etc. - } - errParseDuration struct{ d string } -) - -func (e errLexControl) Error() string { - return fmt.Sprintf("TOML files cannot contain control characters: '0x%02x'", e.r) -} -func (e errLexControl) Usage() string { return "" } - -func (e errLexEscape) Error() string { return fmt.Sprintf(`invalid escape in string '\%c'`, e.r) } -func (e errLexEscape) Usage() string { return usageEscape } -func (e errLexUTF8) Error() string { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) } -func (e errLexUTF8) Usage() string { return "" } -func (e errLexInvalidNum) Error() string { return fmt.Sprintf("invalid number: %q", e.v) } -func (e errLexInvalidNum) Usage() string { return "" } -func (e errLexInvalidDate) Error() string { return fmt.Sprintf("invalid date: %q", e.v) } -func (e errLexInvalidDate) Usage() string { return "" } -func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" } -func (e errLexInlineTableNL) Usage() string { return usageInlineNewline } -func (e errLexStringNL) Error() string { return "strings cannot contain newlines" } -func (e errLexStringNL) Usage() string { return usageStringNewline } -func (e errParseRange) Error() string { return fmt.Sprintf("%v is out of range for %s", e.i, e.size) } -func (e errParseRange) Usage() string { return usageIntOverflow } -func (e errParseDuration) Error() string { return fmt.Sprintf("invalid duration: %q", e.d) } -func (e errParseDuration) Usage() string { return usageDuration } - -const usageEscape = ` -A '\' inside a "-delimited string is interpreted as an escape character. - -The following escape sequences are supported: -\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX - -To prevent a '\' from being recognized as an escape character, use either: - -- a ' or '''-delimited string; escape characters aren't processed in them; or -- write two backslashes to get a single backslash: '\\'. - -If you're trying to add a Windows path (e.g. "C:\Users\martin") then using '/' -instead of '\' will usually also work: "C:/Users/martin". -` - -const usageInlineNewline = ` -Inline tables must always be on a single line: - - table = {key = 42, second = 43} - -It is invalid to split them over multiple lines like so: - - # INVALID - table = { - key = 42, - second = 43 - } - -Use regular for this: - - [table] - key = 42 - second = 43 -` - -const usageStringNewline = ` -Strings must always be on a single line, and cannot span more than one line: - - # INVALID - string = "Hello, - world!" - -Instead use """ or ''' to split strings over multiple lines: - - string = """Hello, - world!""" -` - -const usageIntOverflow = ` -This number is too large; this may be an error in the TOML, but it can also be a -bug in the program that uses too small of an integer. - -The maximum and minimum values are: - - size │ lowest │ highest - ───────┼────────────────┼────────── - int8 │ -128 │ 127 - int16 │ -32,768 │ 32,767 - int32 │ -2,147,483,648 │ 2,147,483,647 - int64 │ -9.2 × 10¹⁷ │ 9.2 × 10¹⁷ - uint8 │ 0 │ 255 - uint16 │ 0 │ 65535 - uint32 │ 0 │ 4294967295 - uint64 │ 0 │ 1.8 × 10¹⁸ - -int refers to int32 on 32-bit systems and int64 on 64-bit systems. -` - -const usageDuration = ` -A duration must be as "number", without any spaces. Valid units are: - - ns nanoseconds (billionth of a second) - us, µs microseconds (millionth of a second) - ms milliseconds (thousands of a second) - s seconds - m minutes - h hours - -You can combine multiple units; for example "5m10s" for 5 minutes and 10 -seconds. -` diff --git a/vendor/github.com/BurntSushi/toml/internal/tz.go b/vendor/github.com/BurntSushi/toml/internal/tz.go deleted file mode 100644 index 022f15bc2b..0000000000 --- a/vendor/github.com/BurntSushi/toml/internal/tz.go +++ /dev/null @@ -1,36 +0,0 @@ -package internal - -import "time" - -// Timezones used for local datetime, date, and time TOML types. -// -// The exact way times and dates without a timezone should be interpreted is not -// well-defined in the TOML specification and left to the implementation. These -// defaults to current local timezone offset of the computer, but this can be -// changed by changing these variables before decoding. -// -// TODO: -// Ideally we'd like to offer people the ability to configure the used timezone -// by setting Decoder.Timezone and Encoder.Timezone; however, this is a bit -// tricky: the reason we use three different variables for this is to support -// round-tripping – without these specific TZ names we wouldn't know which -// format to use. -// -// There isn't a good way to encode this right now though, and passing this sort -// of information also ties in to various related issues such as string format -// encoding, encoding of comments, etc. -// -// So, for the time being, just put this in internal until we can write a good -// comprehensive API for doing all of this. -// -// The reason they're exported is because they're referred from in e.g. -// internal/tag. -// -// Note that this behaviour is valid according to the TOML spec as the exact -// behaviour is left up to implementations. -var ( - localOffset = func() int { _, o := time.Now().Zone(); return o }() - LocalDatetime = time.FixedZone("datetime-local", localOffset) - LocalDate = time.FixedZone("date-local", localOffset) - LocalTime = time.FixedZone("time-local", localOffset) -) diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go deleted file mode 100644 index 3545a6ad66..0000000000 --- a/vendor/github.com/BurntSushi/toml/lex.go +++ /dev/null @@ -1,1283 +0,0 @@ -package toml - -import ( - "fmt" - "reflect" - "runtime" - "strings" - "unicode" - "unicode/utf8" -) - -type itemType int - -const ( - itemError itemType = iota - itemNIL // used in the parser to indicate no type - itemEOF - itemText - itemString - itemRawString - itemMultilineString - itemRawMultilineString - itemBool - itemInteger - itemFloat - itemDatetime - itemArray // the start of an array - itemArrayEnd - itemTableStart - itemTableEnd - itemArrayTableStart - itemArrayTableEnd - itemKeyStart - itemKeyEnd - itemCommentStart - itemInlineTableStart - itemInlineTableEnd -) - -const eof = 0 - -type stateFn func(lx *lexer) stateFn - -func (p Position) String() string { - return fmt.Sprintf("at line %d; start %d; length %d", p.Line, p.Start, p.Len) -} - -type lexer struct { - input string - start int - pos int - line int - state stateFn - items chan item - tomlNext bool - - // Allow for backing up up to 4 runes. This is necessary because TOML - // contains 3-rune tokens (""" and '''). - prevWidths [4]int - nprev int // how many of prevWidths are in use - atEOF bool // If we emit an eof, we can still back up, but it is not OK to call next again. - - // A stack of state functions used to maintain context. - // - // The idea is to reuse parts of the state machine in various places. For - // example, values can appear at the top level or within arbitrarily nested - // arrays. The last state on the stack is used after a value has been lexed. - // Similarly for comments. - stack []stateFn -} - -type item struct { - typ itemType - val string - err error - pos Position -} - -func (lx *lexer) nextItem() item { - for { - select { - case item := <-lx.items: - return item - default: - lx.state = lx.state(lx) - //fmt.Printf(" STATE %-24s current: %-10s stack: %s\n", lx.state, lx.current(), lx.stack) - } - } -} - -func lex(input string, tomlNext bool) *lexer { - lx := &lexer{ - input: input, - state: lexTop, - items: make(chan item, 10), - stack: make([]stateFn, 0, 10), - line: 1, - tomlNext: tomlNext, - } - return lx -} - -func (lx *lexer) push(state stateFn) { - lx.stack = append(lx.stack, state) -} - -func (lx *lexer) pop() stateFn { - if len(lx.stack) == 0 { - return lx.errorf("BUG in lexer: no states to pop") - } - last := lx.stack[len(lx.stack)-1] - lx.stack = lx.stack[0 : len(lx.stack)-1] - return last -} - -func (lx *lexer) current() string { - return lx.input[lx.start:lx.pos] -} - -func (lx lexer) getPos() Position { - p := Position{ - Line: lx.line, - Start: lx.start, - Len: lx.pos - lx.start, - } - if p.Len <= 0 { - p.Len = 1 - } - return p -} - -func (lx *lexer) emit(typ itemType) { - // Needed for multiline strings ending with an incomplete UTF-8 sequence. - if lx.start > lx.pos { - lx.error(errLexUTF8{lx.input[lx.pos]}) - return - } - lx.items <- item{typ: typ, pos: lx.getPos(), val: lx.current()} - lx.start = lx.pos -} - -func (lx *lexer) emitTrim(typ itemType) { - lx.items <- item{typ: typ, pos: lx.getPos(), val: strings.TrimSpace(lx.current())} - lx.start = lx.pos -} - -func (lx *lexer) next() (r rune) { - if lx.atEOF { - panic("BUG in lexer: next called after EOF") - } - if lx.pos >= len(lx.input) { - lx.atEOF = true - return eof - } - - if lx.input[lx.pos] == '\n' { - lx.line++ - } - lx.prevWidths[3] = lx.prevWidths[2] - lx.prevWidths[2] = lx.prevWidths[1] - lx.prevWidths[1] = lx.prevWidths[0] - if lx.nprev < 4 { - lx.nprev++ - } - - r, w := utf8.DecodeRuneInString(lx.input[lx.pos:]) - if r == utf8.RuneError { - lx.error(errLexUTF8{lx.input[lx.pos]}) - return utf8.RuneError - } - - // Note: don't use peek() here, as this calls next(). - if isControl(r) || (r == '\r' && (len(lx.input)-1 == lx.pos || lx.input[lx.pos+1] != '\n')) { - lx.errorControlChar(r) - return utf8.RuneError - } - - lx.prevWidths[0] = w - lx.pos += w - return r -} - -// ignore skips over the pending input before this point. -func (lx *lexer) ignore() { - lx.start = lx.pos -} - -// backup steps back one rune. Can be called 4 times between calls to next. -func (lx *lexer) backup() { - if lx.atEOF { - lx.atEOF = false - return - } - if lx.nprev < 1 { - panic("BUG in lexer: backed up too far") - } - w := lx.prevWidths[0] - lx.prevWidths[0] = lx.prevWidths[1] - lx.prevWidths[1] = lx.prevWidths[2] - lx.prevWidths[2] = lx.prevWidths[3] - lx.nprev-- - - lx.pos -= w - if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { - lx.line-- - } -} - -// accept consumes the next rune if it's equal to `valid`. -func (lx *lexer) accept(valid rune) bool { - if lx.next() == valid { - return true - } - lx.backup() - return false -} - -// peek returns but does not consume the next rune in the input. -func (lx *lexer) peek() rune { - r := lx.next() - lx.backup() - return r -} - -// skip ignores all input that matches the given predicate. -func (lx *lexer) skip(pred func(rune) bool) { - for { - r := lx.next() - if pred(r) { - continue - } - lx.backup() - lx.ignore() - return - } -} - -// error stops all lexing by emitting an error and returning `nil`. -// -// Note that any value that is a character is escaped if it's a special -// character (newlines, tabs, etc.). -func (lx *lexer) error(err error) stateFn { - if lx.atEOF { - return lx.errorPrevLine(err) - } - lx.items <- item{typ: itemError, pos: lx.getPos(), err: err} - return nil -} - -// errorfPrevline is like error(), but sets the position to the last column of -// the previous line. -// -// This is so that unexpected EOF or NL errors don't show on a new blank line. -func (lx *lexer) errorPrevLine(err error) stateFn { - pos := lx.getPos() - pos.Line-- - pos.Len = 1 - pos.Start = lx.pos - 1 - lx.items <- item{typ: itemError, pos: pos, err: err} - return nil -} - -// errorPos is like error(), but allows explicitly setting the position. -func (lx *lexer) errorPos(start, length int, err error) stateFn { - pos := lx.getPos() - pos.Start = start - pos.Len = length - lx.items <- item{typ: itemError, pos: pos, err: err} - return nil -} - -// errorf is like error, and creates a new error. -func (lx *lexer) errorf(format string, values ...interface{}) stateFn { - if lx.atEOF { - pos := lx.getPos() - pos.Line-- - pos.Len = 1 - pos.Start = lx.pos - 1 - lx.items <- item{typ: itemError, pos: pos, err: fmt.Errorf(format, values...)} - return nil - } - lx.items <- item{typ: itemError, pos: lx.getPos(), err: fmt.Errorf(format, values...)} - return nil -} - -func (lx *lexer) errorControlChar(cc rune) stateFn { - return lx.errorPos(lx.pos-1, 1, errLexControl{cc}) -} - -// lexTop consumes elements at the top level of TOML data. -func lexTop(lx *lexer) stateFn { - r := lx.next() - if isWhitespace(r) || isNL(r) { - return lexSkip(lx, lexTop) - } - switch r { - case '#': - lx.push(lexTop) - return lexCommentStart - case '[': - return lexTableStart - case eof: - if lx.pos > lx.start { - return lx.errorf("unexpected EOF") - } - lx.emit(itemEOF) - return nil - } - - // At this point, the only valid item can be a key, so we back up - // and let the key lexer do the rest. - lx.backup() - lx.push(lexTopEnd) - return lexKeyStart -} - -// lexTopEnd is entered whenever a top-level item has been consumed. (A value -// or a table.) It must see only whitespace, and will turn back to lexTop -// upon a newline. If it sees EOF, it will quit the lexer successfully. -func lexTopEnd(lx *lexer) stateFn { - r := lx.next() - switch { - case r == '#': - // a comment will read to a newline for us. - lx.push(lexTop) - return lexCommentStart - case isWhitespace(r): - return lexTopEnd - case isNL(r): - lx.ignore() - return lexTop - case r == eof: - lx.emit(itemEOF) - return nil - } - return lx.errorf( - "expected a top-level item to end with a newline, comment, or EOF, but got %q instead", - r) -} - -// lexTable lexes the beginning of a table. Namely, it makes sure that -// it starts with a character other than '.' and ']'. -// It assumes that '[' has already been consumed. -// It also handles the case that this is an item in an array of tables. -// e.g., '[[name]]'. -func lexTableStart(lx *lexer) stateFn { - if lx.peek() == '[' { - lx.next() - lx.emit(itemArrayTableStart) - lx.push(lexArrayTableEnd) - } else { - lx.emit(itemTableStart) - lx.push(lexTableEnd) - } - return lexTableNameStart -} - -func lexTableEnd(lx *lexer) stateFn { - lx.emit(itemTableEnd) - return lexTopEnd -} - -func lexArrayTableEnd(lx *lexer) stateFn { - if r := lx.next(); r != ']' { - return lx.errorf("expected end of table array name delimiter ']', but got %q instead", r) - } - lx.emit(itemArrayTableEnd) - return lexTopEnd -} - -func lexTableNameStart(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.peek(); { - case r == ']' || r == eof: - return lx.errorf("unexpected end of table name (table names cannot be empty)") - case r == '.': - return lx.errorf("unexpected table separator (table names cannot be empty)") - case r == '"' || r == '\'': - lx.ignore() - lx.push(lexTableNameEnd) - return lexQuotedName - default: - lx.push(lexTableNameEnd) - return lexBareName - } -} - -// lexTableNameEnd reads the end of a piece of a table name, optionally -// consuming whitespace. -func lexTableNameEnd(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.next(); { - case isWhitespace(r): - return lexTableNameEnd - case r == '.': - lx.ignore() - return lexTableNameStart - case r == ']': - return lx.pop() - default: - return lx.errorf("expected '.' or ']' to end table name, but got %q instead", r) - } -} - -// lexBareName lexes one part of a key or table. -// -// It assumes that at least one valid character for the table has already been -// read. -// -// Lexes only one part, e.g. only 'a' inside 'a.b'. -func lexBareName(lx *lexer) stateFn { - r := lx.next() - if isBareKeyChar(r, lx.tomlNext) { - return lexBareName - } - lx.backup() - lx.emit(itemText) - return lx.pop() -} - -// lexBareName lexes one part of a key or table. -// -// It assumes that at least one valid character for the table has already been -// read. -// -// Lexes only one part, e.g. only '"a"' inside '"a".b'. -func lexQuotedName(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r): - return lexSkip(lx, lexValue) - case r == '"': - lx.ignore() // ignore the '"' - return lexString - case r == '\'': - lx.ignore() // ignore the "'" - return lexRawString - case r == eof: - return lx.errorf("unexpected EOF; expected value") - default: - return lx.errorf("expected value but found %q instead", r) - } -} - -// lexKeyStart consumes all key parts until a '='. -func lexKeyStart(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.peek(); { - case r == '=' || r == eof: - return lx.errorf("unexpected '=': key name appears blank") - case r == '.': - return lx.errorf("unexpected '.': keys cannot start with a '.'") - case r == '"' || r == '\'': - lx.ignore() - fallthrough - default: // Bare key - lx.emit(itemKeyStart) - return lexKeyNameStart - } -} - -func lexKeyNameStart(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.peek(); { - case r == '=' || r == eof: - return lx.errorf("unexpected '='") - case r == '.': - return lx.errorf("unexpected '.'") - case r == '"' || r == '\'': - lx.ignore() - lx.push(lexKeyEnd) - return lexQuotedName - default: - lx.push(lexKeyEnd) - return lexBareName - } -} - -// lexKeyEnd consumes the end of a key and trims whitespace (up to the key -// separator). -func lexKeyEnd(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.next(); { - case isWhitespace(r): - return lexSkip(lx, lexKeyEnd) - case r == eof: - return lx.errorf("unexpected EOF; expected key separator '='") - case r == '.': - lx.ignore() - return lexKeyNameStart - case r == '=': - lx.emit(itemKeyEnd) - return lexSkip(lx, lexValue) - default: - return lx.errorf("expected '.' or '=', but got %q instead", r) - } -} - -// lexValue starts the consumption of a value anywhere a value is expected. -// lexValue will ignore whitespace. -// After a value is lexed, the last state on the next is popped and returned. -func lexValue(lx *lexer) stateFn { - // We allow whitespace to precede a value, but NOT newlines. - // In array syntax, the array states are responsible for ignoring newlines. - r := lx.next() - switch { - case isWhitespace(r): - return lexSkip(lx, lexValue) - case isDigit(r): - lx.backup() // avoid an extra state and use the same as above - return lexNumberOrDateStart - } - switch r { - case '[': - lx.ignore() - lx.emit(itemArray) - return lexArrayValue - case '{': - lx.ignore() - lx.emit(itemInlineTableStart) - return lexInlineTableValue - case '"': - if lx.accept('"') { - if lx.accept('"') { - lx.ignore() // Ignore """ - return lexMultilineString - } - lx.backup() - } - lx.ignore() // ignore the '"' - return lexString - case '\'': - if lx.accept('\'') { - if lx.accept('\'') { - lx.ignore() // Ignore """ - return lexMultilineRawString - } - lx.backup() - } - lx.ignore() // ignore the "'" - return lexRawString - case '.': // special error case, be kind to users - return lx.errorf("floats must start with a digit, not '.'") - case 'i', 'n': - if (lx.accept('n') && lx.accept('f')) || (lx.accept('a') && lx.accept('n')) { - lx.emit(itemFloat) - return lx.pop() - } - case '-', '+': - return lexDecimalNumberStart - } - if unicode.IsLetter(r) { - // Be permissive here; lexBool will give a nice error if the - // user wrote something like - // x = foo - // (i.e. not 'true' or 'false' but is something else word-like.) - lx.backup() - return lexBool - } - if r == eof { - return lx.errorf("unexpected EOF; expected value") - } - return lx.errorf("expected value but found %q instead", r) -} - -// lexArrayValue consumes one value in an array. It assumes that '[' or ',' -// have already been consumed. All whitespace and newlines are ignored. -func lexArrayValue(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r) || isNL(r): - return lexSkip(lx, lexArrayValue) - case r == '#': - lx.push(lexArrayValue) - return lexCommentStart - case r == ',': - return lx.errorf("unexpected comma") - case r == ']': - return lexArrayEnd - } - - lx.backup() - lx.push(lexArrayValueEnd) - return lexValue -} - -// lexArrayValueEnd consumes everything between the end of an array value and -// the next value (or the end of the array): it ignores whitespace and newlines -// and expects either a ',' or a ']'. -func lexArrayValueEnd(lx *lexer) stateFn { - switch r := lx.next(); { - case isWhitespace(r) || isNL(r): - return lexSkip(lx, lexArrayValueEnd) - case r == '#': - lx.push(lexArrayValueEnd) - return lexCommentStart - case r == ',': - lx.ignore() - return lexArrayValue // move on to the next value - case r == ']': - return lexArrayEnd - default: - return lx.errorf("expected a comma (',') or array terminator (']'), but got %s", runeOrEOF(r)) - } -} - -// lexArrayEnd finishes the lexing of an array. -// It assumes that a ']' has just been consumed. -func lexArrayEnd(lx *lexer) stateFn { - lx.ignore() - lx.emit(itemArrayEnd) - return lx.pop() -} - -// lexInlineTableValue consumes one key/value pair in an inline table. -// It assumes that '{' or ',' have already been consumed. Whitespace is ignored. -func lexInlineTableValue(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r): - return lexSkip(lx, lexInlineTableValue) - case isNL(r): - if lx.tomlNext { - return lexSkip(lx, lexInlineTableValue) - } - return lx.errorPrevLine(errLexInlineTableNL{}) - case r == '#': - lx.push(lexInlineTableValue) - return lexCommentStart - case r == ',': - return lx.errorf("unexpected comma") - case r == '}': - return lexInlineTableEnd - } - lx.backup() - lx.push(lexInlineTableValueEnd) - return lexKeyStart -} - -// lexInlineTableValueEnd consumes everything between the end of an inline table -// key/value pair and the next pair (or the end of the table): -// it ignores whitespace and expects either a ',' or a '}'. -func lexInlineTableValueEnd(lx *lexer) stateFn { - switch r := lx.next(); { - case isWhitespace(r): - return lexSkip(lx, lexInlineTableValueEnd) - case isNL(r): - if lx.tomlNext { - return lexSkip(lx, lexInlineTableValueEnd) - } - return lx.errorPrevLine(errLexInlineTableNL{}) - case r == '#': - lx.push(lexInlineTableValueEnd) - return lexCommentStart - case r == ',': - lx.ignore() - lx.skip(isWhitespace) - if lx.peek() == '}' { - if lx.tomlNext { - return lexInlineTableValueEnd - } - return lx.errorf("trailing comma not allowed in inline tables") - } - return lexInlineTableValue - case r == '}': - return lexInlineTableEnd - default: - return lx.errorf("expected a comma or an inline table terminator '}', but got %s instead", runeOrEOF(r)) - } -} - -func runeOrEOF(r rune) string { - if r == eof { - return "end of file" - } - return "'" + string(r) + "'" -} - -// lexInlineTableEnd finishes the lexing of an inline table. -// It assumes that a '}' has just been consumed. -func lexInlineTableEnd(lx *lexer) stateFn { - lx.ignore() - lx.emit(itemInlineTableEnd) - return lx.pop() -} - -// lexString consumes the inner contents of a string. It assumes that the -// beginning '"' has already been consumed and ignored. -func lexString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == eof: - return lx.errorf(`unexpected EOF; expected '"'`) - case isNL(r): - return lx.errorPrevLine(errLexStringNL{}) - case r == '\\': - lx.push(lexString) - return lexStringEscape - case r == '"': - lx.backup() - lx.emit(itemString) - lx.next() - lx.ignore() - return lx.pop() - } - return lexString -} - -// lexMultilineString consumes the inner contents of a string. It assumes that -// the beginning '"""' has already been consumed and ignored. -func lexMultilineString(lx *lexer) stateFn { - r := lx.next() - switch r { - default: - return lexMultilineString - case eof: - return lx.errorf(`unexpected EOF; expected '"""'`) - case '\\': - return lexMultilineStringEscape - case '"': - /// Found " → try to read two more "". - if lx.accept('"') { - if lx.accept('"') { - /// Peek ahead: the string can contain " and "", including at the - /// end: """str""""" - /// 6 or more at the end, however, is an error. - if lx.peek() == '"' { - /// Check if we already lexed 5 's; if so we have 6 now, and - /// that's just too many man! - /// - /// Second check is for the edge case: - /// - /// two quotes allowed. - /// vv - /// """lol \"""""" - /// ^^ ^^^---- closing three - /// escaped - /// - /// But ugly, but it works - if strings.HasSuffix(lx.current(), `"""""`) && !strings.HasSuffix(lx.current(), `\"""""`) { - return lx.errorf(`unexpected '""""""'`) - } - lx.backup() - lx.backup() - return lexMultilineString - } - - lx.backup() /// backup: don't include the """ in the item. - lx.backup() - lx.backup() - lx.emit(itemMultilineString) - lx.next() /// Read over ''' again and discard it. - lx.next() - lx.next() - lx.ignore() - return lx.pop() - } - lx.backup() - } - return lexMultilineString - } -} - -// lexRawString consumes a raw string. Nothing can be escaped in such a string. -// It assumes that the beginning "'" has already been consumed and ignored. -func lexRawString(lx *lexer) stateFn { - r := lx.next() - switch { - default: - return lexRawString - case r == eof: - return lx.errorf(`unexpected EOF; expected "'"`) - case isNL(r): - return lx.errorPrevLine(errLexStringNL{}) - case r == '\'': - lx.backup() - lx.emit(itemRawString) - lx.next() - lx.ignore() - return lx.pop() - } -} - -// lexMultilineRawString consumes a raw string. Nothing can be escaped in such a -// string. It assumes that the beginning triple-' has already been consumed and -// ignored. -func lexMultilineRawString(lx *lexer) stateFn { - r := lx.next() - switch r { - default: - return lexMultilineRawString - case eof: - return lx.errorf(`unexpected EOF; expected "'''"`) - case '\'': - /// Found ' → try to read two more ''. - if lx.accept('\'') { - if lx.accept('\'') { - /// Peek ahead: the string can contain ' and '', including at the - /// end: '''str''''' - /// 6 or more at the end, however, is an error. - if lx.peek() == '\'' { - /// Check if we already lexed 5 's; if so we have 6 now, and - /// that's just too many man! - if strings.HasSuffix(lx.current(), "'''''") { - return lx.errorf(`unexpected "''''''"`) - } - lx.backup() - lx.backup() - return lexMultilineRawString - } - - lx.backup() /// backup: don't include the ''' in the item. - lx.backup() - lx.backup() - lx.emit(itemRawMultilineString) - lx.next() /// Read over ''' again and discard it. - lx.next() - lx.next() - lx.ignore() - return lx.pop() - } - lx.backup() - } - return lexMultilineRawString - } -} - -// lexMultilineStringEscape consumes an escaped character. It assumes that the -// preceding '\\' has already been consumed. -func lexMultilineStringEscape(lx *lexer) stateFn { - if isNL(lx.next()) { /// \ escaping newline. - return lexMultilineString - } - lx.backup() - lx.push(lexMultilineString) - return lexStringEscape(lx) -} - -func lexStringEscape(lx *lexer) stateFn { - r := lx.next() - switch r { - case 'e': - if !lx.tomlNext { - return lx.error(errLexEscape{r}) - } - fallthrough - case 'b': - fallthrough - case 't': - fallthrough - case 'n': - fallthrough - case 'f': - fallthrough - case 'r': - fallthrough - case '"': - fallthrough - case ' ', '\t': - // Inside """ .. """ strings you can use \ to escape newlines, and any - // amount of whitespace can be between the \ and \n. - fallthrough - case '\\': - return lx.pop() - case 'x': - if !lx.tomlNext { - return lx.error(errLexEscape{r}) - } - return lexHexEscape - case 'u': - return lexShortUnicodeEscape - case 'U': - return lexLongUnicodeEscape - } - return lx.error(errLexEscape{r}) -} - -func lexHexEscape(lx *lexer) stateFn { - var r rune - for i := 0; i < 2; i++ { - r = lx.next() - if !isHexadecimal(r) { - return lx.errorf( - `expected two hexadecimal digits after '\x', but got %q instead`, - lx.current()) - } - } - return lx.pop() -} - -func lexShortUnicodeEscape(lx *lexer) stateFn { - var r rune - for i := 0; i < 4; i++ { - r = lx.next() - if !isHexadecimal(r) { - return lx.errorf( - `expected four hexadecimal digits after '\u', but got %q instead`, - lx.current()) - } - } - return lx.pop() -} - -func lexLongUnicodeEscape(lx *lexer) stateFn { - var r rune - for i := 0; i < 8; i++ { - r = lx.next() - if !isHexadecimal(r) { - return lx.errorf( - `expected eight hexadecimal digits after '\U', but got %q instead`, - lx.current()) - } - } - return lx.pop() -} - -// lexNumberOrDateStart processes the first character of a value which begins -// with a digit. It exists to catch values starting with '0', so that -// lexBaseNumberOrDate can differentiate base prefixed integers from other -// types. -func lexNumberOrDateStart(lx *lexer) stateFn { - r := lx.next() - switch r { - case '0': - return lexBaseNumberOrDate - } - - if !isDigit(r) { - // The only way to reach this state is if the value starts - // with a digit, so specifically treat anything else as an - // error. - return lx.errorf("expected a digit but got %q", r) - } - - return lexNumberOrDate -} - -// lexNumberOrDate consumes either an integer, float or datetime. -func lexNumberOrDate(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexNumberOrDate - } - switch r { - case '-', ':': - return lexDatetime - case '_': - return lexDecimalNumber - case '.', 'e', 'E': - return lexFloat - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexDatetime consumes a Datetime, to a first approximation. -// The parser validates that it matches one of the accepted formats. -func lexDatetime(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexDatetime - } - switch r { - case '-', ':', 'T', 't', ' ', '.', 'Z', 'z', '+': - return lexDatetime - } - - lx.backup() - lx.emitTrim(itemDatetime) - return lx.pop() -} - -// lexHexInteger consumes a hexadecimal integer after seeing the '0x' prefix. -func lexHexInteger(lx *lexer) stateFn { - r := lx.next() - if isHexadecimal(r) { - return lexHexInteger - } - switch r { - case '_': - return lexHexInteger - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexOctalInteger consumes an octal integer after seeing the '0o' prefix. -func lexOctalInteger(lx *lexer) stateFn { - r := lx.next() - if isOctal(r) { - return lexOctalInteger - } - switch r { - case '_': - return lexOctalInteger - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexBinaryInteger consumes a binary integer after seeing the '0b' prefix. -func lexBinaryInteger(lx *lexer) stateFn { - r := lx.next() - if isBinary(r) { - return lexBinaryInteger - } - switch r { - case '_': - return lexBinaryInteger - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexDecimalNumber consumes a decimal float or integer. -func lexDecimalNumber(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexDecimalNumber - } - switch r { - case '.', 'e', 'E': - return lexFloat - case '_': - return lexDecimalNumber - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexDecimalNumber consumes the first digit of a number beginning with a sign. -// It assumes the sign has already been consumed. Values which start with a sign -// are only allowed to be decimal integers or floats. -// -// The special "nan" and "inf" values are also recognized. -func lexDecimalNumberStart(lx *lexer) stateFn { - r := lx.next() - - // Special error cases to give users better error messages - switch r { - case 'i': - if !lx.accept('n') || !lx.accept('f') { - return lx.errorf("invalid float: '%s'", lx.current()) - } - lx.emit(itemFloat) - return lx.pop() - case 'n': - if !lx.accept('a') || !lx.accept('n') { - return lx.errorf("invalid float: '%s'", lx.current()) - } - lx.emit(itemFloat) - return lx.pop() - case '0': - p := lx.peek() - switch p { - case 'b', 'o', 'x': - return lx.errorf("cannot use sign with non-decimal numbers: '%s%c'", lx.current(), p) - } - case '.': - return lx.errorf("floats must start with a digit, not '.'") - } - - if isDigit(r) { - return lexDecimalNumber - } - - return lx.errorf("expected a digit but got %q", r) -} - -// lexBaseNumberOrDate differentiates between the possible values which -// start with '0'. It assumes that before reaching this state, the initial '0' -// has been consumed. -func lexBaseNumberOrDate(lx *lexer) stateFn { - r := lx.next() - // Note: All datetimes start with at least two digits, so we don't - // handle date characters (':', '-', etc.) here. - if isDigit(r) { - return lexNumberOrDate - } - switch r { - case '_': - // Can only be decimal, because there can't be an underscore - // between the '0' and the base designator, and dates can't - // contain underscores. - return lexDecimalNumber - case '.', 'e', 'E': - return lexFloat - case 'b': - r = lx.peek() - if !isBinary(r) { - lx.errorf("not a binary number: '%s%c'", lx.current(), r) - } - return lexBinaryInteger - case 'o': - r = lx.peek() - if !isOctal(r) { - lx.errorf("not an octal number: '%s%c'", lx.current(), r) - } - return lexOctalInteger - case 'x': - r = lx.peek() - if !isHexadecimal(r) { - lx.errorf("not a hexidecimal number: '%s%c'", lx.current(), r) - } - return lexHexInteger - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexFloat consumes the elements of a float. It allows any sequence of -// float-like characters, so floats emitted by the lexer are only a first -// approximation and must be validated by the parser. -func lexFloat(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexFloat - } - switch r { - case '_', '.', '-', '+', 'e', 'E': - return lexFloat - } - - lx.backup() - lx.emit(itemFloat) - return lx.pop() -} - -// lexBool consumes a bool string: 'true' or 'false. -func lexBool(lx *lexer) stateFn { - var rs []rune - for { - r := lx.next() - if !unicode.IsLetter(r) { - lx.backup() - break - } - rs = append(rs, r) - } - s := string(rs) - switch s { - case "true", "false": - lx.emit(itemBool) - return lx.pop() - } - return lx.errorf("expected value but found %q instead", s) -} - -// lexCommentStart begins the lexing of a comment. It will emit -// itemCommentStart and consume no characters, passing control to lexComment. -func lexCommentStart(lx *lexer) stateFn { - lx.ignore() - lx.emit(itemCommentStart) - return lexComment -} - -// lexComment lexes an entire comment. It assumes that '#' has been consumed. -// It will consume *up to* the first newline character, and pass control -// back to the last state on the stack. -func lexComment(lx *lexer) stateFn { - switch r := lx.next(); { - case isNL(r) || r == eof: - lx.backup() - lx.emit(itemText) - return lx.pop() - default: - return lexComment - } -} - -// lexSkip ignores all slurped input and moves on to the next state. -func lexSkip(lx *lexer, nextState stateFn) stateFn { - lx.ignore() - return nextState -} - -func (s stateFn) String() string { - name := runtime.FuncForPC(reflect.ValueOf(s).Pointer()).Name() - if i := strings.LastIndexByte(name, '.'); i > -1 { - name = name[i+1:] - } - if s == nil { - name = "" - } - return name + "()" -} - -func (itype itemType) String() string { - switch itype { - case itemError: - return "Error" - case itemNIL: - return "NIL" - case itemEOF: - return "EOF" - case itemText: - return "Text" - case itemString, itemRawString, itemMultilineString, itemRawMultilineString: - return "String" - case itemBool: - return "Bool" - case itemInteger: - return "Integer" - case itemFloat: - return "Float" - case itemDatetime: - return "DateTime" - case itemTableStart: - return "TableStart" - case itemTableEnd: - return "TableEnd" - case itemKeyStart: - return "KeyStart" - case itemKeyEnd: - return "KeyEnd" - case itemArray: - return "Array" - case itemArrayEnd: - return "ArrayEnd" - case itemCommentStart: - return "CommentStart" - case itemInlineTableStart: - return "InlineTableStart" - case itemInlineTableEnd: - return "InlineTableEnd" - } - panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype))) -} - -func (item item) String() string { - return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val) -} - -func isWhitespace(r rune) bool { return r == '\t' || r == ' ' } -func isNL(r rune) bool { return r == '\n' || r == '\r' } -func isControl(r rune) bool { // Control characters except \t, \r, \n - switch r { - case '\t', '\r', '\n': - return false - default: - return (r >= 0x00 && r <= 0x1f) || r == 0x7f - } -} -func isDigit(r rune) bool { return r >= '0' && r <= '9' } -func isBinary(r rune) bool { return r == '0' || r == '1' } -func isOctal(r rune) bool { return r >= '0' && r <= '7' } -func isHexadecimal(r rune) bool { - return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F') -} - -func isBareKeyChar(r rune, tomlNext bool) bool { - if tomlNext { - return (r >= 'A' && r <= 'Z') || - (r >= 'a' && r <= 'z') || - (r >= '0' && r <= '9') || - r == '_' || r == '-' || - r == 0xb2 || r == 0xb3 || r == 0xb9 || (r >= 0xbc && r <= 0xbe) || - (r >= 0xc0 && r <= 0xd6) || (r >= 0xd8 && r <= 0xf6) || (r >= 0xf8 && r <= 0x037d) || - (r >= 0x037f && r <= 0x1fff) || - (r >= 0x200c && r <= 0x200d) || (r >= 0x203f && r <= 0x2040) || - (r >= 0x2070 && r <= 0x218f) || (r >= 0x2460 && r <= 0x24ff) || - (r >= 0x2c00 && r <= 0x2fef) || (r >= 0x3001 && r <= 0xd7ff) || - (r >= 0xf900 && r <= 0xfdcf) || (r >= 0xfdf0 && r <= 0xfffd) || - (r >= 0x10000 && r <= 0xeffff) - } - - return (r >= 'A' && r <= 'Z') || - (r >= 'a' && r <= 'z') || - (r >= '0' && r <= '9') || - r == '_' || r == '-' -} diff --git a/vendor/github.com/BurntSushi/toml/meta.go b/vendor/github.com/BurntSushi/toml/meta.go deleted file mode 100644 index 2e78b24e95..0000000000 --- a/vendor/github.com/BurntSushi/toml/meta.go +++ /dev/null @@ -1,121 +0,0 @@ -package toml - -import ( - "strings" -) - -// MetaData allows access to meta information about TOML data that's not -// accessible otherwise. -// -// It allows checking if a key is defined in the TOML data, whether any keys -// were undecoded, and the TOML type of a key. -type MetaData struct { - context Key // Used only during decoding. - - keyInfo map[string]keyInfo - mapping map[string]interface{} - keys []Key - decoded map[string]struct{} - data []byte // Input file; for errors. -} - -// IsDefined reports if the key exists in the TOML data. -// -// The key should be specified hierarchically, for example to access the TOML -// key "a.b.c" you would use IsDefined("a", "b", "c"). Keys are case sensitive. -// -// Returns false for an empty key. -func (md *MetaData) IsDefined(key ...string) bool { - if len(key) == 0 { - return false - } - - var ( - hash map[string]interface{} - ok bool - hashOrVal interface{} = md.mapping - ) - for _, k := range key { - if hash, ok = hashOrVal.(map[string]interface{}); !ok { - return false - } - if hashOrVal, ok = hash[k]; !ok { - return false - } - } - return true -} - -// Type returns a string representation of the type of the key specified. -// -// Type will return the empty string if given an empty key or a key that does -// not exist. Keys are case sensitive. -func (md *MetaData) Type(key ...string) string { - if ki, ok := md.keyInfo[Key(key).String()]; ok { - return ki.tomlType.typeString() - } - return "" -} - -// Keys returns a slice of every key in the TOML data, including key groups. -// -// Each key is itself a slice, where the first element is the top of the -// hierarchy and the last is the most specific. The list will have the same -// order as the keys appeared in the TOML data. -// -// All keys returned are non-empty. -func (md *MetaData) Keys() []Key { - return md.keys -} - -// Undecoded returns all keys that have not been decoded in the order in which -// they appear in the original TOML document. -// -// This includes keys that haven't been decoded because of a [Primitive] value. -// Once the Primitive value is decoded, the keys will be considered decoded. -// -// Also note that decoding into an empty interface will result in no decoding, -// and so no keys will be considered decoded. -// -// In this sense, the Undecoded keys correspond to keys in the TOML document -// that do not have a concrete type in your representation. -func (md *MetaData) Undecoded() []Key { - undecoded := make([]Key, 0, len(md.keys)) - for _, key := range md.keys { - if _, ok := md.decoded[key.String()]; !ok { - undecoded = append(undecoded, key) - } - } - return undecoded -} - -// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get -// values of this type. -type Key []string - -func (k Key) String() string { - ss := make([]string, len(k)) - for i := range k { - ss[i] = k.maybeQuoted(i) - } - return strings.Join(ss, ".") -} - -func (k Key) maybeQuoted(i int) string { - if k[i] == "" { - return `""` - } - for _, c := range k[i] { - if !isBareKeyChar(c, false) { - return `"` + dblQuotedReplacer.Replace(k[i]) + `"` - } - } - return k[i] -} - -func (k Key) add(piece string) Key { - newKey := make(Key, len(k)+1) - copy(newKey, k) - newKey[len(k)] = piece - return newKey -} diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go deleted file mode 100644 index 9c19153698..0000000000 --- a/vendor/github.com/BurntSushi/toml/parse.go +++ /dev/null @@ -1,811 +0,0 @@ -package toml - -import ( - "fmt" - "os" - "strconv" - "strings" - "time" - "unicode/utf8" - - "github.com/BurntSushi/toml/internal" -) - -type parser struct { - lx *lexer - context Key // Full key for the current hash in scope. - currentKey string // Base key name for everything except hashes. - pos Position // Current position in the TOML file. - tomlNext bool - - ordered []Key // List of keys in the order that they appear in the TOML data. - - keyInfo map[string]keyInfo // Map keyname → info about the TOML key. - mapping map[string]interface{} // Map keyname → key value. - implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names"). -} - -type keyInfo struct { - pos Position - tomlType tomlType -} - -func parse(data string) (p *parser, err error) { - _, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110") - - defer func() { - if r := recover(); r != nil { - if pErr, ok := r.(ParseError); ok { - pErr.input = data - err = pErr - return - } - panic(r) - } - }() - - // Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString() - // which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add - // it anyway. - if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16 - data = data[2:] - } else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8 - data = data[3:] - } - - // Examine first few bytes for NULL bytes; this probably means it's a UTF-16 - // file (second byte in surrogate pair being NULL). Again, do this here to - // avoid having to deal with UTF-8/16 stuff in the lexer. - ex := 6 - if len(data) < 6 { - ex = len(data) - } - if i := strings.IndexRune(data[:ex], 0); i > -1 { - return nil, ParseError{ - Message: "files cannot contain NULL bytes; probably using UTF-16; TOML files must be UTF-8", - Position: Position{Line: 1, Start: i, Len: 1}, - Line: 1, - input: data, - } - } - - p = &parser{ - keyInfo: make(map[string]keyInfo), - mapping: make(map[string]interface{}), - lx: lex(data, tomlNext), - ordered: make([]Key, 0), - implicits: make(map[string]struct{}), - tomlNext: tomlNext, - } - for { - item := p.next() - if item.typ == itemEOF { - break - } - p.topLevel(item) - } - - return p, nil -} - -func (p *parser) panicErr(it item, err error) { - panic(ParseError{ - err: err, - Position: it.pos, - Line: it.pos.Len, - LastKey: p.current(), - }) -} - -func (p *parser) panicItemf(it item, format string, v ...interface{}) { - panic(ParseError{ - Message: fmt.Sprintf(format, v...), - Position: it.pos, - Line: it.pos.Len, - LastKey: p.current(), - }) -} - -func (p *parser) panicf(format string, v ...interface{}) { - panic(ParseError{ - Message: fmt.Sprintf(format, v...), - Position: p.pos, - Line: p.pos.Line, - LastKey: p.current(), - }) -} - -func (p *parser) next() item { - it := p.lx.nextItem() - //fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.pos.Line, it.val) - if it.typ == itemError { - if it.err != nil { - panic(ParseError{ - Position: it.pos, - Line: it.pos.Line, - LastKey: p.current(), - err: it.err, - }) - } - - p.panicItemf(it, "%s", it.val) - } - return it -} - -func (p *parser) nextPos() item { - it := p.next() - p.pos = it.pos - return it -} - -func (p *parser) bug(format string, v ...interface{}) { - panic(fmt.Sprintf("BUG: "+format+"\n\n", v...)) -} - -func (p *parser) expect(typ itemType) item { - it := p.next() - p.assertEqual(typ, it.typ) - return it -} - -func (p *parser) assertEqual(expected, got itemType) { - if expected != got { - p.bug("Expected '%s' but got '%s'.", expected, got) - } -} - -func (p *parser) topLevel(item item) { - switch item.typ { - case itemCommentStart: // # .. - p.expect(itemText) - case itemTableStart: // [ .. ] - name := p.nextPos() - - var key Key - for ; name.typ != itemTableEnd && name.typ != itemEOF; name = p.next() { - key = append(key, p.keyString(name)) - } - p.assertEqual(itemTableEnd, name.typ) - - p.addContext(key, false) - p.setType("", tomlHash, item.pos) - p.ordered = append(p.ordered, key) - case itemArrayTableStart: // [[ .. ]] - name := p.nextPos() - - var key Key - for ; name.typ != itemArrayTableEnd && name.typ != itemEOF; name = p.next() { - key = append(key, p.keyString(name)) - } - p.assertEqual(itemArrayTableEnd, name.typ) - - p.addContext(key, true) - p.setType("", tomlArrayHash, item.pos) - p.ordered = append(p.ordered, key) - case itemKeyStart: // key = .. - outerContext := p.context - /// Read all the key parts (e.g. 'a' and 'b' in 'a.b') - k := p.nextPos() - var key Key - for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() { - key = append(key, p.keyString(k)) - } - p.assertEqual(itemKeyEnd, k.typ) - - /// The current key is the last part. - p.currentKey = key[len(key)-1] - - /// All the other parts (if any) are the context; need to set each part - /// as implicit. - context := key[:len(key)-1] - for i := range context { - p.addImplicitContext(append(p.context, context[i:i+1]...)) - } - p.ordered = append(p.ordered, p.context.add(p.currentKey)) - - /// Set value. - vItem := p.next() - val, typ := p.value(vItem, false) - p.set(p.currentKey, val, typ, vItem.pos) - - /// Remove the context we added (preserving any context from [tbl] lines). - p.context = outerContext - p.currentKey = "" - default: - p.bug("Unexpected type at top level: %s", item.typ) - } -} - -// Gets a string for a key (or part of a key in a table name). -func (p *parser) keyString(it item) string { - switch it.typ { - case itemText: - return it.val - case itemString, itemMultilineString, - itemRawString, itemRawMultilineString: - s, _ := p.value(it, false) - return s.(string) - default: - p.bug("Unexpected key type: %s", it.typ) - } - panic("unreachable") -} - -var datetimeRepl = strings.NewReplacer( - "z", "Z", - "t", "T", - " ", "T") - -// value translates an expected value from the lexer into a Go value wrapped -// as an empty interface. -func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) { - switch it.typ { - case itemString: - return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it) - case itemMultilineString: - return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it) - case itemRawString: - return it.val, p.typeOfPrimitive(it) - case itemRawMultilineString: - return stripFirstNewline(it.val), p.typeOfPrimitive(it) - case itemInteger: - return p.valueInteger(it) - case itemFloat: - return p.valueFloat(it) - case itemBool: - switch it.val { - case "true": - return true, p.typeOfPrimitive(it) - case "false": - return false, p.typeOfPrimitive(it) - default: - p.bug("Expected boolean value, but got '%s'.", it.val) - } - case itemDatetime: - return p.valueDatetime(it) - case itemArray: - return p.valueArray(it) - case itemInlineTableStart: - return p.valueInlineTable(it, parentIsArray) - default: - p.bug("Unexpected value type: %s", it.typ) - } - panic("unreachable") -} - -func (p *parser) valueInteger(it item) (interface{}, tomlType) { - if !numUnderscoresOK(it.val) { - p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val) - } - if numHasLeadingZero(it.val) { - p.panicItemf(it, "Invalid integer %q: cannot have leading zeroes", it.val) - } - - num, err := strconv.ParseInt(it.val, 0, 64) - if err != nil { - // Distinguish integer values. Normally, it'd be a bug if the lexer - // provides an invalid integer, but it's possible that the number is - // out of range of valid values (which the lexer cannot determine). - // So mark the former as a bug but the latter as a legitimate user - // error. - if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { - p.panicErr(it, errParseRange{i: it.val, size: "int64"}) - } else { - p.bug("Expected integer value, but got '%s'.", it.val) - } - } - return num, p.typeOfPrimitive(it) -} - -func (p *parser) valueFloat(it item) (interface{}, tomlType) { - parts := strings.FieldsFunc(it.val, func(r rune) bool { - switch r { - case '.', 'e', 'E': - return true - } - return false - }) - for _, part := range parts { - if !numUnderscoresOK(part) { - p.panicItemf(it, "Invalid float %q: underscores must be surrounded by digits", it.val) - } - } - if len(parts) > 0 && numHasLeadingZero(parts[0]) { - p.panicItemf(it, "Invalid float %q: cannot have leading zeroes", it.val) - } - if !numPeriodsOK(it.val) { - // As a special case, numbers like '123.' or '1.e2', - // which are valid as far as Go/strconv are concerned, - // must be rejected because TOML says that a fractional - // part consists of '.' followed by 1+ digits. - p.panicItemf(it, "Invalid float %q: '.' must be followed by one or more digits", it.val) - } - val := strings.Replace(it.val, "_", "", -1) - if val == "+nan" || val == "-nan" { // Go doesn't support this, but TOML spec does. - val = "nan" - } - num, err := strconv.ParseFloat(val, 64) - if err != nil { - if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { - p.panicErr(it, errParseRange{i: it.val, size: "float64"}) - } else { - p.panicItemf(it, "Invalid float value: %q", it.val) - } - } - return num, p.typeOfPrimitive(it) -} - -var dtTypes = []struct { - fmt string - zone *time.Location - next bool -}{ - {time.RFC3339Nano, time.Local, false}, - {"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false}, - {"2006-01-02", internal.LocalDate, false}, - {"15:04:05.999999999", internal.LocalTime, false}, - - // tomlNext - {"2006-01-02T15:04Z07:00", time.Local, true}, - {"2006-01-02T15:04", internal.LocalDatetime, true}, - {"15:04", internal.LocalTime, true}, -} - -func (p *parser) valueDatetime(it item) (interface{}, tomlType) { - it.val = datetimeRepl.Replace(it.val) - var ( - t time.Time - ok bool - err error - ) - for _, dt := range dtTypes { - if dt.next && !p.tomlNext { - continue - } - t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone) - if err == nil { - ok = true - break - } - } - if !ok { - p.panicItemf(it, "Invalid TOML Datetime: %q.", it.val) - } - return t, p.typeOfPrimitive(it) -} - -func (p *parser) valueArray(it item) (interface{}, tomlType) { - p.setType(p.currentKey, tomlArray, it.pos) - - var ( - types []tomlType - - // Initialize to a non-nil empty slice. This makes it consistent with - // how S = [] decodes into a non-nil slice inside something like struct - // { S []string }. See #338 - array = []interface{}{} - ) - for it = p.next(); it.typ != itemArrayEnd; it = p.next() { - if it.typ == itemCommentStart { - p.expect(itemText) - continue - } - - val, typ := p.value(it, true) - array = append(array, val) - types = append(types, typ) - - // XXX: types isn't used here, we need it to record the accurate type - // information. - // - // Not entirely sure how to best store this; could use "key[0]", - // "key[1]" notation, or maybe store it on the Array type? - _ = types - } - return array, tomlArray -} - -func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tomlType) { - var ( - hash = make(map[string]interface{}) - outerContext = p.context - outerKey = p.currentKey - ) - - p.context = append(p.context, p.currentKey) - prevContext := p.context - p.currentKey = "" - - p.addImplicit(p.context) - p.addContext(p.context, parentIsArray) - - /// Loop over all table key/value pairs. - for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() { - if it.typ == itemCommentStart { - p.expect(itemText) - continue - } - - /// Read all key parts. - k := p.nextPos() - var key Key - for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() { - key = append(key, p.keyString(k)) - } - p.assertEqual(itemKeyEnd, k.typ) - - /// The current key is the last part. - p.currentKey = key[len(key)-1] - - /// All the other parts (if any) are the context; need to set each part - /// as implicit. - context := key[:len(key)-1] - for i := range context { - p.addImplicitContext(append(p.context, context[i:i+1]...)) - } - p.ordered = append(p.ordered, p.context.add(p.currentKey)) - - /// Set the value. - val, typ := p.value(p.next(), false) - p.set(p.currentKey, val, typ, it.pos) - hash[p.currentKey] = val - - /// Restore context. - p.context = prevContext - } - p.context = outerContext - p.currentKey = outerKey - return hash, tomlHash -} - -// numHasLeadingZero checks if this number has leading zeroes, allowing for '0', -// +/- signs, and base prefixes. -func numHasLeadingZero(s string) bool { - if len(s) > 1 && s[0] == '0' && !(s[1] == 'b' || s[1] == 'o' || s[1] == 'x') { // Allow 0b, 0o, 0x - return true - } - if len(s) > 2 && (s[0] == '-' || s[0] == '+') && s[1] == '0' { - return true - } - return false -} - -// numUnderscoresOK checks whether each underscore in s is surrounded by -// characters that are not underscores. -func numUnderscoresOK(s string) bool { - switch s { - case "nan", "+nan", "-nan", "inf", "-inf", "+inf": - return true - } - accept := false - for _, r := range s { - if r == '_' { - if !accept { - return false - } - } - - // isHexadecimal is a superset of all the permissable characters - // surrounding an underscore. - accept = isHexadecimal(r) - } - return accept -} - -// numPeriodsOK checks whether every period in s is followed by a digit. -func numPeriodsOK(s string) bool { - period := false - for _, r := range s { - if period && !isDigit(r) { - return false - } - period = r == '.' - } - return !period -} - -// Set the current context of the parser, where the context is either a hash or -// an array of hashes, depending on the value of the `array` parameter. -// -// Establishing the context also makes sure that the key isn't a duplicate, and -// will create implicit hashes automatically. -func (p *parser) addContext(key Key, array bool) { - var ok bool - - // Always start at the top level and drill down for our context. - hashContext := p.mapping - keyContext := make(Key, 0) - - // We only need implicit hashes for key[0:-1] - for _, k := range key[0 : len(key)-1] { - _, ok = hashContext[k] - keyContext = append(keyContext, k) - - // No key? Make an implicit hash and move on. - if !ok { - p.addImplicit(keyContext) - hashContext[k] = make(map[string]interface{}) - } - - // If the hash context is actually an array of tables, then set - // the hash context to the last element in that array. - // - // Otherwise, it better be a table, since this MUST be a key group (by - // virtue of it not being the last element in a key). - switch t := hashContext[k].(type) { - case []map[string]interface{}: - hashContext = t[len(t)-1] - case map[string]interface{}: - hashContext = t - default: - p.panicf("Key '%s' was already created as a hash.", keyContext) - } - } - - p.context = keyContext - if array { - // If this is the first element for this array, then allocate a new - // list of tables for it. - k := key[len(key)-1] - if _, ok := hashContext[k]; !ok { - hashContext[k] = make([]map[string]interface{}, 0, 4) - } - - // Add a new table. But make sure the key hasn't already been used - // for something else. - if hash, ok := hashContext[k].([]map[string]interface{}); ok { - hashContext[k] = append(hash, make(map[string]interface{})) - } else { - p.panicf("Key '%s' was already created and cannot be used as an array.", key) - } - } else { - p.setValue(key[len(key)-1], make(map[string]interface{})) - } - p.context = append(p.context, key[len(key)-1]) -} - -// set calls setValue and setType. -func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) { - p.setValue(key, val) - p.setType(key, typ, pos) -} - -// setValue sets the given key to the given value in the current context. -// It will make sure that the key hasn't already been defined, account for -// implicit key groups. -func (p *parser) setValue(key string, value interface{}) { - var ( - tmpHash interface{} - ok bool - hash = p.mapping - keyContext Key - ) - for _, k := range p.context { - keyContext = append(keyContext, k) - if tmpHash, ok = hash[k]; !ok { - p.bug("Context for key '%s' has not been established.", keyContext) - } - switch t := tmpHash.(type) { - case []map[string]interface{}: - // The context is a table of hashes. Pick the most recent table - // defined as the current hash. - hash = t[len(t)-1] - case map[string]interface{}: - hash = t - default: - p.panicf("Key '%s' has already been defined.", keyContext) - } - } - keyContext = append(keyContext, key) - - if _, ok := hash[key]; ok { - // Normally redefining keys isn't allowed, but the key could have been - // defined implicitly and it's allowed to be redefined concretely. (See - // the `valid/implicit-and-explicit-after.toml` in toml-test) - // - // But we have to make sure to stop marking it as an implicit. (So that - // another redefinition provokes an error.) - // - // Note that since it has already been defined (as a hash), we don't - // want to overwrite it. So our business is done. - if p.isArray(keyContext) { - p.removeImplicit(keyContext) - hash[key] = value - return - } - if p.isImplicit(keyContext) { - p.removeImplicit(keyContext) - return - } - - // Otherwise, we have a concrete key trying to override a previous - // key, which is *always* wrong. - p.panicf("Key '%s' has already been defined.", keyContext) - } - - hash[key] = value -} - -// setType sets the type of a particular value at a given key. It should be -// called immediately AFTER setValue. -// -// Note that if `key` is empty, then the type given will be applied to the -// current context (which is either a table or an array of tables). -func (p *parser) setType(key string, typ tomlType, pos Position) { - keyContext := make(Key, 0, len(p.context)+1) - keyContext = append(keyContext, p.context...) - if len(key) > 0 { // allow type setting for hashes - keyContext = append(keyContext, key) - } - // Special case to make empty keys ("" = 1) work. - // Without it it will set "" rather than `""`. - // TODO: why is this needed? And why is this only needed here? - if len(keyContext) == 0 { - keyContext = Key{""} - } - p.keyInfo[keyContext.String()] = keyInfo{tomlType: typ, pos: pos} -} - -// Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and -// "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly). -func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} } -func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) } -func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok } -func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray } -func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) } - -// current returns the full key name of the current context. -func (p *parser) current() string { - if len(p.currentKey) == 0 { - return p.context.String() - } - if len(p.context) == 0 { - return p.currentKey - } - return fmt.Sprintf("%s.%s", p.context, p.currentKey) -} - -func stripFirstNewline(s string) string { - if len(s) > 0 && s[0] == '\n' { - return s[1:] - } - if len(s) > 1 && s[0] == '\r' && s[1] == '\n' { - return s[2:] - } - return s -} - -// stripEscapedNewlines removes whitespace after line-ending backslashes in -// multiline strings. -// -// A line-ending backslash is an unescaped \ followed only by whitespace until -// the next newline. After a line-ending backslash, all whitespace is removed -// until the next non-whitespace character. -func (p *parser) stripEscapedNewlines(s string) string { - var b strings.Builder - var i int - for { - ix := strings.Index(s[i:], `\`) - if ix < 0 { - b.WriteString(s) - return b.String() - } - i += ix - - if len(s) > i+1 && s[i+1] == '\\' { - // Escaped backslash. - i += 2 - continue - } - // Scan until the next non-whitespace. - j := i + 1 - whitespaceLoop: - for ; j < len(s); j++ { - switch s[j] { - case ' ', '\t', '\r', '\n': - default: - break whitespaceLoop - } - } - if j == i+1 { - // Not a whitespace escape. - i++ - continue - } - if !strings.Contains(s[i:j], "\n") { - // This is not a line-ending backslash. - // (It's a bad escape sequence, but we can let - // replaceEscapes catch it.) - i++ - continue - } - b.WriteString(s[:i]) - s = s[j:] - i = 0 - } -} - -func (p *parser) replaceEscapes(it item, str string) string { - replaced := make([]rune, 0, len(str)) - s := []byte(str) - r := 0 - for r < len(s) { - if s[r] != '\\' { - c, size := utf8.DecodeRune(s[r:]) - r += size - replaced = append(replaced, c) - continue - } - r += 1 - if r >= len(s) { - p.bug("Escape sequence at end of string.") - return "" - } - switch s[r] { - default: - p.bug("Expected valid escape code after \\, but got %q.", s[r]) - case ' ', '\t': - p.panicItemf(it, "invalid escape: '\\%c'", s[r]) - case 'b': - replaced = append(replaced, rune(0x0008)) - r += 1 - case 't': - replaced = append(replaced, rune(0x0009)) - r += 1 - case 'n': - replaced = append(replaced, rune(0x000A)) - r += 1 - case 'f': - replaced = append(replaced, rune(0x000C)) - r += 1 - case 'r': - replaced = append(replaced, rune(0x000D)) - r += 1 - case 'e': - if p.tomlNext { - replaced = append(replaced, rune(0x001B)) - r += 1 - } - case '"': - replaced = append(replaced, rune(0x0022)) - r += 1 - case '\\': - replaced = append(replaced, rune(0x005C)) - r += 1 - case 'x': - if p.tomlNext { - escaped := p.asciiEscapeToUnicode(it, s[r+1:r+3]) - replaced = append(replaced, escaped) - r += 3 - } - case 'u': - // At this point, we know we have a Unicode escape of the form - // `uXXXX` at [r, r+5). (Because the lexer guarantees this - // for us.) - escaped := p.asciiEscapeToUnicode(it, s[r+1:r+5]) - replaced = append(replaced, escaped) - r += 5 - case 'U': - // At this point, we know we have a Unicode escape of the form - // `uXXXX` at [r, r+9). (Because the lexer guarantees this - // for us.) - escaped := p.asciiEscapeToUnicode(it, s[r+1:r+9]) - replaced = append(replaced, escaped) - r += 9 - } - } - return string(replaced) -} - -func (p *parser) asciiEscapeToUnicode(it item, bs []byte) rune { - s := string(bs) - hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32) - if err != nil { - p.bug("Could not parse '%s' as a hexadecimal number, but the lexer claims it's OK: %s", s, err) - } - if !utf8.ValidRune(rune(hex)) { - p.panicItemf(it, "Escaped character '\\u%s' is not valid UTF-8.", s) - } - return rune(hex) -} diff --git a/vendor/github.com/BurntSushi/toml/type_fields.go b/vendor/github.com/BurntSushi/toml/type_fields.go deleted file mode 100644 index 254ca82e54..0000000000 --- a/vendor/github.com/BurntSushi/toml/type_fields.go +++ /dev/null @@ -1,242 +0,0 @@ -package toml - -// Struct field handling is adapted from code in encoding/json: -// -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the Go distribution. - -import ( - "reflect" - "sort" - "sync" -) - -// A field represents a single field found in a struct. -type field struct { - name string // the name of the field (`toml` tag included) - tag bool // whether field has a `toml` tag - index []int // represents the depth of an anonymous field - typ reflect.Type // the type of the field -} - -// byName sorts field by name, breaking ties with depth, -// then breaking ties with "name came from toml tag", then -// breaking ties with index sequence. -type byName []field - -func (x byName) Len() int { return len(x) } - -func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byName) Less(i, j int) bool { - if x[i].name != x[j].name { - return x[i].name < x[j].name - } - if len(x[i].index) != len(x[j].index) { - return len(x[i].index) < len(x[j].index) - } - if x[i].tag != x[j].tag { - return x[i].tag - } - return byIndex(x).Less(i, j) -} - -// byIndex sorts field by index sequence. -type byIndex []field - -func (x byIndex) Len() int { return len(x) } - -func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byIndex) Less(i, j int) bool { - for k, xik := range x[i].index { - if k >= len(x[j].index) { - return false - } - if xik != x[j].index[k] { - return xik < x[j].index[k] - } - } - return len(x[i].index) < len(x[j].index) -} - -// typeFields returns a list of fields that TOML should recognize for the given -// type. The algorithm is breadth-first search over the set of structs to -// include - the top struct and then any reachable anonymous structs. -func typeFields(t reflect.Type) []field { - // Anonymous fields to explore at the current level and the next. - current := []field{} - next := []field{{typ: t}} - - // Count of queued names for current level and the next. - var count map[reflect.Type]int - var nextCount map[reflect.Type]int - - // Types already visited at an earlier level. - visited := map[reflect.Type]bool{} - - // Fields found. - var fields []field - - for len(next) > 0 { - current, next = next, current[:0] - count, nextCount = nextCount, map[reflect.Type]int{} - - for _, f := range current { - if visited[f.typ] { - continue - } - visited[f.typ] = true - - // Scan f.typ for fields to include. - for i := 0; i < f.typ.NumField(); i++ { - sf := f.typ.Field(i) - if sf.PkgPath != "" && !sf.Anonymous { // unexported - continue - } - opts := getOptions(sf.Tag) - if opts.skip { - continue - } - index := make([]int, len(f.index)+1) - copy(index, f.index) - index[len(f.index)] = i - - ft := sf.Type - if ft.Name() == "" && ft.Kind() == reflect.Ptr { - // Follow pointer. - ft = ft.Elem() - } - - // Record found field and index sequence. - if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { - tagged := opts.name != "" - name := opts.name - if name == "" { - name = sf.Name - } - fields = append(fields, field{name, tagged, index, ft}) - if count[f.typ] > 1 { - // If there were multiple instances, add a second, - // so that the annihilation code will see a duplicate. - // It only cares about the distinction between 1 or 2, - // so don't bother generating any more copies. - fields = append(fields, fields[len(fields)-1]) - } - continue - } - - // Record new anonymous struct to explore in next round. - nextCount[ft]++ - if nextCount[ft] == 1 { - f := field{name: ft.Name(), index: index, typ: ft} - next = append(next, f) - } - } - } - } - - sort.Sort(byName(fields)) - - // Delete all fields that are hidden by the Go rules for embedded fields, - // except that fields with TOML tags are promoted. - - // The fields are sorted in primary order of name, secondary order - // of field index length. Loop over names; for each name, delete - // hidden fields by choosing the one dominant field that survives. - out := fields[:0] - for advance, i := 0, 0; i < len(fields); i += advance { - // One iteration per name. - // Find the sequence of fields with the name of this first field. - fi := fields[i] - name := fi.name - for advance = 1; i+advance < len(fields); advance++ { - fj := fields[i+advance] - if fj.name != name { - break - } - } - if advance == 1 { // Only one field with this name - out = append(out, fi) - continue - } - dominant, ok := dominantField(fields[i : i+advance]) - if ok { - out = append(out, dominant) - } - } - - fields = out - sort.Sort(byIndex(fields)) - - return fields -} - -// dominantField looks through the fields, all of which are known to -// have the same name, to find the single field that dominates the -// others using Go's embedding rules, modified by the presence of -// TOML tags. If there are multiple top-level fields, the boolean -// will be false: This condition is an error in Go and we skip all -// the fields. -func dominantField(fields []field) (field, bool) { - // The fields are sorted in increasing index-length order. The winner - // must therefore be one with the shortest index length. Drop all - // longer entries, which is easy: just truncate the slice. - length := len(fields[0].index) - tagged := -1 // Index of first tagged field. - for i, f := range fields { - if len(f.index) > length { - fields = fields[:i] - break - } - if f.tag { - if tagged >= 0 { - // Multiple tagged fields at the same level: conflict. - // Return no field. - return field{}, false - } - tagged = i - } - } - if tagged >= 0 { - return fields[tagged], true - } - // All remaining fields have the same length. If there's more than one, - // we have a conflict (two fields named "X" at the same level) and we - // return no field. - if len(fields) > 1 { - return field{}, false - } - return fields[0], true -} - -var fieldCache struct { - sync.RWMutex - m map[reflect.Type][]field -} - -// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. -func cachedTypeFields(t reflect.Type) []field { - fieldCache.RLock() - f := fieldCache.m[t] - fieldCache.RUnlock() - if f != nil { - return f - } - - // Compute fields without lock. - // Might duplicate effort but won't hold other computations back. - f = typeFields(t) - if f == nil { - f = []field{} - } - - fieldCache.Lock() - if fieldCache.m == nil { - fieldCache.m = map[reflect.Type][]field{} - } - fieldCache.m[t] = f - fieldCache.Unlock() - return f -} diff --git a/vendor/github.com/BurntSushi/toml/type_toml.go b/vendor/github.com/BurntSushi/toml/type_toml.go deleted file mode 100644 index 4e90d77373..0000000000 --- a/vendor/github.com/BurntSushi/toml/type_toml.go +++ /dev/null @@ -1,70 +0,0 @@ -package toml - -// tomlType represents any Go type that corresponds to a TOML type. -// While the first draft of the TOML spec has a simplistic type system that -// probably doesn't need this level of sophistication, we seem to be militating -// toward adding real composite types. -type tomlType interface { - typeString() string -} - -// typeEqual accepts any two types and returns true if they are equal. -func typeEqual(t1, t2 tomlType) bool { - if t1 == nil || t2 == nil { - return false - } - return t1.typeString() == t2.typeString() -} - -func typeIsTable(t tomlType) bool { - return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) -} - -type tomlBaseType string - -func (btype tomlBaseType) typeString() string { - return string(btype) -} - -func (btype tomlBaseType) String() string { - return btype.typeString() -} - -var ( - tomlInteger tomlBaseType = "Integer" - tomlFloat tomlBaseType = "Float" - tomlDatetime tomlBaseType = "Datetime" - tomlString tomlBaseType = "String" - tomlBool tomlBaseType = "Bool" - tomlArray tomlBaseType = "Array" - tomlHash tomlBaseType = "Hash" - tomlArrayHash tomlBaseType = "ArrayHash" -) - -// typeOfPrimitive returns a tomlType of any primitive value in TOML. -// Primitive values are: Integer, Float, Datetime, String and Bool. -// -// Passing a lexer item other than the following will cause a BUG message -// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. -func (p *parser) typeOfPrimitive(lexItem item) tomlType { - switch lexItem.typ { - case itemInteger: - return tomlInteger - case itemFloat: - return tomlFloat - case itemDatetime: - return tomlDatetime - case itemString: - return tomlString - case itemMultilineString: - return tomlString - case itemRawString: - return tomlString - case itemRawMultilineString: - return tomlString - case itemBool: - return tomlBool - } - p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) - panic("unreachable") -} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/.gitignore b/vendor/github.com/brianvoe/gofakeit/v7/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/brianvoe/gofakeit/v7/BENCHMARKS.md b/vendor/github.com/brianvoe/gofakeit/v7/BENCHMARKS.md new file mode 100644 index 0000000000..0f6776c58f --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/BENCHMARKS.md @@ -0,0 +1,323 @@ +go test -bench=. -benchmem \ +goos: darwin \ +goarch: amd64 \ +pkg: github.com/brianvoe/gofakeit/v7 \ +cpu: Apple M1 Max \ +Table generated with tablesgenerator.com/markdown_tables File->Paste table data + +| Benchmark | Ops | CPU | MEM | MEM alloc | +|---------------------------------------|----------|----------------|--------------|------------------| +| BenchmarkAddress-10 | 1369538 | 874.7 ns/op | 195 B/op | 5 allocs/op | +| BenchmarkStreet-10 | 3438403 | 347.9 ns/op | 25 B/op | 2 allocs/op | +| BenchmarkStreetNumber-10 | 8601847 | 138.2 ns/op | 4 B/op | 1 allocs/op | +| BenchmarkStreetPrefix-10 | 19814623 | 60.26 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetName-10 | 19633909 | 60.78 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetSuffix-10 | 19717612 | 60.19 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCity-10 | 20219280 | 58.88 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkState-10 | 19526760 | 60.85 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStateAbr-10 | 19634631 | 60.79 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkZip-10 | 7521580 | 157.7 ns/op | 5 B/op | 1 allocs/op | +| BenchmarkCountry-10 | 19451166 | 61.29 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCountryAbr-10 | 19585867 | 60.82 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitude-10 | 72309668 | 16.22 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitude-10 | 72334910 | 16.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitudeInRange-10 | 65830375 | 17.77 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitudeInRange-10 | 66400602 | 17.77 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPetName-10 | 30391768 | 39.19 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimal-10 | 28761544 | 41.22 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimalType-10 | 26955640 | 44.13 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFarmAnimal-10 | 22307872 | 53.39 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCat-10 | 24226416 | 49.13 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDog-10 | 19702195 | 60.53 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBird-10 | 17095884 | 70.22 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAppName-10 | 3805696 | 314.4 ns/op | 25 B/op | 1 allocs/op | +| BenchmarkAppVersion-10 | 10250247 | 116.4 ns/op | 7 B/op | 1 allocs/op | +| BenchmarkAppAuthor-10 | 11592895 | 101.2 ns/op | 8 B/op | 0 allocs/op | +| BenchmarkUsername-10 | 8975020 | 132.9 ns/op | 16 B/op | 2 allocs/op | +| BenchmarkPassword-10 | 322147 | 3647 ns/op | 1656 B/op | 60 allocs/op | +| BenchmarkBeerName-10 | 27986706 | 42.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerStyle-10 | 19460616 | 60.99 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerHop-10 | 26915132 | 44.35 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerYeast-10 | 24840991 | 47.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerMalt-10 | 20806075 | 57.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerIbu-10 | 41349307 | 28.99 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkBeerAlcohol-10 | 6054163 | 197.8 ns/op | 28 B/op | 2 allocs/op | +| BenchmarkBeerBlg-10 | 5825622 | 205.6 ns/op | 37 B/op | 2 allocs/op | +| BenchmarkBook-10 | 6927696 | 171.9 ns/op | 48 B/op | 1 allocs/op | +| BenchmarkBookTitle-10 | 31594431 | 37.36 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBookAuthor-10 | 29969000 | 39.91 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBookGenre-10 | 24269676 | 48.77 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCar-10 | 3795943 | 316.3 ns/op | 96 B/op | 1 allocs/op | +| BenchmarkCarType-10 | 26309082 | 43.81 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarFuelType-10 | 26414821 | 45.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarTransmissionType-10 | 24309171 | 48.83 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarMaker-10 | 23505099 | 51.01 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarModel-10 | 19055469 | 62.82 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityActor-10 | 19915483 | 57.84 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityBusiness-10 | 20186090 | 67.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebritySport-10 | 14223360 | 84.47 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkColor-10 | 21535978 | 54.16 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNiceColors-10 | 71414755 | 16.16 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSafeColor-10 | 24683570 | 46.53 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHexColor-10 | 4815675 | 250.3 ns/op | 24 B/op | 3 allocs/op | +| BenchmarkRGBColor-10 | 19453399 | 61.67 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkCompany-10 | 25604892 | 46.66 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCompanySuffix-10 | 24647574 | 48.83 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBlurb-10 | 20634126 | 58.88 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBuzzWord-10 | 23034157 | 51.84 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBS-10 | 21803314 | 55.08 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJob-10 | 4121804 | 292.0 ns/op | 64 B/op | 1 allocs/op | +| BenchmarkJobTitle-10 | 24344308 | 47.51 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobDescriptor-10 | 24049240 | 50.12 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobLevel-10 | 19349389 | 62.45 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSlogan-10 | 4499653 | 263.1 ns/op | 41 B/op | 1 allocs/op | +| BenchmarkCSVLookup100-10 | 1184 | 1014597 ns/op | 713620 B/op | 9923 allocs/op | +| BenchmarkEmoji-10 | 24200866 | 49.72 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiDescription-10 | 22978600 | 52.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiCategory-10 | 21228057 | 56.57 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiAlias-10 | 17616240 | 68.45 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiTag-10 | 19253190 | 62.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkError-10 | 1637725 | 736.5 ns/op | 288 B/op | 8 allocs/op | +| BenchmarkErrorObject-10 | 6755540 | 177.7 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkErrorDatabase-10 | 5794706 | 200.2 ns/op | 63 B/op | 3 allocs/op | +| BenchmarkErrorGRPC-10 | 6063802 | 196.8 ns/op | 64 B/op | 3 allocs/op | +| BenchmarkErrorHTTP-10 | 3956130 | 302.2 ns/op | 158 B/op | 4 allocs/op | +| BenchmarkErrorHTTPClient-10 | 6025258 | 196.4 ns/op | 52 B/op | 3 allocs/op | +| BenchmarkErrorHTTPServer-10 | 5969395 | 202.1 ns/op | 59 B/op | 3 allocs/op | +| BenchmarkErrorRuntime-10 | 4786108 | 248.3 ns/op | 150 B/op | 3 allocs/op | +| BenchmarkErrorValidation-10 | 1811821 | 667.8 ns/op | 277 B/op | 7 allocs/op | +| BenchmarkFileMimeType-10 | 26273320 | 45.47 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFileExtension-10 | 22216770 | 53.94 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCusip-10 | 6778542 | 176.4 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkIsin-10 | 1844566 | 652.1 ns/op | 525 B/op | 7 allocs/op | +| BenchmarkFruit-10 | 20381516 | 58.81 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVegetable-10 | 19638996 | 61.11 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBreakfast-10 | 9425649 | 127.2 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkLunch-10 | 8996594 | 133.6 ns/op | 34 B/op | 1 allocs/op | +| BenchmarkDinner-10 | 9427389 | 126.6 ns/op | 36 B/op | 1 allocs/op | +| BenchmarkDrink-10 | 8552294 | 140.4 ns/op | 7 B/op | 2 allocs/op | +| BenchmarkSnack-10 | 7678719 | 156.7 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkDessert-10 | 8907098 | 134.0 ns/op | 31 B/op | 2 allocs/op | +| BenchmarkGamertag-10 | 2474312 | 483.9 ns/op | 83 B/op | 5 allocs/op | +| BenchmarkDice-10 | 47727080 | 25.22 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkGenerate/package-10 | 423741 | 2822 ns/op | 1187 B/op | 29 allocs/op | +| BenchmarkGenerate/Complex-10 | 138112 | 8653 ns/op | 4553 B/op | 80 allocs/op | +| BenchmarkFixedWidthLookup100-10 | 2072 | 583512 ns/op | 489975 B/op | 8701 allocs/op | +| BenchmarkRegex-10 | 633699 | 1914 ns/op | 1632 B/op | 27 allocs/op | +| BenchmarkRegexEmail-10 | 205447 | 5893 ns/op | 4084 B/op | 90 allocs/op | +| BenchmarkMap-10 | 337576 | 3596 ns/op | 1111 B/op | 16 allocs/op | +| BenchmarkHackerPhrase-10 | 166683 | 7209 ns/op | 3107 B/op | 50 allocs/op | +| BenchmarkHackerAbbreviation-10 | 25295019 | 47.33 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerAdjective-10 | 24022460 | 49.76 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerNoun-10 | 22496308 | 53.31 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerVerb-10 | 18546052 | 64.53 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackeringVerb-10 | 20298242 | 59.05 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkReplaceWithNumbers-10 | 1402717 | 852.8 ns/op | 296 B/op | 10 allocs/op | +| BenchmarkHipsterWord-10 | 25151432 | 47.83 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHipsterSentence-10 | 1314279 | 907.8 ns/op | 288 B/op | 3 allocs/op | +| BenchmarkHipsterParagraph-10 | 67437 | 17682 ns/op | 10521 B/op | 48 allocs/op | +| BenchmarkInputName-10 | 20759898 | 57.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSvg-10 | 225738 | 5181 ns/op | 8876 B/op | 52 allocs/op | +| BenchmarkImageURL-10 | 15524359 | 77.15 ns/op | 38 B/op | 3 allocs/op | +| BenchmarkImage-10 | 63 | 18773091 ns/op | 2457691 B/op | 307202 allocs/op | +| BenchmarkImageJpeg-10 | 39 | 29498291 ns/op | 2982478 B/op | 307217 allocs/op | +| BenchmarkImagePng-10 | 16 | 68552771 ns/op | 5899010 B/op | 307270 allocs/op | +| BenchmarkDomainName-10 | 3001479 | 402.2 ns/op | 95 B/op | 5 allocs/op | +| BenchmarkDomainSuffix-10 | 21476332 | 56.03 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkURL-10 | 1289262 | 934.6 ns/op | 277 B/op | 10 allocs/op | +| BenchmarkHTTPMethod-10 | 19895946 | 60.56 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkIPv4Address-10 | 6088518 | 196.5 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkIPv6Address-10 | 2580320 | 462.0 ns/op | 111 B/op | 8 allocs/op | +| BenchmarkMacAddress-10 | 3281300 | 364.7 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkHTTPStatusCode-10 | 16597051 | 72.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPStatusCodeSimple-10 | 17250238 | 69.52 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLogLevel-10 | 20608036 | 58.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUserAgent-10 | 1946059 | 615.5 ns/op | 298 B/op | 5 allocs/op | +| BenchmarkChromeUserAgent-10 | 2619324 | 458.2 ns/op | 184 B/op | 5 allocs/op | +| BenchmarkFirefoxUserAgent-10 | 1601706 | 753.8 ns/op | 362 B/op | 6 allocs/op | +| BenchmarkSafariUserAgent-10 | 1569805 | 764.4 ns/op | 551 B/op | 7 allocs/op | +| BenchmarkOperaUserAgent-10 | 2378972 | 504.7 ns/op | 212 B/op | 5 allocs/op | +| BenchmarkJSONLookup100-10 | 928 | 1276230 ns/op | 813725 B/op | 12134 allocs/op | +| BenchmarkLanguage-10 | 23873984 | 50.34 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageAbbreviation-10 | 25025524 | 47.93 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageBCP-10 | 21895112 | 54.74 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguage-10 | 21169636 | 56.70 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLoremIpsumWord-10 | 23980356 | 49.92 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLoremIpsumSentence-10 | 1344384 | 894.8 ns/op | 219 B/op | 2 allocs/op | +| BenchmarkLoremIpsumParagraph-10 | 66643 | 17916 ns/op | 8483 B/op | 40 allocs/op | +| BenchmarkMinecraftOre-10 | 15077451 | 79.85 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWood-10 | 14422303 | 83.44 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorTier-10 | 15262417 | 78.70 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorPart-10 | 15340200 | 78.11 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeapon-10 | 15107792 | 79.78 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftTool-10 | 14428170 | 83.15 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftDye-10 | 14657188 | 81.95 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftFood-10 | 14860236 | 81.01 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftAnimal-10 | 15281302 | 78.35 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerJob-10 | 14586627 | 82.14 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerStation-10 | 14678592 | 81.82 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerLevel-10 | 14314164 | 83.76 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobPassive-10 | 15132750 | 79.32 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobNeutral-10 | 13802880 | 87.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobHostile-10 | 13141233 | 91.06 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobBoss-10 | 15245322 | 78.79 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftBiome-10 | 14943789 | 79.86 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeather-10 | 12681386 | 94.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBool-10 | 73596490 | 16.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUUID-10 | 4128735 | 288.7 ns/op | 48 B/op | 1 allocs/op | +| BenchmarkShuffleAnySlice-10 | 3149857 | 380.0 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkFlipACoin-10 | 74457853 | 16.17 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMovie-10 | 9234234 | 129.3 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkMovieName-10 | 25314163 | 47.82 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMovieGenre-10 | 24570799 | 48.81 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNumber-10 | 74087221 | 16.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUint8-10 | 73790145 | 16.35 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUint16-10 | 74334474 | 16.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUint32-10 | 71804154 | 16.72 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUint64-10 | 71385904 | 16.64 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUintRange-10 | 73982353 | 16.13 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkInt8-10 | 73927286 | 16.14 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkInt16-10 | 74022668 | 16.19 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkInt32-10 | 72009002 | 16.64 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkInt64-10 | 72375081 | 16.59 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkIntRange-10 | 74396306 | 16.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFloat32-10 | 73950822 | 16.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFloat32Range-10 | 73622833 | 16.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFloat64-10 | 73076970 | 16.31 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFloat64Range-10 | 73385329 | 16.33 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkShuffleInts-10 | 9151563 | 131.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkRandomInt-10 | 72188592 | 16.63 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkRandomUint-10 | 72293332 | 16.64 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHexUint-10 | 14888452 | 80.93 ns/op | 16 B/op | 2 allocs/op | +| BenchmarkCurrency-10 | 14366668 | 83.15 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkCurrencyShort-10 | 24445954 | 48.68 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCurrencyLong-10 | 23560556 | 50.65 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPrice-10 | 73693664 | 16.33 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCreditCard-10 | 1000000 | 1153 ns/op | 264 B/op | 15 allocs/op | +| BenchmarkCreditCardType-10 | 32410167 | 36.93 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCreditCardNumber-10 | 1511084 | 799.1 ns/op | 183 B/op | 10 allocs/op | +| BenchmarkCreditCardExp-10 | 11014600 | 108.5 ns/op | 5 B/op | 1 allocs/op | +| BenchmarkCreditCardCvv-10 | 20325733 | 59.31 ns/op | 3 B/op | 1 allocs/op | +| BenchmarkAchRouting-10 | 7338657 | 164.0 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkAchAccount-10 | 5646235 | 212.0 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkBitcoinAddress-10 | 517399 | 2306 ns/op | 715 B/op | 37 allocs/op | +| BenchmarkBitcoinPrivateKey-10 | 1276884 | 943.2 ns/op | 184 B/op | 5 allocs/op | +| BenchmarkName-10 | 7771977 | 152.6 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkFirstName-10 | 23523357 | 50.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMiddleName-10 | 17589612 | 68.17 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLastName-10 | 20825980 | 57.63 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNamePrefix-10 | 25542308 | 46.65 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNameSuffix-10 | 21972974 | 54.56 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSSN-10 | 31829850 | 37.71 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkGender-10 | 73621140 | 16.25 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHobby-10 | 17347129 | 69.06 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPerson-10 | 317911 | 3693 ns/op | 837 B/op | 33 allocs/op | +| BenchmarkContact-10 | 1843221 | 650.8 ns/op | 136 B/op | 6 allocs/op | +| BenchmarkPhone-10 | 6786794 | 176.2 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkPhoneFormatted-10 | 4674930 | 256.2 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkEmail-10 | 2794358 | 431.1 ns/op | 88 B/op | 4 allocs/op | +| BenchmarkTeams-10 | 1576238 | 763.8 ns/op | 672 B/op | 10 allocs/op | +| BenchmarkProduct-10 | 206918 | 5813 ns/op | 1069 B/op | 31 allocs/op | +| BenchmarkProductName-10 | 2313364 | 517.4 ns/op | 103 B/op | 5 allocs/op | +| BenchmarkProductDescription-10 | 348346 | 3434 ns/op | 549 B/op | 8 allocs/op | +| BenchmarkProductCategory-10 | 25139860 | 47.73 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProductFeature-10 | 21264922 | 56.46 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProductMaterial-10 | 18142828 | 66.24 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProductUPC-10 | 1399148 | 859.1 ns/op | 96 B/op | 11 allocs/op | +| BenchmarkSchool-10 | 4161710 | 287.6 ns/op | 34 B/op | 1 allocs/op | +| BenchmarkLetter-10 | 73457020 | 16.29 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLetterN-10 | 5060271 | 238.8 ns/op | 64 B/op | 2 allocs/op | +| BenchmarkVowel-10 | 58685206 | 20.87 ns/op | 4 B/op | 1 allocs/op | +| BenchmarkDigit-10 | 73944177 | 16.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDigitN-10 | 5051070 | 236.6 ns/op | 64 B/op | 2 allocs/op | +| BenchmarkNumerify-10 | 6794545 | 176.4 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkLexify-10 | 11113212 | 108.3 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkShuffleStrings-10 | 9924429 | 121.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkRandomString-10 | 73420688 | 16.34 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkTemplate-10 | 2488 | 477349 ns/op | 280877 B/op | 4611 allocs/op | +| BenchmarkDate-10 | 10292476 | 116.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPastDate-10 | 18285830 | 65.48 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFutureDate-10 | 18399240 | 65.13 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDateRange-10 | 8406979 | 142.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMonth-10 | 74105902 | 16.26 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMonthString-10 | 73647870 | 16.26 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkWeekDay-10 | 73990911 | 16.24 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDay-10 | 73435291 | 16.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkYear-10 | 73950066 | 16.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHour-10 | 74219916 | 16.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinute-10 | 74349634 | 16.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSecond-10 | 73787313 | 16.29 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNanoSecond-10 | 74299380 | 16.15 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkTimeZone-10 | 19105237 | 62.83 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkTimeZoneFull-10 | 16170054 | 74.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkTimeZoneAbv-10 | 20725029 | 58.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkTimeZoneOffset-10 | 14597666 | 81.13 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkTimeZoneRegion-10 | 15733551 | 76.25 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkWeighted-10 | 28507484 | 40.42 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkAdjective-10 | 6726474 | 178.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectiveDescriptive-10 | 16486224 | 73.39 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectiveQuantitative-10 | 15290762 | 78.51 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectiveProper-10 | 16535046 | 72.42 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectiveDemonstrative-10 | 16448917 | 73.41 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectivePossessive-10 | 15715839 | 73.22 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectiveInterrogative-10 | 15543478 | 77.43 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdjectiveIndefinite-10 | 16306894 | 73.50 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverb-10 | 7139924 | 168.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbManner-10 | 17139112 | 70.37 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbDegree-10 | 16213138 | 73.70 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbPlace-10 | 17268267 | 69.67 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbTimeDefinite-10 | 16273309 | 73.70 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbTimeIndefinite-10 | 15822297 | 74.26 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbFrequencyDefinite-10 | 16344181 | 73.30 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAdverbFrequencyIndefinite-10 | 16118569 | 74.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkComment-10 | 1000000 | 1146 ns/op | 258 B/op | 6 allocs/op | +| BenchmarkConnective-10 | 7132710 | 168.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkConnectiveTime-10 | 15339457 | 78.08 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkConnectiveComparative-10 | 16188842 | 74.04 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkConnectiveComplaint-10 | 14127903 | 85.00 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkConnectiveListing-10 | 16073437 | 74.65 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkConnectiveCasual-10 | 13771904 | 87.06 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkConnectiveExamplify-10 | 15763296 | 76.03 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkWord-10 | 8047610 | 148.5 ns/op | 3 B/op | 0 allocs/op | +| BenchmarkSentenceSimple-10 | 682924 | 1707 ns/op | 590 B/op | 11 allocs/op | +| BenchmarkInterjection-10 | 16295702 | 73.50 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNoun-10 | 6711976 | 179.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounCommon-10 | 17117466 | 69.83 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounConcrete-10 | 17144979 | 69.81 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounAbstract-10 | 16839790 | 71.16 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounCollectivePeople-10 | 16360652 | 73.24 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounCollectiveAnimal-10 | 16453287 | 72.79 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounCollectiveThing-10 | 16397232 | 72.97 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounCountable-10 | 17171895 | 69.78 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounUncountable-10 | 17193412 | 69.75 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNounProper-10 | 10644372 | 112.0 ns/op | 7 B/op | 0 allocs/op | +| BenchmarkNounDeterminer-10 | 17003730 | 70.44 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPhrase-10 | 23481584 | 51.12 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPhraseNoun-10 | 2961691 | 405.1 ns/op | 104 B/op | 2 allocs/op | +| BenchmarkPhraseVerb-10 | 1422132 | 845.1 ns/op | 232 B/op | 6 allocs/op | +| BenchmarkPhraseAdverb-10 | 7617193 | 153.3 ns/op | 9 B/op | 0 allocs/op | +| BenchmarkPhrasePreposition-10 | 2336155 | 513.3 ns/op | 123 B/op | 3 allocs/op | +| BenchmarkPreposition-10 | 9244665 | 129.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPrepositionSimple-10 | 16397623 | 73.11 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPrepositionDouble-10 | 16107751 | 74.19 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPrepositionCompound-10 | 16364900 | 73.10 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronoun-10 | 6436707 | 186.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounPersonal-10 | 16997427 | 70.53 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounObject-10 | 15303380 | 78.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounPossessive-10 | 15323908 | 78.10 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounReflective-10 | 15258552 | 78.45 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounIndefinite-10 | 16053780 | 74.69 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounDemonstrative-10 | 16476726 | 72.73 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounInterrogative-10 | 15526576 | 77.15 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPronounRelative-10 | 14159284 | 84.64 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSentence-10 | 721934 | 1642 ns/op | 219 B/op | 3 allocs/op | +| BenchmarkParagraph-10 | 39356 | 30481 ns/op | 6687 B/op | 53 allocs/op | +| BenchmarkQuestion-10 | 1757269 | 683.1 ns/op | 243 B/op | 3 allocs/op | +| BenchmarkQuote-10 | 1522988 | 787.2 ns/op | 261 B/op | 3 allocs/op | +| BenchmarkVerb-10 | 8924802 | 127.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVerbAction-10 | 17150564 | 69.83 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVerbTransitive-10 | 17328488 | 69.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVerbIntransitive-10 | 16427985 | 72.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVerbLinking-10 | 17754280 | 67.52 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVerbHelping-10 | 17118238 | 70.31 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkXMLLookup100-10 | 937 | 1279022 ns/op | 862536 B/op | 11370 allocs/op | \ No newline at end of file diff --git a/vendor/github.com/brianvoe/gofakeit/v7/CODE_OF_CONDUCT.md b/vendor/github.com/brianvoe/gofakeit/v7/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..99d12c90fe --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at brian@webiswhatido.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/brianvoe/gofakeit/v7/CONTRIBUTING.md b/vendor/github.com/brianvoe/gofakeit/v7/CONTRIBUTING.md new file mode 100644 index 0000000000..5a4812c28e --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/CONTRIBUTING.md @@ -0,0 +1 @@ +# Make a pull request and submit it and ill take a look at it. Thanks! diff --git a/vendor/github.com/brianvoe/gofakeit/v7/LICENSE.txt b/vendor/github.com/brianvoe/gofakeit/v7/LICENSE.txt new file mode 100644 index 0000000000..21984c9d5e --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/brianvoe/gofakeit/v7/README.md b/vendor/github.com/brianvoe/gofakeit/v7/README.md new file mode 100644 index 0000000000..e6dc520b88 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/README.md @@ -0,0 +1,876 @@ +![Gofakeit](https://raw.githubusercontent.com/brianvoe/gofakeit/master/logo.png) + +# Gofakeit [![Go Report Card](https://goreportcard.com/badge/github.com/brianvoe/gofakeit)](https://goreportcard.com/report/github.com/brianvoe/gofakeit) ![Test](https://github.com/brianvoe/gofakeit/workflows/Test/badge.svg?branch=master) [![GoDoc](https://godoc.org/github.com/brianvoe/gofakeit/v7?status.svg)](https://godoc.org/github.com/brianvoe/gofakeit/v7) [![license](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/brianvoe/gofakeit/master/LICENSE.txt) + +Random data generator written in go + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G0R5EJT) + +Buy Me A Coffee + +## Features + +- [310+ Functions!!!](#functions) +- [Random Sources](#random-sources) +- [Global Rand](#global-rand-set) +- [Struct Generator](#struct) +- [Custom Functions](#custom-functions) +- [Templates](#templates) +- [Http Server](https://github.com/brianvoe/gofakeit/tree/master/cmd/gofakeitserver) +- [Command Line Tool](https://github.com/brianvoe/gofakeit/tree/master/cmd/gofakeit) +- Zero dependencies +- [Benchmarks](https://github.com/brianvoe/gofakeit/blob/master/BENCHMARKS.md) +- [Issue](https://github.com/brianvoe/gofakeit/issues) + +## Contributors + +Thank you to all our Gofakeit contributors! + + + + + +## Installation + +```go +go get github.com/brianvoe/gofakeit/v7 +``` + +## Simple Usage + +```go +import "github.com/brianvoe/gofakeit/v7" + +gofakeit.Name() // Markus Moen +gofakeit.Email() // alaynawuckert@kozey.biz +gofakeit.Phone() // (570)245-7485 +gofakeit.BS() // front-end +gofakeit.BeerName() // Duvel +gofakeit.Color() // MediumOrchid +gofakeit.Company() // Moen, Pagac and Wuckert +gofakeit.CreditCardNumber() // 4287271570245748 +gofakeit.HackerPhrase() // Connecting the array won't do anything, we need to generate the haptic COM driver! +gofakeit.JobTitle() // Director +gofakeit.CurrencyShort() // USD +``` + +[See full list of functions](#functions) + +## Seed + +If you are using the default global usage and dont care about seeding no need to set anything. +Gofakeit will seed it with a cryptographically secure number. + +If you need a reproducible outcome you can set it via the Seed function call. Every example in +this repo sets it for testing purposes. + +```go +import "github.com/brianvoe/gofakeit/v7" + +gofakeit.Seed(0) // If 0 will use crypto/rand to generate a number + +// or + +gofakeit.Seed(8675309) // Set it to whatever number you want +``` + +## Random Sources + +Gofakeit has a few rand sources, by default it uses math/rand/v2 PCG which is a pseudo random number generator and is thread locked. + +If you want to see other potential sources you can see the sub package [Source](https://github.com/brianvoe/gofakeit/tree/master/source) for more information. + +```go +import ( + "github.com/brianvoe/gofakeit/v7" + "github.com/brianvoe/gofakeit/v7/source" + "math/rand/v2" +) + +// Uses math/rand/v2(PCG Pseudo) with mutex locking +faker := gofakeit.New(0) + +// NewFaker takes in a source and whether or not it should be thread safe +faker := gofakeit.NewFaker(source rand.Source, threadSafe bool) + +// PCG Pseudo +faker := gofakeit.NewFaker(rand.NewPCG(11, 11), true) + +// ChaCha8 +faker := gofakeit.NewFaker(rand.NewChaCha8([32]byte{0, 1, 2, 3, 4, 5}), true) + + +// Additional from Gofakeit sub package source + +// JSF(Jenkins Small Fast) +faker := gofakeit.NewFaker(source.NewJSF(11), true) + +// SFC(Simple Fast Counter) +faker := gofakeit.NewFaker(source.NewSFC(11), true) + +// Crypto - Uses crypto/rand +faker := gofakeit.NewFaker(source.NewCrypto(), true) + +// Dumb - simple incrementing number +faker := gofakeit.NewFaker(source.NewDumb(11), true) +``` + +## Global Rand Set + +If you would like to use the simple function calls but need to use something like +crypto/rand you can override the default global with the random source that you want. + +```go +import "github.com/brianvoe/gofakeit/v7" + +gofakeit.GlobalFaker = gofakeit.New(0) +``` + +## Struct + +Gofakeit can generate random data for struct fields. For the most part it covers all the basic type +as well as some non-basic like time.Time. + +Struct fields can also use tags to more specifically generate data for that field type. + +```go +import "github.com/brianvoe/gofakeit/v7" + +// Create structs with random injected data +type Foo struct { + Str string + Int int + Pointer *int + Name string `fake:"{firstname}"` // Any available function all lowercase + Sentence string `fake:"{sentence:3}"` // Can call with parameters + RandStr string `fake:"{randomstring:[hello,world]}"` + Number string `fake:"{number:1,10}"` // Comma separated for multiple values + Regex string `fake:"{regex:[abcdef]{5}}"` // Generate string from regex + Map map[string]int `fakesize:"2"` + Array []string `fakesize:"2"` + ArrayRange []string `fakesize:"2,6"` + Bar Bar + Skip *string `fake:"skip"` // Set to "skip" to not generate data for + SkipAlt *string `fake:"-"` // Set to "-" to not generate data for + Created time.Time // Can take in a fake tag as well as a format tag + CreatedFormat time.Time `fake:"{year}-{month}-{day}" format:"2006-01-02"` +} + +type Bar struct { + Name string + Number int + Float float32 +} + +// Pass your struct as a pointer +var f Foo +err := gofakeit.Struct(&f) + +fmt.Println(f.Str) // hrukpttuezptneuvunh +fmt.Println(f.Int) // -7825289004089916589 +fmt.Println(*f.Pointer) // -343806609094473732 +fmt.Println(f.Name) // fred +fmt.Println(f.Sentence) // Record river mind. +fmt.Println(fStr) // world +fmt.Println(f.Number) // 4 +fmt.Println(f.Regex) // cbdfc +fmt.Println(f.Map) // map[PxLIo:52 lxwnqhqc:846] +fmt.Println(f.Array) // cbdfc +fmt.Printf("%+v", f.Bar) // {Name:QFpZ Number:-2882647639396178786 Float:1.7636692e+37} +fmt.Println(f.Skip) // +fmt.Println(f.Created.String()) // 1908-12-07 04:14:25.685339029 +0000 UTC + +// Supported formats +// int, int8, int16, int32, int64, +// uint, uint8, uint16, uint32, uint64, +// float32, float64, +// bool, string, +// array, pointers, map +// time.Time // If setting time you can also set a format tag +// Nested Struct Fields and Embedded Fields +``` + +## Fakeable types + +It is possible to extend a struct by implementing the `Fakeable` interface +in order to control the generation. + +For example, this is useful when it is not possible to modify the struct that you want to fake by adding struct tags to a field but you still need to be able to control the generation process. + +```go +// Custom string that you want to generate your own data for +type Friend string + +func (c *Friend) Fake(f *gofakeit.Faker) (any, error) { + // Can call any other faker methods + return f.RandomString([]string{"billy", "fred", "susan"}), nil +} + +// Custom time that you want to generate your own data for +type Age time.Time + +func (c *Age) Fake(f *gofakeit.Faker) (any, error) { + return f.DateRange(time.Now().AddDate(-100, 0, 0), time.Now().AddDate(-18, 0, 0)), nil +} + +// This is the struct that we cannot modify to add struct tags +type User struct { + Name Friend + Age *Age +} + +var u User +gofakeit.Struct(&u) +fmt.Printf("%s", f.Name) // billy +fmt.Printf("%s", f.Age) // 1990-12-07 04:14:25.685339029 +0000 UTC +``` + +## Custom Functions + +In a lot of situations you may need to use your own random function usage for your specific needs. + +If you would like to extend the usage of struct tags, generate function, available usages in the gofakeit server +or gofakeit command sub packages. You can do so via the AddFuncLookup. Each function has their own lookup, if +you need more reference examples you can look at each files lookups. + +```go +// Simple +gofakeit.AddFuncLookup("friendname", gofakeit.Info{ + Category: "custom", + Description: "Random friend name", + Example: "bill", + Output: "string", + Generate: func(f *Faker, m *gofakeit.MapParams, info *gofakeit.Info) (any, error) { + return f.RandomString([]string{"bill", "bob", "sally"}), nil + }, +}) + +// With Params +gofakeit.AddFuncLookup("jumbleword", gofakeit.Info{ + Category: "jumbleword", + Description: "Take a word and jumble it up", + Example: "loredlowlh", + Output: "string", + Params: []gofakeit.Param{ + {Field: "word", Type: "string", Description: "Word you want to jumble"}, + }, + Generate: func(f *Faker, m *gofakeit.MapParams, info *gofakeit.Info) (any, error) { + word, err := info.GetString(m, "word") + if err != nil { + return nil, err + } + + split := strings.Split(word, "") + f.ShuffleStrings(split) + return strings.Join(split, ""), nil + }, +}) + +type Foo struct { + FriendName string `fake:"{friendname}"` + JumbleWord string `fake:"{jumbleword:helloworld}"` +} + +var f Foo +gofakeit.Struct(&f) +fmt.Printf("%s", f.FriendName) // bill +fmt.Printf("%s", f.JumbleWord) // loredlowlh +``` + +## Templates + +Generate custom outputs using golang's template engine [https://pkg.go.dev/text/template](https://pkg.go.dev/text/template). + +We have added all the available functions to the template engine as well as some additional ones that are useful for template building. + +Additional Available Functions +```go +- ToUpper(s string) string // Make string upper case +- ToLower(s string) string // Make string lower case +- ToString(s any) // Convert to string +- ToDate(s string) time.Time // Convert string to date +- SpliceAny(args ...any) []any // Build a slice of anys, used with Weighted +- SpliceString(args ...string) []string // Build a slice of strings, used with Teams and RandomString +- SpliceUInt(args ...uint) []uint // Build a slice of uint, used with Dice and RandomUint +- SpliceInt(args ...int) []int // Build a slice of int, used with RandomInt +``` + +
+ Unavailable Gofakeit functions + +```go +// Any functions that dont have a return value +- AnythingThatReturnsVoid(): void + +// Not available to use in templates +- Template(co *TemplateOptions) ([]byte, error) +- RandomMapKey(mapI any) any +``` +
+ + +### Example Usages + +```go +import "github.com/brianvoe/gofakeit/v7" + +func main() { + // Accessing the Lines variable from within the template. + template := ` + Subject: {{RandomString (SliceString "Greetings" "Hello" "Hi")}} + + Dear {{LastName}}, + + {{RandomString (SliceString "Greetings!" "Hello there!" "Hi, how are you?")}} + + {{Paragraph 1 5 10 "\n\n"}} + + {{RandomString (SliceString "Warm regards" "Best wishes" "Sincerely")}} + {{$person:=Person}} + {{$person.FirstName}} {{$person.LastName}} + {{$person.Email}} + {{$person.Phone}} + ` + + value, err := gofakeit.Template(template, &TemplateOptions{Data: 5}) + + if err != nil { + fmt.Println(err) + } + + fmt.Println(string(value)) +} +``` + +Output: +```text +Subject: Hello + +Dear Krajcik, + +Greetings! + +Quia voluptatem voluptatem voluptatem. Quia voluptatem voluptatem voluptatem. Quia voluptatem voluptatem voluptatem. + +Warm regards +Kaitlyn Krajcik +kaitlynkrajcik@krajcik +570-245-7485 +``` + +## Functions + +All functions also exist as methods on the Faker struct + +### File + +Passing `nil` to `CSV`, `JSON` or `XML` will auto generate data using default values. + +```go +CSV(co *CSVOptions) ([]byte, error) +JSON(jo *JSONOptions) ([]byte, error) +XML(xo *XMLOptions) ([]byte, error) +FileExtension() string +FileMimeType() string +``` + +### Template + +Passing `nil` will auto generate data using default values. + +```go +Template(co *TemplateOptions) (string, error) +Markdown(co *MarkdownOptions) (string, error) +EmailText(co *EmailOptions) (string, error) +FixedWidth(co *FixedWidthOptions) (string, error) +``` + +### Product + +```go +Product() *ProductInfo +ProductName() string +ProductDescription() string +ProductCategory() string +ProductFeature() string +ProductMaterial() string +ProductUPC() string +ProductAudience() string +ProductDimension() string +ProductUseCase() string +ProductBenefit() string +ProductSuffix() string + +``` + +### Person + +```go +Person() *PersonInfo +Name() string +NamePrefix() string +NameSuffix() string +FirstName() string +MiddleName() string +LastName() string +Gender() string +SSN() string +Hobby() string +Contact() *ContactInfo +Email() string +Phone() string +PhoneFormatted() string +Teams(peopleArray []string, teamsArray []string) map[string][]string +``` + +### Generate + +```go +Struct(v any) +Slice(v any) +Map() map[string]any +Generate(value string) string +Regex(value string) string +``` + +### Auth + +```go +Username() string +Password(lower bool, upper bool, numeric bool, special bool, space bool, num int) string +``` + +### Address + +```go +Address() *AddressInfo +City() string +Country() string +CountryAbr() string +State() string +StateAbr() string +Street() string +StreetName() string +StreetNumber() string +StreetPrefix() string +StreetSuffix() string +Zip() string +Latitude() float64 +LatitudeInRange(min, max float64) (float64, error) +Longitude() float64 +LongitudeInRange(min, max float64) (float64, error) +``` + +### Game + +```go +Gamertag() string +Dice(numDice uint, sides []uint) []uint +``` + +### Beer + +```go +BeerAlcohol() string +BeerBlg() string +BeerHop() string +BeerIbu() string +BeerMalt() string +BeerName() string +BeerStyle() string +BeerYeast() string +``` + +### Car + +```go +Car() *CarInfo +CarMaker() string +CarModel() string +CarType() string +CarFuelType() string +CarTransmissionType() string +``` + +### Words + +```go +// Nouns +Noun() string +NounCommon() string +NounConcrete() string +NounAbstract() string +NounCollectivePeople() string +NounCollectiveAnimal() string +NounCollectiveThing() string +NounCountable() string +NounUncountable() string + +// Verbs +Verb() string +VerbAction() string +VerbLinking() string +VerbHelping() string + +// Adverbs +Adverb() string +AdverbManner() string +AdverbDegree() string +AdverbPlace() string +AdverbTimeDefinite() string +AdverbTimeIndefinite() string +AdverbFrequencyDefinite() string +AdverbFrequencyIndefinite() string + +// Propositions +Preposition() string +PrepositionSimple() string +PrepositionDouble() string +PrepositionCompound() string + +// Adjectives +Adjective() string +AdjectiveDescriptive() string +AdjectiveQuantitative() string +AdjectiveProper() string +AdjectiveDemonstrative() string +AdjectivePossessive() string +AdjectiveInterrogative() string +AdjectiveIndefinite() string + +// Pronouns +Pronoun() string +PronounPersonal() string +PronounObject() string +PronounPossessive() string +PronounReflective() string +PronounDemonstrative() string +PronounInterrogative() string +PronounRelative() string + +// Connectives +Connective() string +ConnectiveTime() string +ConnectiveComparative() string +ConnectiveComplaint() string +ConnectiveListing() string +ConnectiveCasual() string +ConnectiveExamplify() string + +// Words +Word() string + +// Sentences +Sentence(wordCount int) string +Paragraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string +LoremIpsumWord() string +LoremIpsumSentence(wordCount int) string +LoremIpsumParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string +Question() string +Quote() string +Phrase() string +``` + +### Foods + +```go +Fruit() string +Vegetable() string +Breakfast() string +Lunch() string +Dinner() string +Snack() string +Dessert() string +``` + +### Misc + +```go +Bool() bool +UUID() string +Weighted(options []any, weights []float32) (any, error) +FlipACoin() string +RandomMapKey(mapI any) any +ShuffleAnySlice(v any) +``` + +### Colors + +```go +Color() string +HexColor() string +RGBColor() []int +SafeColor() string +NiceColors() string +``` + +### Images + +```go +Image(width int, height int) *img.RGBA +ImageJpeg(width int, height int) []byte +ImagePng(width int, height int) []byte +``` + +### Internet + +```go +URL() string +DomainName() string +DomainSuffix() string +IPv4Address() string +IPv6Address() string +MacAddress() string +HTTPStatusCode() string +HTTPStatusCodeSimple() int +LogLevel(logType string) string +HTTPMethod() string +HTTPVersion() string +UserAgent() string +ChromeUserAgent() string +FirefoxUserAgent() string +OperaUserAgent() string +SafariUserAgent() string +``` + +### HTML + +```go +InputName() string +Svg(options *SVGOptions) string +``` + +### Date/Time + +```go +Date() time.Time +PastDate() time.Time +FutureDate() time.Time +DateRange(start, end time.Time) time.Time +NanoSecond() int +Second() int +Minute() int +Hour() int +Month() int +MonthString() string +Day() int +WeekDay() string +Year() int +TimeZone() string +TimeZoneAbv() string +TimeZoneFull() string +TimeZoneOffset() float32 +TimeZoneRegion() string +``` + +### Payment + +```go +Price(min, max float64) float64 +CreditCard() *CreditCardInfo +CreditCardCvv() string +CreditCardExp() string +CreditCardNumber(*CreditCardOptions) string +CreditCardType() string +Currency() *CurrencyInfo +CurrencyLong() string +CurrencyShort() string +AchRouting() string +AchAccount() string +BitcoinAddress() string +BitcoinPrivateKey() string +``` + +### Finance + +```go +Cusip() string +Isin() string +``` + +### Company + +```go +BS() string +Blurb() string +BuzzWord() string +Company() string +CompanySuffix() string +Job() *JobInfo +JobDescriptor() string +JobLevel() string +JobTitle() string +Slogan() string +``` + +### Hacker + +```go +HackerAbbreviation() string +HackerAdjective() string +Hackeringverb() string +HackerNoun() string +HackerPhrase() string +HackerVerb() string +``` + +### Hipster + +```go +HipsterWord() string +HipsterSentence(wordCount int) string +HipsterParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string +``` + +### App + +```go +AppName() string +AppVersion() string +AppAuthor() string +``` + +### Animal + +```go +PetName() string +Animal() string +AnimalType() string +FarmAnimal() string +Cat() string +Dog() string +Bird() string +``` + +### Emoji + +```go +Emoji() string +EmojiDescription() string +EmojiCategory() string +EmojiAlias() string +EmojiTag() string +``` + +### Language + +```go +Language() string +LanguageAbbreviation() string +ProgrammingLanguage() string +ProgrammingLanguageBest() string +``` + +### Number + +```go +Number(min int, max int) int +Int() int +IntN(n int) int +Int8() int8 +Int16() int16 +Int32() int32 +Int64() int64 +Uint() uint +UintN(n uint) uint +Uint8() uint8 +Uint16() uint16 +Uint32() uint32 +Uint64() uint64 +Float32() float32 +Float32Range(min, max float32) float32 +Float64() float64 +Float64Range(min, max float64) float64 +ShuffleInts(a []int) +RandomInt(i []int) int +HexUint(bitsize int) string +``` + +### String + +```go +Digit() string +DigitN(n uint) string +Letter() string +LetterN(n uint) string +Lexify(str string) string +Numerify(str string) string +ShuffleStrings(a []string) +RandomString(a []string) string +``` + +### Celebrity + +```go +CelebrityActor() string +CelebrityBusiness() string +CelebritySport() string +``` + +### Minecraft + +```go +MinecraftOre() string +MinecraftWood() string +MinecraftArmorTier() string +MinecraftArmorPart() string +MinecraftWeapon() string +MinecraftTool() string +MinecraftDye() string +MinecraftFood() string +MinecraftAnimal() string +MinecraftVillagerJob() string +MinecraftVillagerStation() string +MinecraftVillagerLevel() string +MinecraftMobPassive() string +MinecraftMobNeutral() string +MinecraftMobHostile() string +MinecraftMobBoss() string +MinecraftBiome() string +MinecraftWeather() string +``` + +### Book + +```go +Book() *BookInfo +BookTitle() string +BookAuthor() string +BookGenre() string +``` + +### Movie + +```go +Movie() *MovieInfo +MovieName() string +MovieGenre() string +``` + +### Error + +```go +Error() error +ErrorDatabase() error +ErrorGRPC() error +ErrorHTTP() error +ErrorHTTPClient() error +ErrorHTTPServer() error +ErrorInput() error +ErrorRuntime() error +``` + +### School + +```go +School() string +``` + +### Song + +```go +Song() *SongInfo +SongName() string +SongArtist() string +SongGenre() string +``` diff --git a/vendor/github.com/brianvoe/gofakeit/v7/address.go b/vendor/github.com/brianvoe/gofakeit/v7/address.go new file mode 100644 index 0000000000..f8e4e7b887 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/address.go @@ -0,0 +1,420 @@ +package gofakeit + +import ( + "errors" + "strings" +) + +// AddressInfo is a struct full of address information +type AddressInfo struct { + Address string `json:"address" xml:"address"` + Street string `json:"street" xml:"street"` + City string `json:"city" xml:"city"` + State string `json:"state" xml:"state"` + Zip string `json:"zip" xml:"zip"` + Country string `json:"country" xml:"country"` + Latitude float64 `json:"latitude" xml:"latitude"` + Longitude float64 `json:"longitude" xml:"longitude"` +} + +// Address will generate a struct of address information +func Address() *AddressInfo { return address(GlobalFaker) } + +// Address will generate a struct of address information +func (f *Faker) Address() *AddressInfo { return address(f) } + +func address(f *Faker) *AddressInfo { + street := street(f) + city := city(f) + state := state(f) + zip := zip(f) + + return &AddressInfo{ + Address: street + ", " + city + ", " + state + " " + zip, + Street: street, + City: city, + State: state, + Zip: zip, + Country: country(f), + Latitude: latitude(f), + Longitude: longitude(f), + } +} + +// Street will generate a random address street string +func Street() string { return street(GlobalFaker) } + +// Street will generate a random address street string +func (f *Faker) Street() string { return street(f) } + +func street(f *Faker) string { + var street = "" + switch randInt := randIntRange(f, 1, 2); randInt { + case 1: + street = streetNumber(f) + " " + streetPrefix(f) + " " + streetName(f) + streetSuffix(f) + case 2: + street = streetNumber(f) + " " + streetName(f) + streetSuffix(f) + } + + return street +} + +// StreetNumber will generate a random address street number string +func StreetNumber() string { return streetNumber(GlobalFaker) } + +// StreetNumber will generate a random address street number string +func (f *Faker) StreetNumber() string { return streetNumber(f) } + +func streetNumber(f *Faker) string { + return strings.TrimLeft(replaceWithNumbers(f, getRandValue(f, []string{"address", "number"})), "0") +} + +// StreetPrefix will generate a random address street prefix string +func StreetPrefix() string { return streetPrefix(GlobalFaker) } + +// StreetPrefix will generate a random address street prefix string +func (f *Faker) StreetPrefix() string { return streetPrefix(f) } + +func streetPrefix(f *Faker) string { return getRandValue(f, []string{"address", "street_prefix"}) } + +// StreetName will generate a random address street name string +func StreetName() string { return streetName(GlobalFaker) } + +// StreetName will generate a random address street name string +func (f *Faker) StreetName() string { return streetName(f) } + +func streetName(f *Faker) string { return getRandValue(f, []string{"address", "street_name"}) } + +// StreetSuffix will generate a random address street suffix string +func StreetSuffix() string { return streetSuffix(GlobalFaker) } + +// StreetSuffix will generate a random address street suffix string +func (f *Faker) StreetSuffix() string { return streetSuffix(f) } + +func streetSuffix(f *Faker) string { return getRandValue(f, []string{"address", "street_suffix"}) } + +// City will generate a random city string +func City() string { return city(GlobalFaker) } + +// City will generate a random city string +func (f *Faker) City() string { return city(f) } + +func city(f *Faker) string { return getRandValue(f, []string{"address", "city"}) } + +// State will generate a random state string +func State() string { return state(GlobalFaker) } + +// State will generate a random state string +func (f *Faker) State() string { return state(f) } + +func state(f *Faker) string { return getRandValue(f, []string{"address", "state"}) } + +// StateAbr will generate a random abbreviated state string +func StateAbr() string { return stateAbr(GlobalFaker) } + +// StateAbr will generate a random abbreviated state string +func (f *Faker) StateAbr() string { return stateAbr(f) } + +func stateAbr(f *Faker) string { return getRandValue(f, []string{"address", "state_abr"}) } + +// Zip will generate a random Zip code string +func Zip() string { return zip(GlobalFaker) } + +// Zip will generate a random Zip code string +func (f *Faker) Zip() string { return zip(f) } + +func zip(f *Faker) string { + return replaceWithNumbers(f, getRandValue(f, []string{"address", "zip"})) +} + +// Country will generate a random country string +func Country() string { return country(GlobalFaker) } + +// Country will generate a random country string +func (f *Faker) Country() string { return country(f) } + +func country(f *Faker) string { return getRandValue(f, []string{"address", "country"}) } + +// CountryAbr will generate a random abbreviated country string +func CountryAbr() string { return countryAbr(GlobalFaker) } + +// CountryAbr will generate a random abbreviated country string +func (f *Faker) CountryAbr() string { return countryAbr(f) } + +func countryAbr(f *Faker) string { return getRandValue(f, []string{"address", "country_abr"}) } + +// Latitude will generate a random latitude float64 +func Latitude() float64 { return latitude(GlobalFaker) } + +// Latitude will generate a random latitude float64 +func (f *Faker) Latitude() float64 { return latitude(f) } + +func latitude(f *Faker) float64 { return toFixed((f.Float64()*180)-90, 6) } + +// LatitudeInRange will generate a random latitude within the input range +func LatitudeInRange(min, max float64) (float64, error) { + return latitudeInRange(GlobalFaker, min, max) +} + +// LatitudeInRange will generate a random latitude within the input range +func (f *Faker) LatitudeInRange(min, max float64) (float64, error) { + return latitudeInRange(f, min, max) +} + +func latitudeInRange(f *Faker, min, max float64) (float64, error) { + if min > max || min < -90 || min > 90 || max < -90 || max > 90 { + return 0, errors.New("invalid min or max range, must be valid floats and between -90 and 90") + } + return toFixed(float64Range(f, min, max), 6), nil +} + +// Longitude will generate a random longitude float64 +func Longitude() float64 { return longitude(GlobalFaker) } + +// Longitude will generate a random longitude float64 +func (f *Faker) Longitude() float64 { return longitude(f) } + +func longitude(f *Faker) float64 { return toFixed((f.Float64()*360)-180, 6) } + +// LongitudeInRange will generate a random longitude within the input range +func LongitudeInRange(min, max float64) (float64, error) { + return longitudeInRange(GlobalFaker, min, max) +} + +// LongitudeInRange will generate a random longitude within the input range +func (f *Faker) LongitudeInRange(min, max float64) (float64, error) { + return longitudeInRange(f, min, max) +} + +func longitudeInRange(f *Faker, min, max float64) (float64, error) { + if min > max || min < -180 || min > 180 || max < -180 || max > 180 { + return 0, errors.New("invalid min or max range, must be valid floats and between -180 and 180") + } + return toFixed(float64Range(f, min, max), 6), nil +} + +func addAddressLookup() { + AddFuncLookup("address", Info{ + Display: "Address", + Category: "address", + Description: "Residential location including street, city, state, country and postal code", + Example: `{ + "address": "364 Unionsville, Norfolk, Ohio 99536", + "street": "364 Unionsville", + "city": "Norfolk", + "state": "Ohio", + "zip": "99536", + "country": "Lesotho", + "latitude": 88.792592, + "longitude": 174.504681 +}`, + Output: "map[string]any", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return address(f), nil + }, + }) + + AddFuncLookup("city", Info{ + Display: "City", + Category: "address", + Description: "Part of a country with significant population, often a central hub for culture and commerce", + Example: "Marcelside", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return city(f), nil + }, + }) + + AddFuncLookup("country", Info{ + Display: "Country", + Category: "address", + Description: "Nation with its own government and defined territory", + Example: "United States of America", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return country(f), nil + }, + }) + + AddFuncLookup("countryabr", Info{ + Display: "Country Abbreviation", + Category: "address", + Description: "Shortened 2-letter form of a country's name", + Example: "US", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return countryAbr(f), nil + }, + }) + + AddFuncLookup("state", Info{ + Display: "State", + Category: "address", + Description: "Governmental division within a country, often having its own laws and government", + Example: "Illinois", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return state(f), nil + }, + }) + + AddFuncLookup("stateabr", Info{ + Display: "State Abbreviation", + Category: "address", + Description: "Shortened 2-letter form of a country's state", + Example: "IL", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return stateAbr(f), nil + }, + }) + + AddFuncLookup("street", Info{ + Display: "Street", + Category: "address", + Description: "Public road in a city or town, typically with houses and buildings on each side", + Example: "364 East Rapidsborough", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return street(f), nil + }, + }) + + AddFuncLookup("streetname", Info{ + Display: "Street Name", + Category: "address", + Description: "Name given to a specific road or street", + Example: "View", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return streetName(f), nil + }, + }) + + AddFuncLookup("streetnumber", Info{ + Display: "Street Number", + Category: "address", + Description: "Numerical identifier assigned to a street", + Example: "13645", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return streetNumber(f), nil + }, + }) + + AddFuncLookup("streetprefix", Info{ + Display: "Street Prefix", + Category: "address", + Description: "Directional or descriptive term preceding a street name, like 'East' or 'Main'", + Example: "Lake", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return streetPrefix(f), nil + }, + }) + + AddFuncLookup("streetsuffix", Info{ + Display: "Street Suffix", + Category: "address", + Description: "Designation at the end of a street name indicating type, like 'Avenue' or 'Street'", + Example: "land", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return streetSuffix(f), nil + }, + }) + + AddFuncLookup("zip", Info{ + Display: "Zip", + Category: "address", + Description: "Numerical code for postal address sorting, specific to a geographic area", + Example: "13645", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return zip(f), nil + }, + }) + + AddFuncLookup("latitude", Info{ + Display: "Latitude", + Category: "address", + Description: "Geographic coordinate specifying north-south position on Earth's surface", + Example: "-73.534056", + Output: "float", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return latitude(f), nil + }, + }) + + AddFuncLookup("latituderange", Info{ + Display: "Latitude Range", + Category: "address", + Description: "Latitude number between the given range (default min=0, max=90)", + Example: "22.921026", + Output: "float", + Params: []Param{ + {Field: "min", Display: "Min", Type: "float", Default: "0", Description: "Minimum range"}, + {Field: "max", Display: "Max", Type: "float", Default: "90", Description: "Maximum range"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetFloat64(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetFloat64(m, "max") + if err != nil { + return nil, err + } + + rangeOut, err := latitudeInRange(f, min, max) + if err != nil { + return nil, err + } + + return rangeOut, nil + }, + }) + + AddFuncLookup("longitude", Info{ + Display: "Longitude", + Category: "address", + Description: "Geographic coordinate indicating east-west position on Earth's surface", + Example: "-147.068112", + Output: "float", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return longitude(f), nil + }, + }) + + AddFuncLookup("longituderange", Info{ + Display: "Longitude Range", + Category: "address", + Description: "Longitude number between the given range (default min=0, max=180)", + Example: "-8.170450", + Output: "float", + Params: []Param{ + {Field: "min", Display: "Min", Type: "float", Default: "0", Description: "Minimum range"}, + {Field: "max", Display: "Max", Type: "float", Default: "180", Description: "Maximum range"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetFloat64(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetFloat64(m, "max") + if err != nil { + return nil, err + } + + rangeOut, err := longitudeInRange(f, min, max) + if err != nil { + return nil, err + } + + return rangeOut, nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/animal.go b/vendor/github.com/brianvoe/gofakeit/v7/animal.go new file mode 100644 index 0000000000..b70438b6b2 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/animal.go @@ -0,0 +1,178 @@ +package gofakeit + +// PetName will return a random fun pet name +func PetName() string { + return petName(GlobalFaker) +} + +// PetName will return a random fun pet name +func (f *Faker) PetName() string { + return petName(f) +} + +func petName(f *Faker) string { + return getRandValue(f, []string{"animal", "petname"}) +} + +// Animal will return a random animal +func Animal() string { + return animal(GlobalFaker) +} + +// Animal will return a random animal +func (f *Faker) Animal() string { + return animal(f) +} + +func animal(f *Faker) string { + return getRandValue(f, []string{"animal", "animal"}) +} + +// AnimalType will return a random animal type +func AnimalType() string { + return animalType(GlobalFaker) +} + +// AnimalType will return a random animal type +func (f *Faker) AnimalType() string { + return animalType(f) +} + +func animalType(f *Faker) string { + return getRandValue(f, []string{"animal", "type"}) +} + +// FarmAnimal will return a random animal that usually lives on a farm +func FarmAnimal() string { + return farmAnimal(GlobalFaker) +} + +// FarmAnimal will return a random animal that usually lives on a farm +func (f *Faker) FarmAnimal() string { + return farmAnimal(f) +} + +func farmAnimal(f *Faker) string { + return getRandValue(f, []string{"animal", "farm"}) +} + +// Cat will return a random cat breed +func Cat() string { + return cat(GlobalFaker) +} + +// Cat will return a random cat breed +func (f *Faker) Cat() string { + return cat(f) +} + +func cat(f *Faker) string { + return getRandValue(f, []string{"animal", "cat"}) +} + +// Dog will return a random dog breed +func Dog() string { + return dog(GlobalFaker) +} + +// Dog will return a random dog breed +func (f *Faker) Dog() string { + return dog(f) +} + +func dog(f *Faker) string { + return getRandValue(f, []string{"animal", "dog"}) +} + +// Bird will return a random bird species +func Bird() string { + return bird(GlobalFaker) +} + +// Bird will return a random bird species +func (f *Faker) Bird() string { + return bird(f) +} + +func bird(f *Faker) string { + return getRandValue(f, []string{"animal", "bird"}) +} + +func addAnimalLookup() { + AddFuncLookup("petname", Info{ + Display: "Pet Name", + Category: "animal", + Description: "Affectionate nickname given to a pet", + Example: "Ozzy Pawsborne", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return petName(f), nil + }, + }) + + AddFuncLookup("animal", Info{ + Display: "Animal", + Category: "animal", + Description: "Living creature with the ability to move, eat, and interact with its environment", + Example: "elk", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return animal(f), nil + }, + }) + + AddFuncLookup("animaltype", Info{ + Display: "Animal Type", + Category: "animal", + Description: "Type of animal, such as mammals, birds, reptiles, etc.", + Example: "amphibians", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return animalType(f), nil + }, + }) + + AddFuncLookup("farmanimal", Info{ + Display: "Farm Animal", + Category: "animal", + Description: "Animal name commonly found on a farm", + Example: "Chicken", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return farmAnimal(f), nil + }, + }) + + AddFuncLookup("cat", Info{ + Display: "Cat", + Category: "animal", + Description: "Various breeds that define different cats", + Example: "Chausie", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return cat(f), nil + }, + }) + + AddFuncLookup("dog", Info{ + Display: "Dog", + Category: "animal", + Description: "Various breeds that define different dogs", + Example: "Norwich Terrier", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return dog(f), nil + }, + }) + + AddFuncLookup("bird", Info{ + Display: "Bird", + Category: "animal", + Description: "Distinct species of birds", + Example: "goose", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bird(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/app.go b/vendor/github.com/brianvoe/gofakeit/v7/app.go new file mode 100644 index 0000000000..9c66cd5cfb --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/app.go @@ -0,0 +1,96 @@ +package gofakeit + +import ( + "fmt" +) + +// AppName will generate a random app name +func AppName() string { + return appName(GlobalFaker) +} + +// AppName will generate a random app name +func (f *Faker) AppName() string { + return appName(f) +} + +func appName(f *Faker) string { + name := "" + switch number(f, 1, 3) { + case 1: + name = noun(f) + verb(f) + case 2: + name = color(f) + noun(f) + case 3: + name = animal(f) + verb(f) + } + + return title(name) +} + +// AppVersion will generate a random app version +func AppVersion() string { + return appVersion(GlobalFaker) +} + +// AppVersion will generate a random app version +func (f *Faker) AppVersion() string { + return appVersion(f) +} + +func appVersion(f *Faker) string { + return fmt.Sprintf("%d.%d.%d", number(f, 1, 5), number(f, 1, 20), number(f, 1, 20)) +} + +// AppAuthor will generate a random company or person name +func AppAuthor() string { + return appAuthor(GlobalFaker) +} + +// AppAuthor will generate a random company or person name +func (f *Faker) AppAuthor() string { + return appAuthor(f) +} + +func appAuthor(f *Faker) string { + if boolFunc(f) { + return name(f) + } + + return company(f) +} + +func addAppLookup() { + AddFuncLookup("appname", Info{ + Display: "App Name", + Category: "app", + Description: "Software program designed for a specific purpose or task on a computer or mobile device", + Example: "Parkrespond", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return appName(f), nil + }, + }) + + AddFuncLookup("appversion", Info{ + Display: "App Version", + Category: "app", + Description: "Particular release of an application in Semantic Versioning format", + Example: "1.12.14", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return appVersion(f), nil + }, + }) + + AddFuncLookup("appauthor", Info{ + Display: "App Author", + Category: "app", + Description: "Person or group creating and developing an application", + Example: "Qado Energy, Inc.", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return appAuthor(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/auth.go b/vendor/github.com/brianvoe/gofakeit/v7/auth.go new file mode 100644 index 0000000000..53afa3e510 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/auth.go @@ -0,0 +1,163 @@ +package gofakeit + +// Username will generate a random username based upon picking a random lastname and random numbers at the end +func Username() string { + return username(GlobalFaker) +} + +// Username will generate a random username based upon picking a random lastname and random numbers at the end +func (f *Faker) Username() string { + return username(f) +} + +func username(f *Faker) string { + return getRandValue(f, []string{"person", "last"}) + replaceWithNumbers(f, "####") +} + +// Password will generate a random password. +// Minimum number length of 5 if less than. +func Password(lower bool, upper bool, numeric bool, special bool, space bool, num int) string { + return password(GlobalFaker, lower, upper, numeric, special, space, num) +} + +// Password will generate a random password. +// Minimum number length of 5 if less than. +func (f *Faker) Password(lower bool, upper bool, numeric bool, special bool, space bool, num int) string { + return password(f, lower, upper, numeric, special, space, num) +} + +func password(f *Faker, lower bool, upper bool, numeric bool, special bool, space bool, num int) string { + // Make sure the num minimum is at least 5 + if num < 5 { + num = 5 + } + + // Setup weights + items := make([]any, 0) + weights := make([]float32, 0) + if lower { + items = append(items, "l") + weights = append(weights, 4) + } + if upper { + items = append(items, "u") + weights = append(weights, 4) + } + if numeric { + items = append(items, "n") + weights = append(weights, 3) + } + if special { + items = append(items, "e") + weights = append(weights, 2) + } + if space { + items = append(items, "a") + weights = append(weights, 1) + } + + // If no items are selected then default to lower, upper, numeric + if len(items) == 0 { + items = append(items, "l", "u", "n") + weights = append(weights, 4, 4, 3) + } + + // Create byte slice + b := make([]byte, num) + + for i := 0; i <= num-1; i++ { + // Run weighted + weight, _ := weighted(f, items, weights) + + switch weight.(string) { + case "l": + b[i] = lowerStr[f.Int64()%int64(len(lowerStr))] + case "u": + b[i] = upperStr[f.Int64()%int64(len(upperStr))] + case "n": + b[i] = numericStr[f.Int64()%int64(len(numericStr))] + case "e": + b[i] = specialSafeStr[f.Int64()%int64(len(specialSafeStr))] + case "a": + b[i] = spaceStr[f.Int64()%int64(len(spaceStr))] + } + } + + // Shuffle bytes + for i := range b { + j := f.IntN(i + 1) + b[i], b[j] = b[j], b[i] + } + + // Replace first or last character if it's a space, and other options are available + if b[0] == ' ' { + b[0] = password(f, lower, upper, numeric, special, false, 1)[0] + } + if b[len(b)-1] == ' ' { + b[len(b)-1] = password(f, lower, upper, numeric, special, false, 1)[0] + } + + return string(b) +} + +func addAuthLookup() { + AddFuncLookup("username", Info{ + Display: "Username", + Category: "auth", + Description: "Unique identifier assigned to a user for accessing an account or system", + Example: "Daniel1364", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return username(f), nil + }, + }) + + AddFuncLookup("password", Info{ + Display: "Password", + Category: "auth", + Description: "Secret word or phrase used to authenticate access to a system or account", + Example: "EEP+wwpk 4lU-eHNXlJZ4n K9%v&TZ9e", + Output: "string", + Params: []Param{ + {Field: "lower", Display: "Lower", Type: "bool", Default: "true", Description: "Whether or not to add lower case characters"}, + {Field: "upper", Display: "Upper", Type: "bool", Default: "true", Description: "Whether or not to add upper case characters"}, + {Field: "numeric", Display: "Numeric", Type: "bool", Default: "true", Description: "Whether or not to add numeric characters"}, + {Field: "special", Display: "Special", Type: "bool", Default: "true", Description: "Whether or not to add special characters"}, + {Field: "space", Display: "Space", Type: "bool", Default: "false", Description: "Whether or not to add spaces"}, + {Field: "length", Display: "Length", Type: "int", Default: "12", Description: "Number of characters in password"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + lower, err := info.GetBool(m, "lower") + if err != nil { + return nil, err + } + + upper, err := info.GetBool(m, "upper") + if err != nil { + return nil, err + } + + numeric, err := info.GetBool(m, "numeric") + if err != nil { + return nil, err + } + + special, err := info.GetBool(m, "special") + if err != nil { + return nil, err + } + + space, err := info.GetBool(m, "space") + if err != nil { + return nil, err + } + + length, err := info.GetInt(m, "length") + if err != nil { + return nil, err + } + + return password(f, lower, upper, numeric, special, space, length), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/beer.go b/vendor/github.com/brianvoe/gofakeit/v7/beer.go new file mode 100644 index 0000000000..a6bc493e6d --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/beer.go @@ -0,0 +1,207 @@ +package gofakeit + +import ( + "strconv" +) + +// BeerName will return a random beer name +func BeerName() string { + return beerName(GlobalFaker) +} + +// BeerName will return a random beer name +func (f *Faker) BeerName() string { + return beerName(f) +} + +func beerName(f *Faker) string { + return getRandValue(f, []string{"beer", "name"}) +} + +// BeerStyle will return a random beer style +func BeerStyle() string { + return beerStyle(GlobalFaker) +} + +// BeerStyle will return a random beer style +func (f *Faker) BeerStyle() string { + return beerStyle(f) +} + +func beerStyle(f *Faker) string { + return getRandValue(f, []string{"beer", "style"}) +} + +// BeerHop will return a random beer hop +func BeerHop() string { + return beerHop(GlobalFaker) +} + +// BeerHop will return a random beer hop +func (f *Faker) BeerHop() string { + return beerHop(f) +} + +func beerHop(f *Faker) string { + return getRandValue(f, []string{"beer", "hop"}) +} + +// BeerYeast will return a random beer yeast +func BeerYeast() string { + return beerYeast(GlobalFaker) +} + +// BeerYeast will return a random beer yeast +func (f *Faker) BeerYeast() string { + return beerYeast(f) +} + +func beerYeast(f *Faker) string { + return getRandValue(f, []string{"beer", "yeast"}) +} + +// BeerMalt will return a random beer malt +func BeerMalt() string { + return beerMalt(GlobalFaker) +} + +// BeerMalt will return a random beer malt +func (f *Faker) BeerMalt() string { + return beerMalt(f) +} + +func beerMalt(f *Faker) string { + return getRandValue(f, []string{"beer", "malt"}) +} + +// BeerAlcohol will return a random beer alcohol level between 2.0 and 10.0 +func BeerAlcohol() string { + return beerAlcohol(GlobalFaker) +} + +// BeerAlcohol will return a random beer alcohol level between 2.0 and 10.0 +func (f *Faker) BeerAlcohol() string { + return beerAlcohol(f) +} + +func beerAlcohol(f *Faker) string { + return strconv.FormatFloat(float64Range(f, 2.0, 10.0), 'f', 1, 64) + "%" +} + +// BeerIbu will return a random beer ibu value between 10 and 100 +func BeerIbu() string { + return beerIbu(GlobalFaker) +} + +// BeerIbu will return a random beer ibu value between 10 and 100 +func (f *Faker) BeerIbu() string { + return beerIbu(f) +} + +func beerIbu(f *Faker) string { + return strconv.Itoa(randIntRange(f, 10, 100)) + " IBU" +} + +// BeerBlg will return a random beer blg between 5.0 and 20.0 +func BeerBlg() string { + return beerBlg(GlobalFaker) +} + +// BeerBlg will return a random beer blg between 5.0 and 20.0 +func (f *Faker) BeerBlg() string { + return beerBlg(f) +} + +func beerBlg(f *Faker) string { + return strconv.FormatFloat(float64Range(f, 5.0, 20.0), 'f', 1, 64) + "°Blg" +} + +func addBeerLookup() { + AddFuncLookup("beername", Info{ + Display: "Beer Name", + Category: "beer", + Description: "Specific brand or variety of beer", + Example: "Duvel", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerName(f), nil + }, + }) + + AddFuncLookup("beerstyle", Info{ + Display: "Beer Style", + Category: "beer", + Description: "Distinct characteristics and flavors of beer", + Example: "European Amber Lager", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerStyle(f), nil + }, + }) + + AddFuncLookup("beerhop", Info{ + Display: "Beer Hop", + Category: "beer", + Description: "The flower used in brewing to add flavor, aroma, and bitterness to beer", + Example: "Glacier", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerHop(f), nil + }, + }) + + AddFuncLookup("beeryeast", Info{ + Display: "Beer Yeast", + Category: "beer", + Description: "Microorganism used in brewing to ferment sugars, producing alcohol and carbonation in beer", + Example: "1388 - Belgian Strong Ale", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerYeast(f), nil + }, + }) + + AddFuncLookup("beermalt", Info{ + Display: "Beer Malt", + Category: "beer", + Description: "Processed barley or other grains, provides sugars for fermentation and flavor to beer", + Example: "Munich", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerMalt(f), nil + }, + }) + + AddFuncLookup("beeralcohol", Info{ + Display: "Beer Alcohol", + Category: "beer", + Description: "Measures the alcohol content in beer", + Example: "2.7%", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerAlcohol(f), nil + }, + }) + + AddFuncLookup("beeribu", Info{ + Display: "Beer IBU", + Category: "beer", + Description: "Scale measuring bitterness of beer from hops", + Example: "29 IBU", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerIbu(f), nil + }, + }) + + AddFuncLookup("beerblg", Info{ + Display: "Beer BLG", + Category: "beer", + Description: "Scale indicating the concentration of extract in worts", + Example: "6.4°Blg", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return beerBlg(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/book.go b/vendor/github.com/brianvoe/gofakeit/v7/book.go new file mode 100644 index 0000000000..fd8e0910b7 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/book.go @@ -0,0 +1,88 @@ +package gofakeit + +func BookTitle() string { return bookTitle(GlobalFaker) } + +func (f *Faker) BookTitle() string { return bookTitle(f) } + +func bookTitle(f *Faker) string { return getRandValue(f, []string{"book", "title"}) } + +func BookAuthor() string { return bookAuthor(GlobalFaker) } + +func (f *Faker) BookAuthor() string { return bookAuthor(f) } + +func bookAuthor(f *Faker) string { return getRandValue(f, []string{"book", "author"}) } + +func BookGenre() string { return bookGenre(GlobalFaker) } + +func (f *Faker) BookGenre() string { return bookGenre(f) } + +func bookGenre(f *Faker) string { return getRandValue(f, []string{"book", "genre"}) } + +type BookInfo struct { + Title string `json:"title" xml:"name"` + Author string `json:"author" xml:"author"` + Genre string `json:"genre" xml:"genre"` +} + +func Book() *BookInfo { return book(GlobalFaker) } + +func (f *Faker) Book() *BookInfo { return book(f) } + +func book(f *Faker) *BookInfo { + return &BookInfo{ + Title: bookTitle(f), + Author: bookAuthor(f), + Genre: bookGenre(f), + } +} + +func addBookLookup() { + AddFuncLookup("book", Info{ + Display: "Book", + Category: "book", + Description: "Written or printed work consisting of pages bound together, covering various subjects or stories", + Example: `{ + "title": "Anna Karenina", + "author": "Toni Morrison", + "genre": "Thriller" +}`, + Output: "map[string]string", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return book(f), nil + }, + }) + + AddFuncLookup("booktitle", Info{ + Display: "Title", + Category: "book", + Description: "The specific name given to a book", + Example: "Hamlet", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bookTitle(f), nil + }, + }) + + AddFuncLookup("bookauthor", Info{ + Display: "Author", + Category: "book", + Description: "The individual who wrote or created the content of a book", + Example: "Mark Twain", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bookAuthor(f), nil + }, + }) + + AddFuncLookup("bookgenre", Info{ + Display: "Genre", + Category: "book", + Description: "Category or type of book defined by its content, style, or form", + Example: "Adventure", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bookGenre(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/car.go b/vendor/github.com/brianvoe/gofakeit/v7/car.go new file mode 100644 index 0000000000..def82dc497 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/car.go @@ -0,0 +1,146 @@ +package gofakeit + +// CarInfo is a struct dataset of all car information +type CarInfo struct { + Type string `json:"type" xml:"type"` + Fuel string `json:"fuel" xml:"fuel"` + Transmission string `json:"transmission" xml:"transmission"` + Brand string `json:"brand" xml:"brand"` + Model string `json:"model" xml:"model"` + Year int `json:"year" xml:"year"` +} + +// Car will generate a struct with car information +func Car() *CarInfo { return car(GlobalFaker) } + +// Car will generate a struct with car information +func (f *Faker) Car() *CarInfo { return car(f) } + +func car(f *Faker) *CarInfo { + return &CarInfo{ + Type: carType(f), + Fuel: carFuelType(f), + Transmission: carTransmissionType(f), + Brand: carMaker(f), + Model: carModel(f), + Year: year(f), + } +} + +// CarType will generate a random car type string +func CarType() string { return carType(GlobalFaker) } + +// CarType will generate a random car type string +func (f *Faker) CarType() string { return carType(f) } + +func carType(f *Faker) string { return getRandValue(f, []string{"car", "type"}) } + +// CarFuelType will return a random fuel type +func CarFuelType() string { return carFuelType(GlobalFaker) } + +// CarFuelType will return a random fuel type +func (f *Faker) CarFuelType() string { return carFuelType(f) } + +func carFuelType(f *Faker) string { return getRandValue(f, []string{"car", "fuel_type"}) } + +// CarTransmissionType will return a random transmission type +func CarTransmissionType() string { return carTransmissionType(GlobalFaker) } + +// CarTransmissionType will return a random transmission type +func (f *Faker) CarTransmissionType() string { return carTransmissionType(f) } + +func carTransmissionType(f *Faker) string { + return getRandValue(f, []string{"car", "transmission_type"}) +} + +// CarMaker will return a random car maker +func CarMaker() string { return carMaker(GlobalFaker) } + +// CarMaker will return a random car maker +func (f *Faker) CarMaker() string { return carMaker(f) } + +func carMaker(f *Faker) string { return getRandValue(f, []string{"car", "maker"}) } + +// CarModel will return a random car model +func CarModel() string { return carModel(GlobalFaker) } + +// CarModel will return a random car model +func (f *Faker) CarModel() string { return carModel(f) } + +func carModel(f *Faker) string { return getRandValue(f, []string{"car", "model"}) } + +func addCarLookup() { + AddFuncLookup("car", Info{ + Display: "Car", + Category: "car", + Description: "Wheeled motor vehicle used for transportation", + Example: `{ + "type": "Passenger car mini", + "fuel": "Gasoline", + "transmission": "Automatic", + "brand": "Fiat", + "model": "Freestyle Fwd", + "year": 1991 +}`, + Output: "map[string]any", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return car(f), nil + }, + }) + + AddFuncLookup("cartype", Info{ + Display: "Car Type", + Category: "car", + Description: "Classification of cars based on size, use, or body style", + Example: "Passenger car mini", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return carType(f), nil + }, + }) + + AddFuncLookup("carfueltype", Info{ + Display: "Car Fuel Type", + Category: "car", + Description: "Type of energy source a car uses", + Example: "CNG", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return carFuelType(f), nil + }, + }) + + AddFuncLookup("cartransmissiontype", Info{ + Display: "Car Transmission Type", + Category: "car", + Description: "Mechanism a car uses to transmit power from the engine to the wheels", + Example: "Manual", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return carTransmissionType(f), nil + }, + }) + + AddFuncLookup("carmaker", Info{ + Display: "Car Maker", + Category: "car", + Description: "Company or brand that manufactures and designs cars", + Example: "Nissan", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return carMaker(f), nil + }, + }) + + AddFuncLookup("carmodel", Info{ + Display: "Car Model", + Category: "car", + Description: "Specific design or version of a car produced by a manufacturer", + Example: "Aveo", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return carModel(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/celebrity.go b/vendor/github.com/brianvoe/gofakeit/v7/celebrity.go new file mode 100644 index 0000000000..b00036d883 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/celebrity.go @@ -0,0 +1,62 @@ +package gofakeit + +// CelebrityActor will generate a random celebrity actor +func CelebrityActor() string { return celebrityActor(GlobalFaker) } + +// CelebrityActor will generate a random celebrity actor +func (f *Faker) CelebrityActor() string { return celebrityActor(f) } + +func celebrityActor(f *Faker) string { return getRandValue(f, []string{"celebrity", "actor"}) } + +// CelebrityBusiness will generate a random celebrity business person +func CelebrityBusiness() string { return celebrityBusiness(GlobalFaker) } + +// CelebrityBusiness will generate a random celebrity business person +func (f *Faker) CelebrityBusiness() string { return celebrityBusiness(f) } + +func celebrityBusiness(f *Faker) string { + return getRandValue(f, []string{"celebrity", "business"}) +} + +// CelebritySport will generate a random celebrity sport person +func CelebritySport() string { return celebritySport(GlobalFaker) } + +// CelebritySport will generate a random celebrity sport person +func (f *Faker) CelebritySport() string { return celebritySport(f) } + +func celebritySport(f *Faker) string { return getRandValue(f, []string{"celebrity", "sport"}) } + +func addCelebrityLookup() { + AddFuncLookup("celebrityactor", Info{ + Display: "Celebrity Actor", + Category: "celebrity", + Description: "Famous person known for acting in films, television, or theater", + Example: "Brad Pitt", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return celebrityActor(f), nil + }, + }) + + AddFuncLookup("celebritybusiness", Info{ + Display: "Celebrity Business", + Category: "celebrity", + Description: "High-profile individual known for significant achievements in business or entrepreneurship", + Example: "Elon Musk", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return celebrityBusiness(f), nil + }, + }) + + AddFuncLookup("celebritysport", Info{ + Display: "Celebrity Sport", + Category: "celebrity", + Description: "Famous athlete known for achievements in a particular sport", + Example: "Michael Phelps", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return celebritySport(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/color.go b/vendor/github.com/brianvoe/gofakeit/v7/color.go new file mode 100644 index 0000000000..fd8d256859 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/color.go @@ -0,0 +1,116 @@ +package gofakeit + +import ( + "github.com/brianvoe/gofakeit/v7/data" +) + +// Color will generate a random color string +func Color() string { return color(GlobalFaker) } + +// Color will generate a random color string +func (f *Faker) Color() string { return color(f) } + +func color(f *Faker) string { return getRandValue(f, []string{"color", "full"}) } + +// NiceColor will generate a random safe color string +func NiceColors() []string { return niceColors(GlobalFaker) } + +// NiceColor will generate a random safe color string +func (f *Faker) NiceColors() []string { return niceColors(f) } + +func niceColors(f *Faker) []string { + return data.ColorsNice[randIntRange(f, 0, len(data.ColorsNice)-1)] +} + +// SafeColor will generate a random safe color string +func SafeColor() string { return safeColor(GlobalFaker) } + +// SafeColor will generate a random safe color string +func (f *Faker) SafeColor() string { return safeColor(f) } + +func safeColor(f *Faker) string { return getRandValue(f, []string{"color", "safe"}) } + +// HexColor will generate a random hexadecimal color string +func HexColor() string { return hexColor(GlobalFaker) } + +// HexColor will generate a random hexadecimal color string +func (f *Faker) HexColor() string { return hexColor(f) } + +func hexColor(f *Faker) string { + color := make([]byte, 6) + hashQuestion := []byte("?#") + for i := 0; i < 6; i++ { + color[i] = hashQuestion[f.IntN(2)] + } + + return "#" + replaceWithHexLetters(f, replaceWithNumbers(f, string(color))) +} + +// RGBColor will generate a random int slice color +func RGBColor() []int { return rgbColor(GlobalFaker) } + +// RGBColor will generate a random int slice color +func (f *Faker) RGBColor() []int { return rgbColor(f) } + +func rgbColor(f *Faker) []int { + return []int{randIntRange(f, 0, 255), randIntRange(f, 0, 255), randIntRange(f, 0, 255)} +} + +func addColorLookup() { + AddFuncLookup("color", Info{ + Display: "Color", + Category: "color", + Description: "Hue seen by the eye, returns the name of the color like red or blue", + Example: "MediumOrchid", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return color(f), nil + }, + }) + + AddFuncLookup("nicecolors", Info{ + Display: "Nice Colors", + Category: "color", + Description: "Attractive and appealing combinations of colors, returns an list of color hex codes", + Example: `["#cfffdd","#b4dec1","#5c5863","#a85163","#ff1f4c"]`, + Output: "[]string", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return niceColors(f), nil + }, + }) + + AddFuncLookup("safecolor", Info{ + Display: "Safe Color", + Category: "color", + Description: "Colors displayed consistently on different web browsers and devices", + Example: "black", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return safeColor(f), nil + }, + }) + + AddFuncLookup("hexcolor", Info{ + Display: "Hex Color", + Category: "color", + Description: "Six-digit code representing a color in the color model", + Example: "#a99fb4", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hexColor(f), nil + }, + }) + + AddFuncLookup("rgbcolor", Info{ + Display: "RGB Color", + Category: "color", + Description: "Color defined by red, green, and blue light values", + Example: "[85, 224, 195]", + Output: "[]int", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return rgbColor(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/company.go b/vendor/github.com/brianvoe/gofakeit/v7/company.go new file mode 100644 index 0000000000..64167295ed --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/company.go @@ -0,0 +1,229 @@ +package gofakeit + +// Company will generate a random company name string +func Company() string { return company(GlobalFaker) } + +// Company will generate a random company name string +func (f *Faker) Company() string { return company(f) } + +func company(f *Faker) string { return getRandValue(f, []string{"company", "name"}) } + +// CompanySuffix will generate a random company suffix string +func CompanySuffix() string { return companySuffix(GlobalFaker) } + +// CompanySuffix will generate a random company suffix string +func (f *Faker) CompanySuffix() string { return companySuffix(f) } + +func companySuffix(f *Faker) string { return getRandValue(f, []string{"company", "suffix"}) } + +// Blurb will generate a random company blurb string +func Blurb() string { return blurb(GlobalFaker) } + +func (f *Faker) Blurb() string { return blurb(f) } + +func blurb(f *Faker) string { return getRandValue(f, []string{"company", "blurb"}) } + +// BuzzWord will generate a random company buzz word string +func BuzzWord() string { return buzzWord(GlobalFaker) } + +// BuzzWord will generate a random company buzz word string +func (f *Faker) BuzzWord() string { return buzzWord(f) } + +func buzzWord(f *Faker) string { return getRandValue(f, []string{"company", "buzzwords"}) } + +// BS will generate a random company bs string +func BS() string { return bs(GlobalFaker) } + +// BS will generate a random company bs string +func (f *Faker) BS() string { return bs(f) } + +func bs(f *Faker) string { return getRandValue(f, []string{"company", "bs"}) } + +// JobInfo is a struct of job information +type JobInfo struct { + Company string `json:"company" xml:"company"` + Title string `json:"title" xml:"title"` + Descriptor string `json:"descriptor" xml:"descriptor"` + Level string `json:"level" xml:"level"` +} + +// Job will generate a struct with random job information +func Job() *JobInfo { return job(GlobalFaker) } + +// Job will generate a struct with random job information +func (f *Faker) Job() *JobInfo { return job(f) } + +func job(f *Faker) *JobInfo { + return &JobInfo{ + Company: company(f), + Title: jobTitle(f), + Descriptor: jobDescriptor(f), + Level: jobLevel(f), + } +} + +// JobTitle will generate a random job title string +func JobTitle() string { return jobTitle(GlobalFaker) } + +// JobTitle will generate a random job title string +func (f *Faker) JobTitle() string { return jobTitle(f) } + +func jobTitle(f *Faker) string { return getRandValue(f, []string{"job", "title"}) } + +// JobDescriptor will generate a random job descriptor string +func JobDescriptor() string { return jobDescriptor(GlobalFaker) } + +// JobDescriptor will generate a random job descriptor string +func (f *Faker) JobDescriptor() string { return jobDescriptor(f) } + +func jobDescriptor(f *Faker) string { return getRandValue(f, []string{"job", "descriptor"}) } + +// JobLevel will generate a random job level string +func JobLevel() string { return jobLevel(GlobalFaker) } + +// JobLevel will generate a random job level string +func (f *Faker) JobLevel() string { return jobLevel(f) } + +func jobLevel(f *Faker) string { return getRandValue(f, []string{"job", "level"}) } + +// Slogan will generate a random company slogan +func Slogan() string { return slogan(GlobalFaker) } + +// Slogan will generate a random company slogan +func (f *Faker) Slogan() string { return slogan(f) } + +// Slogan will generate a random company slogan +func slogan(f *Faker) string { + slogan := "" + var sloganStyle = number(f, 0, 2) + switch sloganStyle { + // Noun. Buzzword! + case 0: + slogan = getRandValue(f, []string{"company", "blurb"}) + ". " + getRandValue(f, []string{"company", "buzzwords"}) + "!" + // Buzzword Noun, Buzzword Noun. + case 1: + slogan = getRandValue(f, []string{"company", "buzzwords"}) + " " + getRandValue(f, []string{"company", "blurb"}) + ", " + getRandValue(f, []string{"company", "buzzwords"}) + " " + getRandValue(f, []string{"company", "blurb"}) + "." + // Buzzword bs Noun, Buzzword. + case 2: + slogan = getRandValue(f, []string{"company", "buzzwords"}) + " " + getRandValue(f, []string{"company", "bs"}) + " " + getRandValue(f, []string{"company", "blurb"}) + ", " + getRandValue(f, []string{"company", "buzzwords"}) + "." + } + return slogan +} + +func addCompanyLookup() { + AddFuncLookup("company", Info{ + Display: "Company", + Category: "company", + Description: "Designated official name of a business or organization", + Example: "Moen, Pagac and Wuckert", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return company(f), nil + }, + }) + + AddFuncLookup("companysuffix", Info{ + Display: "Company Suffix", + Category: "company", + Description: "Suffix at the end of a company name, indicating business structure, like 'Inc.' or 'LLC'", + Example: "Inc", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return companySuffix(f), nil + }, + }) + + AddFuncLookup("bs", Info{ + Display: "BS", + Category: "company", + Description: "Random bs company word", + Example: "front-end", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bs(f), nil + }, + }) + + AddFuncLookup("blurb", Info{ + Display: "Blurb", + Category: "company", + Description: "Brief description or summary of a company's purpose, products, or services", + Example: "word", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return blurb(f), nil + }, + }) + + AddFuncLookup("buzzword", Info{ + Display: "Buzzword", + Category: "company", + Description: "Trendy or overused term often used in business to sound impressive", + Example: "disintermediate", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return buzzWord(f), nil + }, + }) + + AddFuncLookup("job", Info{ + Display: "Job", + Category: "company", + Description: "Position or role in employment, involving specific tasks and responsibilities", + Example: `{ + "company": "ClearHealthCosts", + "title": "Agent", + "descriptor": "Future", + "level": "Tactics" +}`, + Output: "map[string]string", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return job(f), nil + }, + }) + + AddFuncLookup("jobtitle", Info{ + Display: "Job Title", + Category: "company", + Description: "Specific title for a position or role within a company or organization", + Example: "Director", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return jobTitle(f), nil + }, + }) + + AddFuncLookup("jobdescriptor", Info{ + Display: "Job Descriptor", + Category: "company", + Description: "Word used to describe the duties, requirements, and nature of a job", + Example: "Central", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return jobDescriptor(f), nil + }, + }) + + AddFuncLookup("joblevel", Info{ + Display: "Job Level", + Category: "company", + Description: "Random job level", + Example: "Assurance", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return jobLevel(f), nil + }, + }) + + AddFuncLookup("slogan", Info{ + Display: "Slogan", + Category: "company", + Description: "Catchphrase or motto used by a company to represent its brand or values", + Example: "Universal seamless Focus, interactive.", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return slogan(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/csv.go b/vendor/github.com/brianvoe/gofakeit/v7/csv.go new file mode 100644 index 0000000000..7f31ec2f2b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/csv.go @@ -0,0 +1,183 @@ +package gofakeit + +import ( + "bytes" + "encoding/csv" + "encoding/json" + "errors" + "fmt" + "reflect" + "strings" +) + +// CSVOptions defines values needed for csv generation +type CSVOptions struct { + Delimiter string `json:"delimiter" xml:"delimiter" fake:"{randomstring:[,,tab]}"` + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` + Fields []Field `json:"fields" xml:"fields" fake:"{fields}"` +} + +// CSV generates an object or an array of objects in json format +// A nil CSVOptions returns a randomly structured CSV. +func CSV(co *CSVOptions) ([]byte, error) { return csvFunc(GlobalFaker, co) } + +// CSV generates an object or an array of objects in json format +// A nil CSVOptions returns a randomly structured CSV. +func (f *Faker) CSV(co *CSVOptions) ([]byte, error) { return csvFunc(f, co) } + +func csvFunc(f *Faker, co *CSVOptions) ([]byte, error) { + if co == nil { + // We didn't get a CSVOptions, so create a new random one + err := f.Struct(&co) + if err != nil { + return nil, err + } + } + + // Check delimiter + if co.Delimiter == "" { + co.Delimiter = "," + } + if strings.ToLower(co.Delimiter) == "tab" { + co.Delimiter = "\t" + } + if co.Delimiter != "," && co.Delimiter != "\t" && co.Delimiter != ";" { + return nil, errors.New("invalid delimiter type") + } + + // Check fields + if co.Fields == nil || len(co.Fields) <= 0 { + return nil, errors.New("must pass fields in order to build json object(s)") + } + + // Make sure you set a row count + if co.RowCount <= 0 { + return nil, errors.New("must have row count") + } + + b := &bytes.Buffer{} + w := csv.NewWriter(b) + w.Comma = []rune(co.Delimiter)[0] + + // Add header row + header := make([]string, len(co.Fields)) + for i, field := range co.Fields { + header[i] = field.Name + } + w.Write(header) + + // Loop through row count +1(for header) and add fields + for i := 1; i < co.RowCount+1; i++ { + vr := make([]string, len(co.Fields)) + + // Loop through fields and add to them to map[string]any + for ii, field := range co.Fields { + if field.Function == "autoincrement" { + vr[ii] = fmt.Sprintf("%d", i) + continue + } + + // Get function info + funcInfo := GetFuncLookup(field.Function) + if funcInfo == nil { + return nil, errors.New("invalid function, " + field.Function + " does not exist") + } + + value, err := funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return nil, err + } + + if _, ok := value.([]byte); ok { + // If it's a slice of bytes or struct, unmarshal it into an interface + var v any + if err := json.Unmarshal(value.([]byte), &v); err != nil { + return nil, err + } + value = v + } + + // If the value is a list of possible values, marsha it into a string + if reflect.TypeOf(value).Kind() == reflect.Struct || + reflect.TypeOf(value).Kind() == reflect.Ptr || + reflect.TypeOf(value).Kind() == reflect.Map || + reflect.TypeOf(value).Kind() == reflect.Slice { + b, err := json.Marshal(value) + if err != nil { + return nil, err + } + value = string(b) + } + + vr[ii] = fmt.Sprintf("%v", value) + } + + w.Write(vr) + } + + w.Flush() + + if err := w.Error(); err != nil { + return nil, err + } + + return b.Bytes(), nil +} + +func addFileCSVLookup() { + AddFuncLookup("csv", Info{ + Display: "CSV", + Category: "file", + Description: "Individual lines or data entries within a CSV (Comma-Separated Values) format", + Example: `id,first_name,last_name,password +1,Markus,Moen,Dc0VYXjkWABx +2,Osborne,Hilll,XPJ9OVNbs5lm`, + Output: "[]byte", + ContentType: "text/csv", + Params: []Param{ + {Field: "delimiter", Display: "Delimiter", Type: "string", Default: ",", Description: "Separator in between row values"}, + {Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows"}, + {Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + co := CSVOptions{} + + delimiter, err := info.GetString(m, "delimiter") + if err != nil { + return nil, err + } + co.Delimiter = delimiter + + rowcount, err := info.GetInt(m, "rowcount") + if err != nil { + return nil, err + } + co.RowCount = rowcount + + fieldsStr, err := info.GetStringArray(m, "fields") + if err != nil { + return nil, err + } + + // Check to make sure fields has length + if len(fieldsStr) > 0 { + co.Fields = make([]Field, len(fieldsStr)) + + for i, f := range fieldsStr { + // Unmarshal fields string into fields array + err = json.Unmarshal([]byte(f), &co.Fields[i]) + if err != nil { + return nil, err + } + } + } + + csvOut, err := csvFunc(f, &co) + if err != nil { + return nil, err + } + + return csvOut, nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/README.md b/vendor/github.com/brianvoe/gofakeit/v7/data/README.md new file mode 100644 index 0000000000..64441741c2 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/README.md @@ -0,0 +1,33 @@ +# Gofakeit Data + +Gofakeit data set + +## List + +```go +List() +``` + +## Get/Set/Remove Data + +```go +data.Get("desserts") + +data.Set("desserts", map[string][]string{ + "cake": {"chocolate", "vanilla"}, + "pie": {"apple", "pecan"}, + "ice cream": {"strawberry", "vanilla"}, +}) + +data.Remove("desserts") +``` + +## Get/Set/Remove Sub Data + +```go +data.GetSubData("desserts", "cake") + +data.SetSub("desserts", "cake", []string{"chocolate", "vanilla"}) + +data.RemoveSub("desserts", "cake") +``` diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/address.go b/vendor/github.com/brianvoe/gofakeit/v7/data/address.go new file mode 100644 index 0000000000..98d88e8219 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/address.go @@ -0,0 +1,15 @@ +package data + +// Address consists of address information +var Address = map[string][]string{ + "number": {"#####", "####", "###"}, + "street_prefix": {"North", "East", "West", "South", "New", "Lake", "Port"}, + "street_name": {"Alley", "Avenue", "Branch", "Bridge", "Brook", "Brooks", "Burg", "Burgs", "Bypass", "Camp", "Canyon", "Cape", "Causeway", "Center", "Centers", "Circle", "Circles", "Cliff", "Cliffs", "Club", "Common", "Corner", "Corners", "Course", "Court", "Courts", "Cove", "Coves", "Creek", "Crescent", "Crest", "Crossing", "Crossroad", "Curve", "Dale", "Dam", "Divide", "Drive", "Drive", "Drives", "Estate", "Estates", "Expressway", "Extension", "Extensions", "Fall", "Falls", "Ferry", "Field", "Fields", "Flat", "Flats", "Ford", "Fords", "Forest", "Forge", "Forges", "Fork", "Forks", "Fort", "Freeway", "Garden", "Gardens", "Gateway", "Glen", "Glens", "Green", "Greens", "Grove", "Groves", "Harbor", "Harbors", "Haven", "Heights", "Highway", "Hill", "Hills", "Hollow", "Inlet", "Inlet", "Island", "Island", "Islands", "Islands", "Isle", "Isle", "Junction", "Junctions", "Key", "Keys", "Knoll", "Knolls", "Lake", "Lakes", "Land", "Landing", "Lane", "Light", "Lights", "Loaf", "Lock", "Locks", "Locks", "Lodge", "Lodge", "Loop", "Mall", "Manor", "Manors", "Meadow", "Meadows", "Mews", "Mill", "Mills", "Mission", "Mission", "Motorway", "Mount", "Mountain", "Mountain", "Mountains", "Mountains", "Neck", "Orchard", "Oval", "Overpass", "Park", "Parks", "Parkway", "Parkways", "Pass", "Passage", "Path", "Pike", "Pine", "Pines", "Place", "Plain", "Plains", "Plains", "Plaza", "Plaza", "Point", "Points", "Port", "Port", "Ports", "Ports", "Prairie", "Prairie", "Radial", "Ramp", "Ranch", "Rapid", "Rapids", "Rest", "Ridge", "Ridges", "River", "Road", "Road", "Roads", "Roads", "Route", "Row", "Rue", "Run", "Shoal", "Shoals", "Shore", "Shores", "Skyway", "Spring", "Springs", "Springs", "Spur", "Spurs", "Square", "Square", "Squares", "Squares", "Station", "Station", "Stravenue", "Stravenue", "Stream", "Stream", "Street", "Street", "Streets", "Summit", "Summit", "Terrace", "Throughway", "Trace", "Track", "Trafficway", "Trail", "Trail", "Tunnel", "Tunnel", "Turnpike", "Turnpike", "Underpass", "Union", "Unions", "Valley", "Valleys", "Via", "Viaduct", "View", "Views", "Village", "Village", "Villages", "Ville", "Vista", "Vista", "Walk", "Walks", "Wall", "Way", "Ways", "Well", "Wells"}, + "street_suffix": {"town", "ton", "land", "ville", "berg", "burgh", "borough", "bury", "view", "port", "mouth", "stad", "furt", "chester", "mouth", "fort", "haven", "side", "shire"}, + "city": {"New York City", "Los Angeles", "Chicago", "Houston", "Philadelphia", "Phoenix", "San Antonio", "San Diego", "Dallas", "San Jose", "Austin", "Jacksonville", "Indianapolis", "San Francisco", "Columbus", "Fort Worth", "Charlotte", "Detroit", "El Paso", "Memphis", "Boston", "Seattle", "Denver", "Washington", "Nashville-Davidson", "Baltimore", "Louisville/Jefferson", "Portland", "Oklahoma", "Milwaukee", "Las Vegas", "Albuquerque", "Tucson", "Fresno", "Sacramento", "Long Beach", "Kansas", "Mesa", "Virginia Beach", "Atlanta", "Colorado Springs", "Raleigh", "Omaha", "Miami", "Oakland", "Tulsa", "Minneapolis", "Cleveland", "Wichita", "Arlington", "New Orleans", "Bakersfield", "Tampa", "Honolulu", "Anaheim", "Aurora", "Santa Ana", "St. Louis", "Riverside", "Corpus Christi", "Pittsburgh", "Lexington-Fayette", "Stockton", "Cincinnati", "St. Paul", "Toledo", "Newark", "Greensboro", "Plano", "Henderson", "Lincoln", "Buffalo", "Fort Wayne", "Jersey", "Chula Vista", "Orlando", "St. Petersburg", "Norfolk", "Chandler", "Laredo", "Madison", "Durham", "Lubbock", "Winston-Salem", "Garland", "Glendale", "Hialeah", "Reno", "Baton Rouge", "Irvine", "Chesapeake", "Irving", "Scottsdale", "North Las Vegas", "Fremont", "San Bernardino", "Boise", "Birmingham"}, + "state": {"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"}, + "state_abr": {"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY", "AE", "AA", "AP"}, + "zip": {"#####"}, + "country": {"Andorra", "United Arab Emirates", "Afghanistan", "Antigua and Barbuda", "Anguilla", "Albania", "Armenia", "Angola", "Antarctica", "Argentina", "American Samoa", "Austria", "Australia", "Aruba", "Åland Islands", "Azerbaijan", "Bosnia and Herzegovina", "Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria", "Bahrain", "Burundi", "Benin", "Saint Barthélemy", "Bermuda", "Brunei Darussalam", "Bolivia (Plurinational State of)", "Bonaire, Sint Eustatius and Saba", "Brazil", "Bahamas", "Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize", "Canada", "Cocos (Keeling) Islands", "Congo, Democratic Republic of the", "Central African Republic", "Congo", "Switzerland", "Côte d'Ivoire", "Cook Islands", "Chile", "Cameroon", "China", "Colombia", "Costa Rica", "Cuba", "Cabo Verde", "Curaçao", "Christmas Island", "Cyprus", "Czechia", "Germany", "Djibouti", "Denmark", "Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia", "Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia", "Finland", "Fiji", "Falkland Islands (Malvinas)", "Micronesia (Federated States of)", "Faroe Islands", "France", "Gabon", "United Kingdom of Great Britain and Northern Ireland", "Grenada", "Georgia", "French Guiana", "Guernsey", "Ghana", "Gibraltar", "Greenland", "Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece", "South Georgia and the South Sandwich Islands", "Guatemala", "Guam", "Guinea-Bissau", "Guyana", "Hong Kong", "Heard Island and McDonald Islands", "Honduras", "Croatia", "Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "Isle of Man", "India", "British Indian Ocean Territory", "Iraq", "Iran (Islamic Republic of)", "Iceland", "Italy", "Jersey", "Jamaica", "Jordan", "Japan", "Kenya", "Kyrgyzstan", "Cambodia", "Kiribati", "Comoros", "Saint Kitts and Nevis", "Korea (Democratic People's Republic of)", "Korea, Republic of", "Kuwait", "Cayman Islands", "Kazakhstan", "Lao People's Democratic Republic", "Lebanon", "Saint Lucia", "Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg", "Latvia", "Libya", "Morocco", "Monaco", "Moldova, Republic of", "Montenegro", "Saint Martin (French part)", "Madagascar", "Marshall Islands", "North Macedonia", "Mali", "Myanmar", "Mongolia", "Macao", "Northern Mariana Islands", "Martinique", "Mauritania", "Montserrat", "Malta", "Mauritius", "Maldives", "Malawi", "Mexico", "Malaysia", "Mozambique", "Namibia", "New Caledonia", "Niger", "Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway", "Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru", "French Polynesia", "Papua New Guinea", "Philippines", "Pakistan", "Poland", "Saint Pierre and Miquelon", "Pitcairn", "Puerto Rico", "Palestine, State of", "Portugal", "Palau", "Paraguay", "Qatar", "Réunion", "Romania", "Serbia", "Russian Federation", "Rwanda", "Saudi Arabia", "Solomon Islands", "Seychelles", "Sudan", "Sweden", "Singapore", "Saint Helena, Ascension and Tristan da Cunha", "Slovenia", "Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino", "Senegal", "Somalia", "Suriname", "South Sudan", "Sao Tome and Principe", "El Salvador", "Sint Maarten (Dutch part)", "Syrian Arab Republic", "Eswatini", "Turks and Caicos Islands", "Chad", "French Southern Territories", "Togo", "Thailand", "Tajikistan", "Tokelau", "Timor-Leste", "Turkmenistan", "Tunisia", "Tonga", "Turkey", "Trinidad and Tobago", "Tuvalu", "Taiwan, Province of China", "Tanzania, United Republic of", "Ukraine", "Uganda", "United States Minor Outlying Islands", "United States of America", "Uruguay", "Uzbekistan", "Holy See", "Saint Vincent and the Grenadines", "Venezuela (Bolivarian Republic of)", "Virgin Islands (British)", "Virgin Islands (U.S.)", "Viet Nam", "Vanuatu", "Wallis and Futuna", "Samoa", "Yemen", "Mayotte", "South Africa", "Zambia", "Zimbabwe"}, + "country_abr": {"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/animals.go b/vendor/github.com/brianvoe/gofakeit/v7/data/animals.go new file mode 100644 index 0000000000..2e37937440 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/animals.go @@ -0,0 +1,12 @@ +package data + +// Animal consists of animal information +var Animal = map[string][]string{ + "petname": {"Alfalfa", "Archie", "Attila", "Baloo", "Bark Twain", "Barney", "Beans", "Bernadette", "Betty", "Binx", "Biscuit", "Bitsy", "Bob", "Bruiser", "Butterball", "Butters", "Chalupa", "Cheeseburger", "Chewbarka", "Chompers", "Cujo", "Demi", "Dobby", "Doc McDoggins", "Droolius Caesar", "Elmo", "Fergus", "Fluffernutter", "Franz Fur-dinand", "Frodo", "Fyodor Dogstoevsky", "Gary", "Gollum", "Hairy Paw-ter", "Hercules", "Hobbit", "Jabba", "Jellybean", "Jimmy Chew", "Kareem Abdul Ja-Bark", "Kevin", "Khaleesi", "Larry", "Lloyd", "Mary Puppins", "Matilda", "Meatball", "Mister Miyagi", "Moose", "Munchkin", "Nacho", "Noodles", "Nugget", "Olga", "Orville Redenbarker", "Ozzy Pawsborne", "Pam", "Peanut", "Pee Wee", "Pikachu", "Prince of Barkness", "Pumba", "Rambo", "Rex", "Rocky", "Rufus", "Salsa", "Salvador Dogi", "Santa Paws", "Sarah Jessica Barker", "Scrappy", "Sherlock Bones", "Squeakers", "Squirt", "Tank", "Tater", "The Notorious D.O.G.", "Toto", "Twinkie", "Waffles", "Waldo", "Winnie the Poodle", "Woofgang Puck", "Yoda", "Zeus"}, + "animal": {"alligator", "alpaca", "ant", "antelope", "ape", "armadillo", "baboon", "badger", "bat", "bear", "beaver", "bee", "beetle", "buffalo", "butterfly", "camel", "caribou", "cat", "cattle", "cheetah", "chimpanzee", "chinchilla", "cicada", "clam", "cockroach", "cod", "coyote", "crab", "cricket", "crocodile", "crow", "deer", "dinosaur", "dog", "dolphin", "donkey", "duck", "eagle", "eel", "elephant", "elk", "ferret", "fish", "fly", "fox", "frog", "gerbil", "giraffe", "gnat", "gnu", "goat", "goldfish", "goose", "gorilla", "grasshopper", "guinea pig", "hamster", "hare", "hedgehog", "herring", "hippopotamus", "hornet", "horse", "hound", "hyena", "impala", "jackal", "jellyfish", "kangaroo", "koala", "leopard", "lion", "lizard", "llama", "locust", "louse", "macaw", "mallard", "mammoth", "manatee", "marten", "mink", "minnow", "mole", "monkey", "moose", "mosquito", "mouse", "mule", "muskrat", "otter", "ox", "oyster", "panda", "pig", "platypus", "porcupine", "porpoise", "prairie dog", "pug", "rabbit", "raccoon", "rat", "raven", "reindeer", "rhinoceros", "salmon", "sardine", "scorpion", "sea lion", "seal", "serval", "shark", "sheep", "skunk", "snail", "snake", "spider", "squirrel", "swan", "termite", "tiger", "toad", "tortoise", "trout", "turtle", "wallaby", "walrus", "wasp", "water buffalo", "weasel", "whale", "wildebeest", "wolf", "wombat", "woodchuck", "worm", "yak", "yellowjacket", "zebra"}, + "type": {"amphibians", "birds", "fish", "invertebrates", "mammals", "reptiles"}, + "farm": {"Chicken", "Cow", "Donkey", "Duck", "Goat", "Goose", "Horse", "Llama", "Pig", "Sheep", "Turkey"}, + "cat": {"Abyssinian", "Aegean", "American Bobtail", "American Curl", "American Shorthair", "American Wirehair", "Arabian Mau", "Asian", "Asian Semi-longhair", "Australian Mist", "Balinese", "Bambino", "Bengal", "Birman", "Bombay", "Brazilian Shorthair", "British Longhair", "British Semipi-longhair", "British Shorthair", "Burmese", "Burmilla", "California Spangled", "Chantilly-Tiffany", "Chartreux", "Chausie", "Cheetoh", "Colorpoint Shorthair", "Cornish Rex", "Cymric, or Manx Longhair", "Cyprus", "Devon Rex", "Donskoy, or Don Sphynx", "Dragon Li", "Dwarf cat, or Dwelf", "Egyptian Mau", "European Shorthair", "Exotic Shorthair", "Foldex Cat", "German Rex", "Havana Brown", "Highlander", "Himalayan, or Colorpoint Persian", "Japanese Bobtail", "Javanese", "Khao Manee", "Korat", "Korean Bobtail", "Korn Ja", "Kurilian Bobtail", "Kurilian Bobtail, or Kuril Islands Bobtail", "LaPerm", "Lykoi", "Maine Coon", "Manx", "Mekong Bobtail", "Minskin", "Munchkin", "Napoleon", "Nebelung", "Norwegian Forest Cat", "Ocicat", "Ojos Azules", "Oregon Rex", "Oriental Bicolor", "Oriental Longhair", "Oriental Shorthair", "Persian", "Peterbald", "Pixie-bob", "Raas", "Ragamuffin", "Ragdoll", "Russian Blue", "Russian White, Black and Tabby", "Sam Sawet", "Savannah", "Scottish Fold", "Selkirk Rex", "Serengeti", "Serrade petit", "Siamese", "Siberian", "Singapura", "Snowshoe", "Sokoke", "Somali", "Sphynx", "Suphalak", "Thai", "Tonkinese", "Toyger", "Turkish Angora", "Turkish Van", "Ukrainian Levkoy"}, + "dog": {"Affenpinscher", "African", "Airedale", "Akita", "Appenzeller", "Basenji", "Beagle", "Bluetick", "Borzoi", "Bouvier", "Boxer", "Brabancon", "Briard", "Boston Bulldog", "French Bulldog", "Staffordshire Bullterrier", "Cairn", "Chihuahua", "Chow", "Clumber", "Border Collie", "Coonhound", "Cardigan Corgi", "Dachshund", "Great Dane", "Scottish Deerhound", "Dhole", "Dingo", "Doberman", "Norwegian Elkhound", "Entlebucher", "Eskimo", "Germanshepherd", "Italian Greyhound", "Groenendael", "Ibizan Hound", "Afghan Hound", "Basset Hound", "Blood Hound", "English Hound", "Walker Hound", "Husky", "Keeshond", "Kelpie", "Komondor", "Kuvasz", "Labrador", "Leonberg", "Lhasa", "Malamute", "Malinois", "Maltese", "Bull Mastiff", "Tibetan Mastiff", "Mexicanhairless", "Bernese Mountain", "Swiss Mountain", "Newfoundland", "Otterhound", "Papillon", "Pekinese", "Pembroke", "Miniature Pinscher", "German Pointer", "Pomeranian", "Miniature Poodle", "Standard Poodle", "Toy Poodle", "Pug", "Pyrenees", "Redbone", "Chesapeake Retriever", "Curly Retriever", "Flatcoated Retriever", "Golden Retriever", "Rhodesian Ridgeback", "Rottweiler", "Saluki", "Samoyed", "Schipperke", "Giant Schnauzer", "Miniature Schnauzer", "English Setter", "Gordon Setter", "Irish Setter", "English Sheepdog", "Shetland Sheepdog", "Shiba", "Shihtzu", "Blenheim Spaniel", "Brittany Spaniel", "Cocker Spaniel", "Irish Spaniel", "Japanese Spaniel", "Sussex Spaniel", "Welsh Spaniel", "English Springer", "Stbernard", "American Terrier", "Australian Terrier", "Bedlington Terrier", "Border Terrier", "Dandie Terrier", "Fox Terrier", "Irish Terrier", "Kerryblue Terrier", "Lakeland Terrier", "Norfolk Terrier", "Norwich Terrier", "Patterdale Terrier", "Rat Terrier", "Scottish Terrier", "Sealyham Terrier", "Silky Terrier", "Tibetan Terrier", "Toy Terrier", "Westhighland Terrier", "Wheaten Terrier", "Yorkshire Terrier", "Vizsla", "Weimaraner", "Whippet", "Irish Wolfhound"}, + "bird": {"albatross", "bluejay", "canary", "cardinal", "chicken", "crow", "dove", "duck", "eagle", "emu", "falcon", "flamingo", "goose", "hornbill", "hummingbird", "ibis", "jay", "kingfisher", "lovebird", "mynah", "nightingale", "oriole", "ostrich", "owl", "parrot", "peacock", "penguin", "quail", "rooster", "sparrow", "swan", "thrush", "toucan", "vulture", "woodpecker", "yellow warbler"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/beer.go b/vendor/github.com/brianvoe/gofakeit/v7/data/beer.go new file mode 100644 index 0000000000..1192907d5f --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/beer.go @@ -0,0 +1,10 @@ +package data + +// Beer consists of various beer information +var Beer = map[string][]string{ + "name": {"Pliny The Elder", "Founders Kentucky Breakfast", "Trappistes Rochefort 10", "HopSlam Ale", "Stone Imperial Russian Stout", "St. Bernardus Abt 12", "Founders Breakfast Stout", "Weihenstephaner Hefeweissbier", "Péché Mortel", "Celebrator Doppelbock", "Duvel", "Dreadnaught IPA", "Nugget Nectar", "La Fin Du Monde", "Bourbon County Stout", "Old Rasputin Russian Imperial Stout", "Two Hearted Ale", "Ruination IPA", "Schneider Aventinus", "Double Bastard Ale", "90 Minute IPA", "Hop Rod Rye", "Trappistes Rochefort 8", "Chimay Grande Réserve", "Stone IPA", "Arrogant Bastard Ale", "Edmund Fitzgerald Porter", "Chocolate St", "Oak Aged Yeti Imperial Stout", "Ten FIDY", "Storm King Stout", "Shakespeare Oatmeal", "Alpha King Pale Ale", "Westmalle Trappist Tripel", "Samuel Smith’s Imperial IPA", "Yeti Imperial Stout", "Hennepin", "Samuel Smith’s Oatmeal Stout", "Brooklyn Black", "Oaked Arrogant Bastard Ale", "Sublimely Self-Righteous Ale", "Trois Pistoles", "Bell’s Expedition", "Sierra Nevada Celebration Ale", "Sierra Nevada Bigfoot Barleywine Style Ale", "Racer 5 India Pale Ale, Bear Republic Bre", "Orval Trappist Ale", "Hercules Double IPA", "Maharaj", "Maudite"}, + "hop": {"Ahtanum", "Amarillo", "Bitter Gold", "Bravo", "Brewer’s Gold", "Bullion", "Cascade", "Cashmere", "Centennial", "Chelan", "Chinook", "Citra", "Cluster", "Columbia", "Columbus", "Comet", "Crystal", "Equinox", "Eroica", "Fuggle", "Galena", "Glacier", "Golding", "Hallertau", "Horizon", "Liberty", "Magnum", "Millennium", "Mosaic", "Mt. Hood", "Mt. Rainier", "Newport", "Northern Brewer", "Nugget", "Olympic", "Palisade", "Perle", "Saaz", "Santiam", "Simcoe", "Sorachi Ace", "Sterling", "Summit", "Tahoma", "Tettnang", "TriplePearl", "Ultra", "Vanguard", "Warrior", "Willamette", "Yakima Gol"}, + "yeast": {"1007 - German Ale", "1010 - American Wheat", "1028 - London Ale", "1056 - American Ale", "1084 - Irish Ale", "1098 - British Ale", "1099 - Whitbread Ale", "1187 - Ringwood Ale", "1272 - American Ale II", "1275 - Thames Valley Ale", "1318 - London Ale III", "1332 - Northwest Ale", "1335 - British Ale II", "1450 - Dennys Favorite 50", "1469 - West Yorkshire Ale", "1728 - Scottish Ale", "1968 - London ESB Ale", "2565 - Kölsch", "1214 - Belgian Abbey", "1388 - Belgian Strong Ale", "1762 - Belgian Abbey II", "3056 - Bavarian Wheat Blend", "3068 - Weihenstephan Weizen", "3278 - Belgian Lambic Blend", "3333 - German Wheat", "3463 - Forbidden Fruit", "3522 - Belgian Ardennes", "3638 - Bavarian Wheat", "3711 - French Saison", "3724 - Belgian Saison", "3763 - Roeselare Ale Blend", "3787 - Trappist High Gravity", "3942 - Belgian Wheat", "3944 - Belgian Witbier", "2000 - Budvar Lager", "2001 - Urquell Lager", "2007 - Pilsen Lager", "2035 - American Lager", "2042 - Danish Lager", "2112 - California Lager", "2124 - Bohemian Lager", "2206 - Bavarian Lager", "2278 - Czech Pils", "2308 - Munich Lager", "2633 - Octoberfest Lager Blend", "5112 - Brettanomyces bruxellensis", "5335 - Lactobacillus", "5526 - Brettanomyces lambicus", "5733 - Pediococcus"}, + "malt": {"Black malt", "Caramel", "Carapils", "Chocolate", "Munich", "Caramel", "Carapils", "Chocolate malt", "Munich", "Pale", "Roasted barley", "Rye malt", "Special roast", "Victory", "Vienna", "Wheat mal"}, + "style": {"Light Lager", "Pilsner", "European Amber Lager", "Dark Lager", "Bock", "Light Hybrid Beer", "Amber Hybrid Beer", "English Pale Ale", "Scottish And Irish Ale", "Merican Ale", "English Brown Ale", "Porter", "Stout", "India Pale Ale", "German Wheat And Rye Beer", "Belgian And French Ale", "Sour Ale", "Belgian Strong Ale", "Strong Ale", "Fruit Beer", "Vegetable Beer", "Smoke-flavored", "Wood-aged Beer"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/book.go b/vendor/github.com/brianvoe/gofakeit/v7/data/book.go new file mode 100644 index 0000000000..ec3e5d849b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/book.go @@ -0,0 +1,101 @@ +package data + +var Books = map[string][]string{ + "title": { + "Anna Karenina", + "Beloved", + "Blindness", + "Bostan", + "Buddenbrooks", + "Crime and Punishment", + "Don Quijote De La Mancha", + "Fairy tales", + "Faust", + "Gulliver's Travels", + "Gypsy Ballads", + "Hamlet", + "Harry potter and the sorcerer's stone", + "King Lear", + "Leaves of Grass", + "Lolita", + "Madame Bovary", + "Memoirs of Hadrian", + "Metamorphoses", + "Moby Dick", + "Nineteen Eighty-Four", + "Odyssey", + "Oedipus the King", + "One Hundred Years of Solitude", + "One Thousand and One Nights", + "Othello", + "Pippi Longstocking", + "Pride and Prejudice", + "Romeo & Juliet", + "Sherlock Holmes", + "Sons and Lovers", + "The Adventures of Huckleberry Finn", + "The Book Of Job", + "The Brothers Karamazov", + "The Golden Notebook", + "The Idiot", + "The Old Man and the Sea", + "The Stranger", + "Things Fall Apart", + "Ulysses", + "War and Peace", + "Wuthering Heights", + "Zorba the Greek", + }, + "author": { + "Albert Camus", + "Astrid Lindgren", + "Charles Dickens", + "D. H. Lawrence", + "Edgar Allan Poe", + "Emily Brontë", + "Ernest Hemingway", + "Franz Kafka", + "Fyodor Dostoevsky", + "George Orwell", + "Hans Christian Andersen", + "Homer", + "James Joyce", + "Jane Austen", + "Johann Wolfgang von Goethe", + "Jorge Luis Borges", + "Joanne K. Rowling", + "Leo Tolstoy", + "Marcel Proust", + "Mark Twain", + "Paul Celan", + "Salman Rushdie", + "Sophocles", + "Thomas Mann", + "Toni Morrison", + "Vladimir Nabokov", + "William Faulkner", + "William Shakespeare", + "Yasunari Kawabata", + }, + "genre": { + "Adventure", + "Comic", + "Crime", + "Erotic", + "Fiction", + "Fantasy", + "Historical", + "Horror", + "Magic", + "Mystery", + "Philosophical", + "Political", + "Romance", + "Saga", + "Satire", + "Science", + "Speculative", + "Thriller", + "Urban", + }, +} \ No newline at end of file diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/car.go b/vendor/github.com/brianvoe/gofakeit/v7/data/car.go new file mode 100644 index 0000000000..8754b1220e --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/car.go @@ -0,0 +1,10 @@ +package data + +// Car Beer consists of various beer information +var Car = map[string][]string{ + "type": {"Passenger car mini", "Passenger car light", "Passenger car compact", "Passenger car medium", "Passenger car heavy", "Sport utility vehicle", "Pickup truck", "Van"}, + "fuel_type": {"Gasoline", "Methanol", "Ethanol", "Diesel", "LPG", "CNG", "Electric"}, + "transmission_type": {"Manual", "Automatic"}, + "maker": {"Alfa Romeo", "Aston Martin", "Audi", "Bentley", "Benz", "BMW", "Bugatti", "Cadillac", "Chevrolet", "Chrysler", "Citroen", "Corvette", "DAF", "Dacia", "Daewoo", "Daihatsu", "Datsun", "De Lorean", "Dino", "Dodge", "Farboud", "Ferrari", "Fiat", "Ford", "Honda", "Hummer", "Hyundai", "Jaguar", "Jeep", "KIA", "Koenigsegg", "Lada", "Lamborghini", "Lancia", "Land Rover", "Lexus", "Ligier", "Lincoln", "Lotus", "Martini", "Maserati", "Maybach", "Mazda", "McLaren", "Mercedes", "Mercedes-Benz", "Mini", "Mitsubishi", "Nissan", "Noble", "Opel", "Peugeot", "Pontiac", "Porsche", "Renault", "Rolls-Royce", "Rover", "Saab", "Seat", "Skoda", "Smart", "Spyker", "Subaru", "Suzuki", "Toyota", "Tesla", "Vauxhall", "Volkswagen", "Volvo"}, + "model": {"Db9 Coupe", "Db9 Coupe Manual", "Db9 Volante", "V12 Vanquish S", "V8 Vantage", "A3", "A4", "A4 Avant Quattro", "A4 Cabriolet", "A4 Cabriolet Quattro", "A4 Quattro", "A6", "A6 Avant Quattro", "A6 Quattro", "A8 L", "Gti", "Passat", "S4", "S4 Avant", "S4 Cabriolet", "Tt Coupe", "Tt Roadster", "Bentley Arnage", "Continental Flying Spur", "Continental Gt", "325ci Convertible", "325i", "325xi", "325xi Sport Wagon", "330ci Convertible", "330i", "330xi", "525i", "525xi", "530i", "530xi", "530xi Sport Wagon", "550i", "650ci", "650ci Convertible", "750li", "760li", "M3", "M3 Convertible", "M5", "M6", "Mini Cooper", "Mini Cooper Convertible", "Mini Cooper S", "Mini Cooper S Convertible", "X3", "X5", "X5 4.8is", "Z4 3.0 Si Coupe", "Z4 3.0i", "Z4 3.0si", "Z4 M Roadster", "Veyron", "300c/srt-8", "Caravan 2wd", "Charger", "Commander 4wd", "Crossfire Roadster", "Dakota Pickup 2wd", "Dakota Pickup 4wd", "Durango 2wd", "Durango 4wd", "Grand Cherokee 2wd", "Grand Cherokee 4wd", "Liberty/cherokee 2wd", "Liberty/cherokee 4wd", "Pacifica 2wd", "Pacifica Awd", "Pt Cruiser", "Ram 1500 Pickup 2wd", "Ram 1500 Pickup 4wd", "Sebring 4-dr", "Stratus 4-dr", "Town & Country 2wd", "Viper Convertible", "Wrangler/tj 4wd", "F430", "Ferrari 612 Scaglietti", "Ferrari F141", "B4000 4wd", "Crown Victoria Police", "E150 Club Wagon", "E150 Econoline 2wd", "Escape 4wd", "Escape Fwd", "Escape Hybrid 4wd", "Escape Hybrid Fwd", "Expedition 2wd", "Explorer 2wd", "Explorer 4wd", "F150 Ffv 2wd", "F150 Ffv 4wd", "F150 Pickup 2wd", "F150 Pickup 4wd", "Five Hundred Awd", "Focus Fwd", "Focus Station Wag", "Freestar Wagon Fwd", "Freestyle Awd", "Freestyle Fwd", "Grand Marquis", "Gt 2wd", "Ls", "Mark Lt", "Milan", "Monterey Wagon Fwd", "Mountaineer 4wd", "Mustang", "Navigator 2wd", "Ranger Pickup 2wd", "Ranger Pickup 4wd", "Taurus", "Taurus Ethanol Ffv", "Thunderbird", "Town Car", "Zephyr", "B9 Tribeca Awd", "Baja Awd", "Forester Awd", "Impreza Awd", "Impreza Wgn/outback Spt Awd", "Legacy Awd", "Legacy Wagon Awd", "Outback Awd", "Outback Wagon Awd", "9-3 Convertible", "9-3 Sport Sedan", "9-5 Sedan", "C15 Silverado Hybrid 2wd", "C1500 Silverado 2wd", "C1500 Suburban 2wd", "C1500 Tahoe 2wd", "C1500 Yukon 2wd", "Cobalt", "Colorado 2wd", "Colorado 4wd", "Colorado Cab Chassis Inc 2wd", "Colorado Crew Cab 2wd", "Colorado Crew Cab 4wd", "Corvette", "Cts", "Dts", "Envoy 2wd", "Envoy Xl 4wd", "Equinox Awd", "Equinox Fwd", "Escalade 2wd", "Escalade Esv Awd", "G15/25chev Van 2wd Conv", "G1500/2500 Chevy Express 2wd", "G1500/2500 Chevy Van 2wd", "G6", "G6 Gt/gtp Convertible", "Grand Prix", "Gto", "H3 4wd", "Hhr Fwd", "I-280 2wd Ext Cab", "Impala", "K15 Silverado Hybrid 4wd", "K1500 Avalanche 4wd", "K1500 Silverado 4wd", "K1500 Tahoe 4wd", "Lacrosse/allure", "Limousine", "Malibu", "Montana Sv6 Awd", "Monte Carlo", "Rendezvous Awd", "Rendezvous Fwd", "Solstice", "Srx 2wd", "Srx Awd", "Ssr Pickup 2wd", "Sts", "Sts Awd", "Terraza Fwd", "Trailblazer 2wd", "Trailblazer 4wd", "Trailblazer Awd", "Trailblazer Ext 4wd", "Uplander Fwd", "Vue Awd", "Vue Fwd", "Xlr", "Aveo", "Forenza", "Forenza Wagon", "Verona", "Accord", "Accord Hybrid", "Civic", "Civic Hybrid", "Cr-v 4wd", "Element 2wd", "Element 4wd", "Insight", "Mdx 4wd", "Odyssey 2wd", "Pilot 2wd", "Pilot 4wd", "Ridgeline 4wd", "Rl", "Rsx", "S2000", "Tl", "Tsx", "Accent", "Azera", "Elantra", "Santafe 2wd", "Santafe 4wd", "Sonata", "Tiburon", "Tucson 2wd", "Tucson 4wd", "S-type 3.0 Litre", "S-type 4.2 Litre", "S-type R", "Vdp Lwb", "Xj8", "Xk8 Convertible", "Xkr Convertible", "X-type", "X-type Sport Brake", "Amanti", "Optima", "Optima(ms)", "Rio", "Sedona", "Sorento 2wd", "Sorento 4wd", "Spectra(ld)", "Sportage 2wd", "Sportage 4wd", "L-140/715 Gallardo", "L-147/148 Murcielago", "Lr3", "Range Rover", "Range Rover Sport", "Elise/exige", "Coupe Cambiocorsa/gt/g-sport", "Quattroporte", "Mazda 3", "Mazda 5", "Mazda 6", "Mazda 6 Sport Wagon", "Mazda Rx-8", "Mpv", "Mx-5", "C230", "C280", "C280 4matic", "C350", "C350 4matic", "C55 Amg", "Cl65 Amg", "Clk350", "Clk350 (cabriolet)", "Clk55 Amg (cabriolet)", "Cls500", "Cls55 Amg", "E320 Cdi", "E350", "E350 (wagon)", "E350 4matic", "E350 4matic (wagon)", "E500", "E55 Amg", "E55 Amg (wagon)", "Maybach 57s", "Maybach 62", "Ml350", "Ml500", "R350", "R500", "S350", "S430", "Sl500", "Sl600", "Sl65 Amg", "Slk280", "Slk350", "Slr", "Eclipse", "Endeavor 2wd", "Endeavor 4wd", "Galant", "Lancer", "Lancer Evolution", "Lancer Sportback", "Montero", "Outlander 2wd", "Outlander 4wd", "Vibe", "350z", "350z Roadster", "Altima", "Armada 2wd", "Armada 4wd", "Frontier 2wd", "Frontier V6-2wd", "Frontier V6-4wd", "Fx35 Awd", "Fx35 Rwd", "Fx45 Awd", "G35", "M35", "M35x", "M45", "Maxima", "Murano Awd", "Murano Fwd", "Pathfinder 2wd", "Pathfinder 4wd", "Q45", "Q45 Sport", "Quest", "Qx56 4wd", "Sentra", "Titan 2wd", "Titan 4wd", "Xterra 2wd", "Xterra 4wd", "Boxster", "Boxster S", "Carrera 2 Coupe", "Cayenne", "Cayenne S", "Cayenne Turbo", "Cayman S", "Phantom", "F150 Supercrew 4wd", "C8 Spyder", "Aerio", "Aerio Sx", "Aerio Sx Awd", "Grand Vitara Xl-7", "Grand Vitara Xl-7 4wd", "Grand Vitara Xv6", "Grand Vitara Xv6 Awd", "4runner 2wd", "4runner 4wd", "Avalon", "Camry", "Camry Solara", "Camry Solara Convertible", "Corolla", "Corolla Matrix", "Es 330", "Gs 300 4wd", "Gs 300/gs 430", "Gx 470", "Highlander 2wd", "Highlander 4wd", "Highlander Hybrid 2wd", "Highlander Hybrid 4wd", "Is 250", "Is 250 Awd", "Is 350", "Ls 430", "Lx 470", "Prius", "Rav4 2wd", "Rav4 4wd", "Rx 330 2wd", "Rx 330 4wd", "Rx 400h 4wd", "Sc 430", "Scion Tc", "Scion Xa", "Scion Xb", "Sequoia 2wd", "Sequoia 4wd", "Sienna 2wd", "Sienna 4wd", "Toyota Tacoma 2wd", "Toyota Tacoma 4wd", "Toyota Tundra 2wd", "Toyota Tundra 4wd", "Yaris", "A3 Quattro", "Golf", "Jetta", "New Beetle", "New Beetle Convertible", "Passat Wagon 4motion", "Phaeton", "Rabbit", "Touareg", "Tt Coupe Quattro", "Tt Roadster Quattro", "C70 Convertible", "S40 Awd", "S40 Fwd", "S60 Awd", "S60 Fwd", "S60 R Awd", "S80 Fwd", "V50 Awd", "V70 Fwd", "V70 R Awd", "Xc 70 Awd", "Xc 90 Awd", "Xc 90 Fwd"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/celebrity.go b/vendor/github.com/brianvoe/gofakeit/v7/data/celebrity.go new file mode 100644 index 0000000000..ae4fcffd8d --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/celebrity.go @@ -0,0 +1,7 @@ +package data + +var Celebrity = map[string][]string{ + "actor": {"Arnold Schwarzenegger", "Jim Carrey", "Emma Watson", "Robert Downey Jr.", "Daniel Radcliffe", "Chris Evans", "Leonardo DiCaprio", "Tom Cruise", "Brad Pitt", "Charles Chaplin", "Morgan Freeman", "Tom Hanks", "Hugh Jackman", "Matt Damon", "Sylvester Stallone", "Will Smith", "Clint Eastwood", "Cameron Diaz", "George Clooney", "Steven Spielberg", "Harrison Ford", "Robert De Niro", "Al Pacino", "Robert Downey Jr.", "Russell Crowe", "Liam Neeson", "Kate Winslet", "Mark Wahlberg", "Natalie Portman", "Pierce Brosnan", "Sean Connery", "Orlando Bloom", "Dwayne Johnson", "Jackie Chan", "Angelina Jolie", "Adam Sandler", "Scarlett Johansson", "Heath Ledger", "Anne Hathaway", "Jessica Alba", "Edward Norton", "Keira Knightley", "Bradley Cooper", "Will Ferrell", "Julia Roberts", "Nicolas Cage", "Daniel Craig", "Keanu Reeves", "Ian McKellen", "Halle Berry", "Bruce Willis", "Ben Stiller", "Tommy Lee Jones", "Antonio Banderas", "Denzel Washington", "Steve Carell", "Shia LaBeouf", "Megan Fox", "James Franco", "Mel Gibson", "Vin Diesel", "Tim Allen", "Robin Williams", "Kevin Spacey", "Jason Biggs", "Seann William Scott", "Jean-Claude Van Damme", "Zach Galifianakis", "Owen Wilson", "Christian Bale", "Peter Jackson", "Sandra Bullock", "Bruce Lee", "Drew Barrymore", "Macaulay Culkin", "Jack Nicholson", "Bill Murray", "Sigourney Weaver", "Jake Gyllenhaal", "Jason Statham", "Jet Li", "Kate Beckinsale", "Rowan Atkinson", "Marlon Brando", "John Travolta", "Channing Tatum", "Ben Affleck", "Shah Rukh Khan", "Jennifer Aniston", "Emma Stone", "Chris Hemsworth", "James McAvoy", "James Cameron", "Amitabh Bachchan", "Brendan Fraser", "Rachel McAdams", "Tom Hiddleston", "Aamir Khan"}, + "business": {"Elon Musk", "Steve Jobs", "Jeff Bezos", "Bill Gates", "Mark Zuckerberg", "Sundar Pichai", "Walt Disney", "Warren Buffett", "Mukesh Ambani", "P. T. Barnum", "Colonel Sanders", "Ray Kroc", "Richard Branson", "Henry Ford", "Larry Page", "Steve Wozniak", "Ratan Tata", "John D. Rockefeller", "Madam C. J. Walker", "Tim Cook", "Andrew Carnegie", "Paul Allen", "Bobby Flay", "J. P. Morgan", "Satya Nadella", "Dhirubhai Ambani", "Carlos Slim", "Ross Perot", "Jamie Oliver", "Jack Ma", "Larry Ellison", "Sam Walton", "Sheryl Sandberg", "Marco Pierre White", "Indra Nooyi", "David Rockefeller", "Steve Ballmer", "Beyonce Knowles", "N. R. Narayana Murthy", "Mark Wahlberg", "Cameron Diaz", "Sergey Brin", "Howard Hughes", "Jessica Alba", "Dustin Moskovitz", "Eva Mendes", "Amancio Ortega Gaona", "Fred Trump", "Jamsetji Tata", "Kate Hudson", "Martha Stewart", "Peter Jones", "Marco Polo", "Susan Wojcicki", "Oskar Schindler", "Elizabeth Hurley", "Sean Combs", "Kate Spade", "Vincent McMahon", "David Chang", "Coco Chanel", "Vera Wang", "Arianna Huffington", "John McAfee", "Dany Garcia", "Richard Attenborough", "Donatella Versace", "Chris Hughes", "Alexis Ohanian", "J. Paul Getty", "Sharon Osbourne", "Bob Iger", "Kate Walsh", "Chris Gardner", "Jessica Simpson", "Guy Fieri", "Joy Mangano", "Wolfgang Puck", "Christie Brinkley", "Tom Steyer", "Evan Spiegel", "Hugh Hefner", "Preity Zinta", "Shane McMahon", "Salt Bae", "Mario Batali", "Bernard Arnault", "Michael Bloomberg", "Portia de Rossi", "Kevin O'Leary", "Roman Abramovich", "Jamie Dimon", "Rob Dyrdek", "Emeril Lagasse", "Kat Von D", "Karlie Kloss", "Antoni Porowski", "Edmond James de Rothschild", "Mitt Romney", "Aristotle Onassis", "Richard Benjamin Harrison", "Ben Bernanke", "Mark Cuban", "William Randolph Hearst", "Nate Robinson", "Alan Shepard", "Christina Anstead", "Laurene Powell Jobs", "Adam Weitsman", "Gladys Knight", "Gary Vaynerchuk", "Robert Kraft", "John Paul DeJoria", "Lori Greiner", "Carly Fiorina", "Lakshmi Mittal", "Jerry Jones", "Meg Whitman", "Azim Premji", "Lisa Vanderpump", "Dana White", "Russell Simmons", "Jennifer Flavin", "Harry Hamlin", "Conrad Hilton", "Prescott Bush", "Alvaro Morte", "Shigeru Miyamoto", "Phil Knight", "Jack Dorsey", "Barbara Bush", "Lee Iacocca", "Ma Huateng", "Rick Harrison", "Drew Scott", "Jawed Karim", "Daymond John", "Jaclyn Smith", "Maryse Ouellet", "Allegra Versace"}, + "sport": {"Pele", "Usain Bolt", "Muhammad Ali", "Carl Lewis", "Jesse Owens", "Sir Donald Bradman", "Billie Jean King", "Eddy Merckx", "Jackie Joyner-Kersee", "Lionel Messi", "Babe Didrikson Zaharias", "Michael Jordan", "Larisa Latynina", "Diego Maradona", "Serena Williams", "Babe Ruth", "Roger Federer", "Martina Navratilova", "Michael Phelps", "Lottie Dod", "Sachin Tendulkar", "Johan Cruyff", "Tiger Woods", "Sonja Henie", "Aryton Senna", "Nadia Comaneci", "Sergei Bubka", "Emil Zatopek", "Manny Pacquiao", "Imran Khan", "Jackie Robinson", "Shane Warne", "Dhyan Chand", "Fred Perry", "Lin Dan", "Abebe Bikila", "Clara Hughes", "Jan-Ove Waldner", "Bobby Moore", "Bjorn Borg", "Karch Kiraly", "Bradley Wiggins", "Seve Ballesteros", "David Beckham", "Michael Schumacher", "Greg Lemond", "Mia Hamm", "Jacques Anquetil", "Jack Nicklaus", "Steve Davis", "John McEnroe", "Monica Seles", "Magic Johnson", "Joe DiMaggio", "Roger Bannister", "Mo Farah", "Mark Spitz", "Chris Evert", "Al Oerter", "Jimmy Connors", "Michael Johnson", "Ian Botham", "Jim Thorpe", "Sir Steve Redgrave", "Steffi Graf", "Sebastian Coe", "Hicham El Guerrouj", "Eric Liddell", "W.G Grace", "Kenenisa Bekele", "Bernard Hinault", "Bob Beamon", "Paavo Nurmi", "David Campese", "Kelly Slater", "Haile Gebreselassie", "Rafael Nadal", "Brian Lara", "Chris Hoy", "Serge Blanco", "Cristiano Ronaldo", "Sir Gary Sobers", "Andy Murray", "George Best", "Sir Viv Richards", "Fausto Coppi", "Eusebio", "Rod Laver", "Grete Waitz", "Margaret Smith Court", "Tegla Laroupe", "Fanny Blankers-Koen", "Asbel Kiprop", "Lewis Hamilton", "C.B.Fry", "Annika Sörenstam", "Wilma Rudolph", "Alberta Tomba", "Bo Jackson"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/colors.go b/vendor/github.com/brianvoe/gofakeit/v7/data/colors.go new file mode 100644 index 0000000000..96761aad29 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/colors.go @@ -0,0 +1,110 @@ +package data + +// Colors consists of color information +var Colors = map[string][]string{ + "safe": {"black", "maroon", "green", "navy", "olive", "purple", "teal", "lime", "blue", "silver", "gray", "yellow", "fuchsia", "aqua", "white"}, + "full": {"AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "Darkorange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray", "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen"}, +} + +var ColorsNice = [][]string{ + {"#69d2e7", "#a7dbd8", "#e0e4cc", "#f38630", "#fa6900"}, + {"#fe4365", "#fc9d9a", "#f9cdad", "#c8c8a9", "#83af9b"}, + {"#ecd078", "#d95b43", "#c02942", "#542437", "#53777a"}, + {"#556270", "#4ecdc4", "#c7f464", "#ff6b6b", "#c44d58"}, + {"#774f38", "#e08e79", "#f1d4af", "#ece5ce", "#c5e0dc"}, + {"#e8ddcb", "#cdb380", "#036564", "#033649", "#031634"}, + {"#490a3d", "#bd1550", "#e97f02", "#f8ca00", "#8a9b0f"}, + {"#594f4f", "#547980", "#45ada8", "#9de0ad", "#e5fcc2"}, + {"#00a0b0", "#6a4a3c", "#cc333f", "#eb6841", "#edc951"}, + {"#e94e77", "#d68189", "#c6a49a", "#c6e5d9", "#f4ead5"}, + {"#3fb8af", "#7fc7af", "#dad8a7", "#ff9e9d", "#ff3d7f"}, + {"#d9ceb2", "#948c75", "#d5ded9", "#7a6a53", "#99b2b7"}, + {"#ffffff", "#cbe86b", "#f2e9e1", "#1c140d", "#cbe86b"}, + {"#efffcd", "#dce9be", "#555152", "#2e2633", "#99173c"}, + {"#343838", "#005f6b", "#008c9e", "#00b4cc", "#00dffc"}, + {"#413e4a", "#73626e", "#b38184", "#f0b49e", "#f7e4be"}, + {"#ff4e50", "#fc913a", "#f9d423", "#ede574", "#e1f5c4"}, + {"#99b898", "#fecea8", "#ff847c", "#e84a5f", "#2a363b"}, + {"#655643", "#80bca3", "#f6f7bd", "#e6ac27", "#bf4d28"}, + {"#00a8c6", "#40c0cb", "#f9f2e7", "#aee239", "#8fbe00"}, + {"#351330", "#424254", "#64908a", "#e8caa4", "#cc2a41"}, + {"#554236", "#f77825", "#d3ce3d", "#f1efa5", "#60b99a"}, + {"#5d4157", "#838689", "#a8caba", "#cad7b2", "#ebe3aa"}, + {"#8c2318", "#5e8c6a", "#88a65e", "#bfb35a", "#f2c45a"}, + {"#fad089", "#ff9c5b", "#f5634a", "#ed303c", "#3b8183"}, + {"#ff4242", "#f4fad2", "#d4ee5e", "#e1edb9", "#f0f2eb"}, + {"#f8b195", "#f67280", "#c06c84", "#6c5b7b", "#355c7d"}, + {"#d1e751", "#ffffff", "#000000", "#4dbce9", "#26ade4"}, + {"#1b676b", "#519548", "#88c425", "#bef202", "#eafde6"}, + {"#5e412f", "#fcebb6", "#78c0a8", "#f07818", "#f0a830"}, + {"#bcbdac", "#cfbe27", "#f27435", "#f02475", "#3b2d38"}, + {"#452632", "#91204d", "#e4844a", "#e8bf56", "#e2f7ce"}, + {"#eee6ab", "#c5bc8e", "#696758", "#45484b", "#36393b"}, + {"#f0d8a8", "#3d1c00", "#86b8b1", "#f2d694", "#fa2a00"}, + {"#2a044a", "#0b2e59", "#0d6759", "#7ab317", "#a0c55f"}, + {"#f04155", "#ff823a", "#f2f26f", "#fff7bd", "#95cfb7"}, + {"#b9d7d9", "#668284", "#2a2829", "#493736", "#7b3b3b"}, + {"#bbbb88", "#ccc68d", "#eedd99", "#eec290", "#eeaa88"}, + {"#b3cc57", "#ecf081", "#ffbe40", "#ef746f", "#ab3e5b"}, + {"#a3a948", "#edb92e", "#f85931", "#ce1836", "#009989"}, + {"#300030", "#480048", "#601848", "#c04848", "#f07241"}, + {"#67917a", "#170409", "#b8af03", "#ccbf82", "#e33258"}, + {"#aab3ab", "#c4cbb7", "#ebefc9", "#eee0b7", "#e8caaf"}, + {"#e8d5b7", "#0e2430", "#fc3a51", "#f5b349", "#e8d5b9"}, + {"#ab526b", "#bca297", "#c5ceae", "#f0e2a4", "#f4ebc3"}, + {"#607848", "#789048", "#c0d860", "#f0f0d8", "#604848"}, + {"#b6d8c0", "#c8d9bf", "#dadabd", "#ecdbbc", "#fedcba"}, + {"#a8e6ce", "#dcedc2", "#ffd3b5", "#ffaaa6", "#ff8c94"}, + {"#3e4147", "#fffedf", "#dfba69", "#5a2e2e", "#2a2c31"}, + {"#fc354c", "#29221f", "#13747d", "#0abfbc", "#fcf7c5"}, + {"#cc0c39", "#e6781e", "#c8cf02", "#f8fcc1", "#1693a7"}, + {"#1c2130", "#028f76", "#b3e099", "#ffeaad", "#d14334"}, + {"#a7c5bd", "#e5ddcb", "#eb7b59", "#cf4647", "#524656"}, + {"#dad6ca", "#1bb0ce", "#4f8699", "#6a5e72", "#563444"}, + {"#5c323e", "#a82743", "#e15e32", "#c0d23e", "#e5f04c"}, + {"#edebe6", "#d6e1c7", "#94c7b6", "#403b33", "#d3643b"}, + {"#fdf1cc", "#c6d6b8", "#987f69", "#e3ad40", "#fcd036"}, + {"#230f2b", "#f21d41", "#ebebbc", "#bce3c5", "#82b3ae"}, + {"#b9d3b0", "#81bda4", "#b28774", "#f88f79", "#f6aa93"}, + {"#3a111c", "#574951", "#83988e", "#bcdea5", "#e6f9bc"}, + {"#5e3929", "#cd8c52", "#b7d1a3", "#dee8be", "#fcf7d3"}, + {"#1c0113", "#6b0103", "#a30006", "#c21a01", "#f03c02"}, + {"#000000", "#9f111b", "#b11623", "#292c37", "#cccccc"}, + {"#382f32", "#ffeaf2", "#fcd9e5", "#fbc5d8", "#f1396d"}, + {"#e3dfba", "#c8d6bf", "#93ccc6", "#6cbdb5", "#1a1f1e"}, + {"#f6f6f6", "#e8e8e8", "#333333", "#990100", "#b90504"}, + {"#1b325f", "#9cc4e4", "#e9f2f9", "#3a89c9", "#f26c4f"}, + {"#a1dbb2", "#fee5ad", "#faca66", "#f7a541", "#f45d4c"}, + {"#c1b398", "#605951", "#fbeec2", "#61a6ab", "#accec0"}, + {"#5e9fa3", "#dcd1b4", "#fab87f", "#f87e7b", "#b05574"}, + {"#951f2b", "#f5f4d7", "#e0dfb1", "#a5a36c", "#535233"}, + {"#8dccad", "#988864", "#fea6a2", "#f9d6ac", "#ffe9af"}, + {"#2d2d29", "#215a6d", "#3ca2a2", "#92c7a3", "#dfece6"}, + {"#413d3d", "#040004", "#c8ff00", "#fa023c", "#4b000f"}, + {"#eff3cd", "#b2d5ba", "#61ada0", "#248f8d", "#605063"}, + {"#ffefd3", "#fffee4", "#d0ecea", "#9fd6d2", "#8b7a5e"}, + {"#cfffdd", "#b4dec1", "#5c5863", "#a85163", "#ff1f4c"}, + {"#9dc9ac", "#fffec7", "#f56218", "#ff9d2e", "#919167"}, + {"#4e395d", "#827085", "#8ebe94", "#ccfc8e", "#dc5b3e"}, + {"#a8a7a7", "#cc527a", "#e8175d", "#474747", "#363636"}, + {"#f8edd1", "#d88a8a", "#474843", "#9d9d93", "#c5cfc6"}, + {"#046d8b", "#309292", "#2fb8ac", "#93a42a", "#ecbe13"}, + {"#f38a8a", "#55443d", "#a0cab5", "#cde9ca", "#f1edd0"}, + {"#a70267", "#f10c49", "#fb6b41", "#f6d86b", "#339194"}, + {"#ff003c", "#ff8a00", "#fabe28", "#88c100", "#00c176"}, + {"#ffedbf", "#f7803c", "#f54828", "#2e0d23", "#f8e4c1"}, + {"#4e4d4a", "#353432", "#94ba65", "#2790b0", "#2b4e72"}, + {"#0ca5b0", "#4e3f30", "#fefeeb", "#f8f4e4", "#a5b3aa"}, + {"#4d3b3b", "#de6262", "#ffb88c", "#ffd0b3", "#f5e0d3"}, + {"#fffbb7", "#a6f6af", "#66b6ab", "#5b7c8d", "#4f2958"}, + {"#edf6ee", "#d1c089", "#b3204d", "#412e28", "#151101"}, + {"#9d7e79", "#ccac95", "#9a947c", "#748b83", "#5b756c"}, + {"#fcfef5", "#e9ffe1", "#cdcfb7", "#d6e6c3", "#fafbe3"}, + {"#9cddc8", "#bfd8ad", "#ddd9ab", "#f7af63", "#633d2e"}, + {"#30261c", "#403831", "#36544f", "#1f5f61", "#0b8185"}, + {"#aaff00", "#ffaa00", "#ff00aa", "#aa00ff", "#00aaff"}, + {"#d1313d", "#e5625c", "#f9bf76", "#8eb2c5", "#615375"}, + {"#ffe181", "#eee9e5", "#fad3b2", "#ffba7f", "#ff9c97"}, + {"#73c8a9", "#dee1b6", "#e1b866", "#bd5532", "#373b44"}, + {"#805841", "#dcf7f3", "#fffcdd", "#ffd8d8", "#f5a2a2"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/company.go b/vendor/github.com/brianvoe/gofakeit/v7/data/company.go new file mode 100644 index 0000000000..43b6a2dc93 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/company.go @@ -0,0 +1,10 @@ +package data + +// Company consists of company information +var Company = map[string][]string{ + "name": {"3 Round Stones, Inc.", "48 Factoring Inc.", "5PSolutions", "Abt Associates", "Accela", "Accenture", "AccuWeather", "Acxiom", "Adaptive", "Adobe Digital Government", "Aidin", "Alarm.com", "Allianz", "Allied Van Lines", "AllState Insurance Group", "Alltuition", "Altova", "Amazon Web Services", "American Red Ball Movers", "Amida Technology Solutions", "Analytica", "Apextech LLC", "Appallicious", "Aquicore", "Archimedes Inc.", "AreaVibes Inc.", "Arpin Van Lines", "Arrive Labs", "ASC Partners", "Asset4", "Atlas Van Lines", "AtSite", "Aunt Bertha, Inc.", "Aureus Sciences (*Now part of Elsevier)", "AutoGrid Systems", "Avalara", "Avvo", "Ayasdi", "Azavea", "BaleFire Global", "Barchart", "Be Informed", "Bekins", "Berkery Noyes MandASoft", "Berkshire Hathaway", "BetterLesson", "BillGuard", "Bing", "Biovia", "BizVizz", "BlackRock", "Bloomberg", "Booz Allen Hamilton", "Boston Consulting Group", "Boundless", "Bridgewater", "Brightscope", "BuildFax", "Buildingeye", "BuildZoom", "Business and Legal Resources", "Business Monitor International", "Calcbench, Inc.", "Cambridge Information Group", "Cambridge Semantics", "CAN Capital", "Canon", "Capital Cube", "Cappex", "Captricity", "CareSet Systems", "Careset.com", "CARFAX", "Caspio", "Castle Biosciences", "CB Insights", "Ceiba Solutions", "Center for Responsive Politics", "Cerner", "Certara", "CGI", "Charles River Associates", "Charles Schwab Corp.", "Chemical Abstracts Service", "Child Care Desk", "Chubb", "Citigroup", "CityScan", "CitySourced", "Civic Impulse LLC", "Civic Insight", "Civinomics", "Civis Analytics", "Clean Power Finance", "ClearHealthCosts", "ClearStory Data", "Climate Corporation", "CliniCast", "Cloudmade", "Cloudspyre", "Code for America", "Code-N", "Collective IP", "College Abacus, an ECMC initiative", "College Board", "Compared Care", "Compendia Bioscience Life Technologies", "Compliance and Risks", "Computer Packages Inc", "CONNECT-DOT LLC.", "ConnectEDU", "Connotate", "Construction Monitor LLC", "Consumer Reports", "CoolClimate", "Copyright Clearance Center", "CoreLogic", "CostQuest", "Credit Karma", "Credit Sesame", "CrowdANALYTIX", "Dabo Health", "DataLogix", "DataMade", "DataMarket", "Datamyne", "DataWeave", "Deloitte", "DemystData", "Department of Better Technology", "Development Seed", "Docket Alarm, Inc.", "Dow Jones & Co.", "Dun & Bradstreet", "Earth Networks", "EarthObserver App", "Earthquake Alert!", "Eat Shop Sleep", "Ecodesk", "eInstitutional", "Embark", "EMC", "Energy Points, Inc.", "Energy Solutions Forum", "Enervee Corporation", "Enigma.io", "Ensco", "Environmental Data Resources", "Epsilon", "Equal Pay for Women", "Equifax", "Equilar", "Ernst & Young LLP", "eScholar LLC.", "Esri", "Estately", "Everyday Health", "Evidera", "Experian", "Expert Health Data Programming, Inc.", "Exversion", "Ez-XBRL", "Factset", "Factual", "Farmers", "FarmLogs", "Fastcase", "Fidelity Investments", "FindTheBest.com", "First Fuel Software", "FirstPoint, Inc.", "Fitch", "FlightAware", "FlightStats", "FlightView", "Food+Tech Connect", "Forrester Research", "Foursquare", "Fujitsu", "Funding Circle", "FutureAdvisor", "Fuzion Apps, Inc.", "Gallup", "Galorath Incorporated", "Garmin", "Genability", "GenoSpace", "Geofeedia", "Geolytics", "Geoscape", "GetRaised", "GitHub", "Glassy Media", "Golden Helix", "GoodGuide", "Google Maps", "Google Public Data Explorer", "Government Transaction Services", "Govini", "GovTribe", "Govzilla, Inc.", "gRadiant Research LLC", "Graebel Van Lines", "Graematter, Inc.", "Granicus", "GreatSchools", "GuideStar", "H3 Biomedicine", "Harris Corporation", "HDScores, Inc", "Headlight", "Healthgrades", "Healthline", "HealthMap", "HealthPocket, Inc.", "HelloWallet", "HERE", "Honest Buildings", "HopStop", "Housefax", "How's My Offer?", "IBM", "ideas42", "iFactor Consulting", "IFI CLAIMS Patent Services", "iMedicare", "Impact Forecasting (Aon)", "Impaq International", "Import.io", "IMS Health", "InCadence", "indoo.rs", "InfoCommerce Group", "Informatica", "InnoCentive", "Innography", "Innovest Systems", "Inovalon", "Inrix Traffic", "Intelius", "Intermap Technologies", "Investormill", "Iodine", "IPHIX", "iRecycle", "iTriage", "IVES Group Inc", "IW Financial", "JJ Keller", "J.P. Morgan Chase", "Junar, Inc.", "Junyo", "Jurispect", "Kaiser Permanante", "karmadata", "Keychain Logistics Corp.", "KidAdmit, Inc.", "Kimono Labs", "KLD Research", "Knoema", "Knowledge Agency", "KPMG", "Kroll Bond Ratings Agency", "Kyruus", "Lawdragon", "Legal Science Partners", "(Leg)Cyte", "LegiNation, Inc.", "LegiStorm", "Lenddo", "Lending Club", "Level One Technologies", "LexisNexis", "Liberty Mutual Insurance Cos.", "Lilly Open Innovation Drug Discovery", "Liquid Robotics", "Locavore", "LOGIXDATA, LLC", "LoopNet", "Loqate, Inc.", "LoseIt.com", "LOVELAND Technologies", "Lucid", "Lumesis, Inc.", "Mango Transit", "Mapbox", "Maponics", "MapQuest", "Marinexplore, Inc.", "MarketSense", "Marlin & Associates", "Marlin Alter and Associates", "McGraw Hill Financial", "McKinsey", "MedWatcher", "Mercaris", "Merrill Corp.", "Merrill Lynch", "MetLife", "mHealthCoach", "MicroBilt Corporation", "Microsoft Windows Azure Marketplace", "Mint", "Moody's", "Morgan Stanley", "Morningstar, Inc.", "Mozio", "MuckRock.com", "Munetrix", "Municode", "National Van Lines", "Nationwide Mutual Insurance Company", "Nautilytics", "Navico", "NERA Economic Consulting", "NerdWallet", "New Media Parents", "Next Step Living", "NextBus", "nGAP Incorporated", "Nielsen", "Noesis", "NonprofitMetrics", "North American Van Lines", "Noveda Technologies", "NuCivic", "Numedii", "Oliver Wyman", "OnDeck", "OnStar", "Ontodia, Inc", "Onvia", "Open Data Nation", "OpenCounter", "OpenGov", "OpenPlans", "OpportunitySpace, Inc.", "Optensity", "optiGov", "OptumInsight", "Orlin Research", "OSIsoft", "OTC Markets", "Outline", "Oversight Systems", "Overture Technologies", "Owler", "Palantir Technologies", "Panjiva", "Parsons Brinckerhoff", "Patently-O", "PatientsLikeMe", "Pave", "Paxata", "PayScale, Inc.", "PeerJ", "People Power", "Persint", "Personal Democracy Media", "Personal, Inc.", "Personalis", "Peterson's", "PEV4me.com", "PIXIA Corp", "PlaceILive.com", "PlanetEcosystems", "PlotWatt", "Plus-U", "PolicyMap", "Politify", "Poncho App", "POPVOX", "Porch", "PossibilityU", "PowerAdvocate", "Practice Fusion", "Predilytics", "PricewaterhouseCoopers (PWC)", "ProgrammableWeb", "Progressive Insurance Group", "Propeller Health", "ProPublica", "PublicEngines", "PYA Analytics", "Qado Energy, Inc.", "Quandl", "Quertle", "Quid", "R R Donnelley", "RAND Corporation", "Rand McNally", "Rank and Filed", "Ranku", "Rapid Cycle Solutions", "realtor.com", "Recargo", "ReciPal", "Redfin", "RedLaser", "Reed Elsevier", "REI Systems", "Relationship Science", "Remi", "Retroficiency", "Revaluate", "Revelstone", "Rezolve Group", "Rivet Software", "Roadify Transit", "Robinson + Yu", "Russell Investments", "Sage Bionetworks", "SAP", "SAS", "Scale Unlimited", "Science Exchange", "Seabourne", "SeeClickFix", "SigFig", "Simple Energy", "SimpleTuition", "SlashDB", "Smart Utility Systems", "SmartAsset", "SmartProcure", "Smartronix", "SnapSense", "Social Explorer", "Social Health Insights", "SocialEffort Inc", "Socrata", "Solar Census", "SolarList", "Sophic Systems Alliance", "S&P Capital IQ", "SpaceCurve", "SpeSo Health", "Spikes Cavell Analytic Inc", "Splunk", "Spokeo", "SpotCrime", "SpotHero.com", "Stamen Design", "Standard and Poor's", "State Farm Insurance", "Sterling Infosystems", "Stevens Worldwide Van Lines", "STILLWATER SUPERCOMPUTING INC", "StockSmart", "Stormpulse", "StreamLink Software", "StreetCred Software, Inc", "StreetEasy", "Suddath", "Symcat", "Synthicity", "T. Rowe Price", "Tableau Software", "TagniFi", "Telenav", "Tendril", "Teradata", "The Advisory Board Company", "The Bridgespan Group", "The DocGraph Journal", "The Govtech Fund", "The Schork Report", "The Vanguard Group", "Think Computer Corporation", "Thinknum", "Thomson Reuters", "TopCoder", "TowerData", "TransparaGov", "TransUnion", "TrialTrove", "TrialX", "Trintech", "TrueCar", "Trulia", "TrustedID", "TuvaLabs", "Uber", "Unigo LLC", "United Mayflower", "Urban Airship", "Urban Mapping, Inc", "US Green Data", "U.S. News Schools", "USAA Group", "USSearch", "Verdafero", "Vimo", "VisualDoD, LLC", "Vital Axiom | Niinja", "VitalChek", "Vitals", "Vizzuality", "Votizen", "Walk Score", "WaterSmart Software", "WattzOn", "Way Better Patents", "Weather Channel", "Weather Decision Technologies", "Weather Underground", "WebFilings", "Webitects", "WebMD", "Weight Watchers", "WeMakeItSafer", "Wheaton World Wide Moving", "Whitby Group", "Wolfram Research", "Wolters Kluwer", "Workhands", "Xatori", "Xcential", "xDayta", "Xignite", "Yahoo", "Zebu Compliance Solutions", "Yelp", "YourMapper", "Zillow", "ZocDoc", "Zonability", "Zoner", "Zurich Insurance (Risk Room)"}, + "suffix": {"Inc", "and Sons", "LLC", "Group"}, + "buzzwords": {"Adaptive", "Advanced", "Ameliorated", "Assimilated", "Automated", "Balanced", "Business-focused", "Centralized", "Cloned", "Compatible", "Configurable", "Cross-group", "Cross-platform", "Customer-focused", "Customizable", "De-engineered", "Decentralized", "Devolved", "Digitized", "Distributed", "Diverse", "Down-sized", "Enhanced", "Enterprise-wide", "Ergonomic", "Exclusive", "Expanded", "Extended", "Face to face", "Focused", "Front-line", "Fully-configurable", "Function-based", "Fundamental", "Future-proofed", "Grass-roots", "Horizontal", "Implemented", "Innovative", "Integrated", "Intuitive", "Inverse", "Managed", "Mandatory", "Monitored", "Multi-channelled", "Multi-lateral", "Multi-layered", "Multi-tiered", "Networked", "Object-based", "Open-architected", "Open-source", "Operative", "Optimized", "Optional", "Organic", "Organized", "Persevering", "Persistent", "Phased", "Polarised", "Pre-emptive", "Proactive", "Profit-focused", "Profound", "Programmable", "Progressive", "Public-key", "Quality-focused", "Re-contextualized", "Re-engineered", "Reactive", "Realigned", "Reduced", "Reverse-engineered", "Right-sized", "Robust", "Seamless", "Secured", "Self-enabling", "Sharable", "Stand-alone", "Streamlined", "Switchable", "Synchronised", "Synergistic", "Synergized", "Team-oriented", "Total", "Triple-buffered", "Universal", "Up-sized", "Upgradable", "User-centric", "User-friendly", "Versatile", "Virtual", "Vision-oriented", "Visionary", "24 hour", "24/7", "3rd generation", "4th generation", "5th generation", "6th generation", "actuating", "analyzing", "asymmetric", "asynchronous", "attitude-oriented", "background", "bandwidth-monitored", "bi-directional", "bifurcated", "bottom-line", "clear-thinking", "client-driven", "client-server", "coherent", "cohesive", "composite", "content-based", "context-sensitive", "contextually-based", "dedicated", "demand-driven", "didactic", "directional", "discrete", "disintermediate", "dynamic", "eco-centric", "empowering", "encompassing", "even-keeled", "executive", "explicit", "exuding", "fault-tolerant", "foreground", "fresh-thinking", "full-range", "global", "grid-enabled", "heuristic", "high-level", "holistic", "homogeneous", "human-resource", "hybrid", "impactful", "incremental", "intangible", "interactive", "intermediate", "leading edge", "local", "logistical", "maximized", "methodical", "mission-critical", "mobile", "modular", "motivating", "multi-state", "multi-tasking", "multimedia", "national", "needs-based", "neutral", "next generation", "non-volatile", "object-oriented", "optimal", "optimizing", "radical", "real-time", "reciprocal", "regional", "responsive", "scalable", "secondary", "solution-oriented", "stable", "static", "system-worthy", "systematic", "systemic", "tangible", "tertiary", "transitional", "uniform", "upward-trending", "user-facing", "value-added", "web-enabled", "well-modulated", "zero administration", "zero defect", "zero tolerance", "Graphic Interface", "Graphical User Interface", "ability", "access", "adapter", "algorithm", "alliance", "analyzer", "application", "approach", "architecture", "archive", "array", "artificial intelligence", "attitude", "benchmark", "budgetary management", "capability", "capacity", "challenge", "circuit", "collaboration", "complexity", "concept", "conglomeration", "contingency", "core", "customer loyalty", "data-warehouse", "database", "definition", "emulation", "encoding", "encryption", "extranet", "firmware", "flexibility", "focus group", "forecast", "frame", "framework", "function", "functionalities", "groupware", "hardware", "help-desk", "hierarchy", "hub", "implementation", "info-mediaries", "infrastructure", "initiative", "installation", "instruction set", "interface", "internet solution", "intranet", "knowledge base", "knowledge user", "leverage", "local area network", "matrices", "matrix", "methodology", "middleware", "migration", "model", "moderator", "monitoring", "moratorium", "neural-net", "open architecture", "open system", "orchestration", "paradigm", "parallelism", "policy", "portal", "pricing structure", "process improvement", "product", "productivity", "project", "projection", "protocol", "secured line", "service-desk", "software", "solution", "standardization", "strategy", "structure", "success", "superstructure", "support", "synergy", "system engine", "task-force", "throughput", "time-frame", "toolset", "utilisation", "website", "workforce"}, + "bs": {"aggregate", "architect", "benchmark", "brand", "cultivate", "deliver", "deploy", "disintermediate", "drive", "e-enable", "embrace", "empower", "enable", "engage", "engineer", "enhance", "envisioneer", "evolve", "expedite", "exploit", "extend", "facilitate", "generate", "grow", "harness", "implement", "incentivize", "incubate", "innovate", "integrate", "iterate", "leverage", "matrix", "maximize", "mesh", "monetize", "morph", "optimize", "orchestrate", "productize", "recontextualize", "redefine", "reintermediate", "reinvent", "repurpose", "revolutionize", "scale", "seize", "strategize", "streamline", "syndicate", "synergize", "synthesize", "target", "transform", "transition", "unleash", "utilize", "visualize", "whiteboard", "24-365", "24-7", "B2B", "B2C", "back-end", "best-of-breed", "bleeding-edge", "bricks-and-clicks", "clicks-and-mortar", "collaborative", "compelling", "cross-media", "cross-platform", "customized", "cutting-edge", "distributed", "dot-com", "dynamic", "e-business", "efficient", "end-to-end", "enterprise", "extensible", "frictionless", "front-end", "global", "granular", "holistic", "impactful", "innovative", "integrated", "interactive", "intuitive", "killer", "leading-edge", "magnetic", "mission-critical", "next-generation", "one-to-one", "open-source", "out-of-the-box", "plug-and-play", "proactive", "real-time", "revolutionary", "rich", "robust", "scalable", "seamless", "sexy", "sticky", "strategic", "synergistic", "transparent", "turn-key", "ubiquitous", "user-centric", "value-added", "vertical", "viral", "virtual", "visionary", "web-enabled", "wireless", "world-class", "ROI", "action-items", "applications", "architectures", "bandwidth", "channels", "communities", "content", "convergence", "deliverables", "e-business", "e-commerce", "e-markets", "e-services", "e-tailers", "experiences", "eyeballs", "functionalities", "infomediaries", "infrastructures", "initiatives", "interfaces", "markets", "methodologies", "metrics", "mindshare", "models", "networks", "niches", "paradigms", "partnerships", "platforms", "portals", "relationships", "schemas", "solutions", "supply-chains", "synergies", "systems", "technologies", "users", "vortals", "web services", "web-readiness"}, + "blurb": {"Advancement", "Advantage", "Ambition", "Balance", "Belief", "Benefits", "Care", "Challenge", "Change", "Choice", "Commitment", "Comfort", "Connection", "Consistency", "Creativity", "Dedication", "Discovery", "Diversity", "Dream", "Dreams", "Drive", "Ease", "Efficiency", "Empowerment", "Endurance", "Energy", "Engagement", "Environment", "Enterprise", "Excellence", "Exclusivity", "Experience", "Exploration", "Expression", "Family", "Flexibility", "Focus", "Freedom", "Future", "Future", "Growth", "Harmony", "Health", "Heart", "History", "Home", "Honesty", "Hope", "Impact", "Innovation", "Inspiration", "Integrity", "Joy", "Journey", "Knowledge", "Leadership", "Legacy", "Life", "Luxury", "Money", "Motivation", "Optimism", "Partnership", "Passion", "Peace", "People", "Performance", "Perseverance", "Pleasure", "Power", "Pride", "Progress", "Promise", "Quality", "Quality", "Reliability", "Resilience", "Respect", "Revolution", "Safety", "Service", "Simplicity", "Solutions", "Solidarity", "Strength", "Style", "Success", "Sustainability", "Taste", "Teamwork", "Technology", "Time", "Transformation", "Trust", "Unity", "Value", "Versatility", "Vision", "Wellness", "World"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/computer.go b/vendor/github.com/brianvoe/gofakeit/v7/data/computer.go new file mode 100644 index 0000000000..b682c6f820 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/computer.go @@ -0,0 +1,8 @@ +package data + +// Computer consists of computer information +var Computer = map[string][]string{ + "linux_processor": {"i686", "x86_64"}, + "mac_processor": {"Intel", "PPC", "U; Intel", "U; PPC"}, + "windows_platform": {"Windows NT 6.2", "Windows NT 6.1", "Windows NT 6.0", "Windows NT 5.2", "Windows NT 5.1", "Windows NT 5.01", "Windows NT 5.0", "Windows NT 4.0", "Windows 98; Win 9x 4.90", "Windows 98", "Windows 95", "Windows CE"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/currency.go b/vendor/github.com/brianvoe/gofakeit/v7/data/currency.go new file mode 100644 index 0000000000..13b8019973 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/currency.go @@ -0,0 +1,7 @@ +package data + +// Currency consists of currency information +var Currency = map[string][]string{ + "short": {"AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYR", "BZD", "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GGP", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "IMP", "INR", "IQD", "IRR", "ISK", "JEP", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SPL", "SRD", "STD", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TVD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VEF", "VND", "VUV", "WST", "XAF", "XCD", "XDR", "XOF", "XPF", "YER", "ZAR", "ZMW", "ZWD"}, + "long": {"United Arab Emirates Dirham", "Afghanistan Afghani", "Albania Lek", "Armenia Dram", "Netherlands Antilles Guilder", "Angola Kwanza", "Argentina Peso", "Australia Dollar", "Aruba Guilder", "Azerbaijan New Manat", "Bosnia and Herzegovina Convertible Marka", "Barbados Dollar", "Bangladesh Taka", "Bulgaria Lev", "Bahrain Dinar", "Burundi Franc", "Bermuda Dollar", "Brunei Darussalam Dollar", "Bolivia Boliviano", "Brazil Real", "Bahamas Dollar", "Bhutan Ngultrum", "Botswana Pula", "Belarus Ruble", "Belize Dollar", "Canada Dollar", "Congo/Kinshasa Franc", "Switzerland Franc", "Chile Peso", "China Yuan Renminbi", "Colombia Peso", "Costa Rica Colon", "Cuba Convertible Peso", "Cuba Peso", "Cape Verde Escudo", "Czech Republic Koruna", "Djibouti Franc", "Denmark Krone", "Dominican Republic Peso", "Algeria Dinar", "Egypt Pound", "Eritrea Nakfa", "Ethiopia Birr", "Euro Member Countries", "Fiji Dollar", "Falkland Islands (Malvinas) Pound", "United Kingdom Pound", "Georgia Lari", "Guernsey Pound", "Ghana Cedi", "Gibraltar Pound", "Gambia Dalasi", "Guinea Franc", "Guatemala Quetzal", "Guyana Dollar", "Hong Kong Dollar", "Honduras Lempira", "Croatia Kuna", "Haiti Gourde", "Hungary Forint", "Indonesia Rupiah", "Israel Shekel", "Isle of Man Pound", "India Rupee", "Iraq Dinar", "Iran Rial", "Iceland Krona", "Jersey Pound", "Jamaica Dollar", "Jordan Dinar", "Japan Yen", "Kenya Shilling", "Kyrgyzstan Som", "Cambodia Riel", "Comoros Franc", "Korea (North) Won", "Korea (South) Won", "Kuwait Dinar", "Cayman Islands Dollar", "Kazakhstan Tenge", "Laos Kip", "Lebanon Pound", "Sri Lanka Rupee", "Liberia Dollar", "Lesotho Loti", "Lithuania Litas", "Libya Dinar", "Morocco Dirham", "Moldova Leu", "Madagascar Ariary", "Macedonia Denar", "Myanmar (Burma) Kyat", "Mongolia Tughrik", "Macau Pataca", "Mauritania Ouguiya", "Mauritius Rupee", "Maldives (Maldive Islands) Rufiyaa", "Malawi Kwacha", "Mexico Peso", "Malaysia Ringgit", "Mozambique Metical", "Namibia Dollar", "Nigeria Naira", "Nicaragua Cordoba", "Norway Krone", "Nepal Rupee", "New Zealand Dollar", "Oman Rial", "Panama Balboa", "Peru Nuevo Sol", "Papua New Guinea Kina", "Philippines Peso", "Pakistan Rupee", "Poland Zloty", "Paraguay Guarani", "Qatar Riyal", "Romania New Leu", "Serbia Dinar", "Russia Ruble", "Rwanda Franc", "Saudi Arabia Riyal", "Solomon Islands Dollar", "Seychelles Rupee", "Sudan Pound", "Sweden Krona", "Singapore Dollar", "Saint Helena Pound", "Sierra Leone Leone", "Somalia Shilling", "Seborga Luigino", "Suriname Dollar", "São Tomé and Príncipe Dobra", "El Salvador Colon", "Syria Pound", "Swaziland Lilangeni", "Thailand Baht", "Tajikistan Somoni", "Turkmenistan Manat", "Tunisia Dinar", "Tonga Pa'anga", "Turkey Lira", "Trinidad and Tobago Dollar", "Tuvalu Dollar", "Taiwan New Dollar", "Tanzania Shilling", "Ukraine Hryvnia", "Uganda Shilling", "United States Dollar", "Uruguay Peso", "Uzbekistan Som", "Venezuela Bolivar", "Viet Nam Dong", "Vanuatu Vatu", "Samoa Tala", "Communauté Financière Africaine (BEAC) CFA Franc BEAC", "East Caribbean Dollar", "International Monetary Fund (IMF) Special Drawing Rights", "Communauté Financière Africaine (BCEAO) Franc", "Comptoirs Français du Pacifique (CFP) Franc", "Yemen Rial", "South Africa Rand", "Zambia Kwacha", "Zimbabwe Dollar"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/data.go b/vendor/github.com/brianvoe/gofakeit/v7/data/data.go new file mode 100644 index 0000000000..dae4a38b56 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/data.go @@ -0,0 +1,91 @@ +package data + +// Data consists of the main set of fake information +var Data = map[string]map[string][]string{ + "person": Person, + "address": Address, + "company": Company, + "job": Job, + "lorem": Lorem, + "language": Languages, + "internet": Internet, + "file": Files, + "color": Colors, + "computer": Computer, + "hipster": Hipster, + "beer": Beer, + "hacker": Hacker, + "animal": Animal, + "currency": Currency, + "log_level": LogLevels, + "timezone": TimeZone, + "car": Car, + "emoji": Emoji, + "word": Word, + "sentence": Sentence, + "food": Food, + "minecraft": Minecraft, + "celebrity": Celebrity, + "error": Error, + "html": Html, + "book": Books, + "movie": Movies, + "school": School, + "song": Songs, + "product": Product, +} + +func List() map[string][]string { + var list = make(map[string][]string) + + // Loop through the data and add the keys to the list + for key := range Data { + list[key] = []string{} + + // Loop through the sub data and add the keys to the list + for subkey := range Data[key] { + list[key] = append(list[key], subkey) + } + } + + return list +} + +func Get(key string) map[string][]string { + // Make sure the key exists, if not return an empty map + if _, ok := Data[key]; !ok { + return make(map[string][]string) + } + + return Data[key] +} + +func Set(key string, data map[string][]string) { + Data[key] = data +} + +func Remove(key string) { + delete(Data, key) +} + +func GetSubData(key, subkey string) []string { + // Make sure the key exists, if not return an empty map + if _, ok := Data[key]; !ok { + return []string{} + } + + return Data[key][subkey] +} + +func SetSub(key, subkey string, data []string) { + // Make sure the key exists, if not add it + if _, ok := Data[key]; !ok { + Data[key] = make(map[string][]string) + } + + Data[key][subkey] = data +} + +func RemoveSub(key, subkey string) { + delete(Data[key], subkey) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/datetime.go b/vendor/github.com/brianvoe/gofakeit/v7/data/datetime.go new file mode 100644 index 0000000000..1007b76991 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/datetime.go @@ -0,0 +1,10 @@ +package data + +// TimeZone is an array of short and long timezones +var TimeZone = map[string][]string{ + "offset": {"-12", "-11", "-10", "-8", "-7", "-7", "-8", "-7", "-6", "-6", "-6", "-5", "-5", "-6", "-5", "-4", "-4", "-4.5", "-4", "-3", "-4", "-4", "-4", "-2.5", "-3", "-3", "-3", "-3", "-3", "-3", "-2", "-1", "0", "-1", "1", "0", "0", "1", "1", "0", "2", "2", "2", "2", "1", "1", "3", "3", "2", "3", "3", "2", "3", "3", "3", "2", "3", "3", "3", "3", "3", "3", "4", "4.5", "4", "5", "4", "4", "4", "4.5", "5", "5", "5", "5.5", "5.5", "5.75", "6", "6", "6.5", "7", "7", "8", "8", "8", "8", "8", "8", "9", "9", "9", "9.5", "9.5", "10", "10", "10", "10", "10", "11", "11", "12", "12", "12", "12", "13", "13", "13"}, + "abr": {"DST", "U", "HST", "AKDT", "PDT", "PDT", "PST", "UMST", "MDT", "MDT", "CAST", "CDT", "CDT", "CCST", "SPST", "EDT", "UEDT", "VST", "PYT", "ADT", "CBST", "SWST", "PSST", "NDT", "ESAST", "AST", "SEST", "GDT", "MST", "BST", "U", "MDT", "ADT", "CVST", "MDT", "UTC", "GMT", "BST", "GDT", "GST", "WEDT", "CEDT", "RDT", "CEDT", "WCAST", "NST", "GDT", "MEDT", "EST", "SDT", "EEDT", "SAST", "FDT", "TDT", "JDT", "LST", "JST", "AST", "KST", "AST", "EAST", "MSK", "SAMT", "IDT", "AST", "ADT", "MST", "GST", "CST", "AST", "WAST", "YEKT", "PKT", "IST", "SLST", "NST", "CAST", "BST", "MST", "SAST", "NCAST", "CST", "NAST", "MPST", "WAST", "TST", "UST", "NAEST", "JST", "KST", "CAST", "ACST", "EAST", "AEST", "WPST", "TST", "YST", "CPST", "VST", "NZST", "U", "FST", "MST", "KDT", "TST", "SST"}, + "text": {"Dateline Standard Time", "UTC-11", "Hawaiian Standard Time", "Alaskan Standard Time", "Pacific Standard Time (Mexico)", "Pacific Daylight Time", "Pacific Standard Time", "US Mountain Standard Time", "Mountain Standard Time (Mexico)", "Mountain Standard Time", "Central America Standard Time", "Central Standard Time", "Central Standard Time (Mexico)", "Canada Central Standard Time", "SA Pacific Standard Time", "Eastern Standard Time", "US Eastern Standard Time", "Venezuela Standard Time", "Paraguay Standard Time", "Atlantic Standard Time", "Central Brazilian Standard Time", "SA Western Standard Time", "Pacific SA Standard Time", "Newfoundland Standard Time", "E. South America Standard Time", "Argentina Standard Time", "SA Eastern Standard Time", "Greenland Standard Time", "Montevideo Standard Time", "Bahia Standard Time", "UTC-02", "Mid-Atlantic Standard Time", "Azores Standard Time", "Cape Verde Standard Time", "Morocco Standard Time", "UTC", "Greenwich Mean Time", "British Summer Time", "GMT Standard Time", "Greenwich Standard Time", "W. Europe Standard Time", "Central Europe Standard Time", "Romance Standard Time", "Central European Standard Time", "W. Central Africa Standard Time", "Namibia Standard Time", "GTB Standard Time", "Middle East Standard Time", "Egypt Standard Time", "Syria Standard Time", "E. Europe Standard Time", "South Africa Standard Time", "FLE Standard Time", "Turkey Standard Time", "Israel Standard Time", "Libya Standard Time", "Jordan Standard Time", "Arabic Standard Time", "Kaliningrad Standard Time", "Arab Standard Time", "E. Africa Standard Time", "Moscow Standard Time", "Samara Time", "Iran Standard Time", "Arabian Standard Time", "Azerbaijan Standard Time", "Mauritius Standard Time", "Georgian Standard Time", "Caucasus Standard Time", "Afghanistan Standard Time", "West Asia Standard Time", "Yekaterinburg Time", "Pakistan Standard Time", "India Standard Time", "Sri Lanka Standard Time", "Nepal Standard Time", "Central Asia Standard Time", "Bangladesh Standard Time", "Myanmar Standard Time", "SE Asia Standard Time", "N. Central Asia Standard Time", "China Standard Time", "North Asia Standard Time", "Singapore Standard Time", "W. Australia Standard Time", "Taipei Standard Time", "Ulaanbaatar Standard Time", "North Asia East Standard Time", "Japan Standard Time", "Korea Standard Time", "Cen. Australia Standard Time", "AUS Central Standard Time", "E. Australia Standard Time", "AUS Eastern Standard Time", "West Pacific Standard Time", "Tasmania Standard Time", "Yakutsk Standard Time", "Central Pacific Standard Time", "Vladivostok Standard Time", "New Zealand Standard Time", "UTC+12", "Fiji Standard Time", "Magadan Standard Time", "Kamchatka Standard Time", "Tonga Standard Time", "Samoa Standard Time"}, + "full": {"(UTC-12:00) International Date Line West", "(UTC-11:00) Coordinated Universal Time-11", "(UTC-10:00) Hawaii", "(UTC-09:00) Alaska", "(UTC-08:00) Baja California", "(UTC-07:00) Pacific Time (US & Canada)", "(UTC-08:00) Pacific Time (US & Canada)", "(UTC-07:00) Arizona", "(UTC-07:00) Chihuahua, La Paz, Mazatlan", "(UTC-07:00) Mountain Time (US & Canada)", "(UTC-06:00) Central America", "(UTC-06:00) Central Time (US & Canada)", "(UTC-06:00) Guadalajara, Mexico City, Monterrey", "(UTC-06:00) Saskatchewan", "(UTC-05:00) Bogota, Lima, Quito", "(UTC-05:00) Eastern Time (US & Canada)", "(UTC-05:00) Indiana (East)", "(UTC-04:30) Caracas", "(UTC-04:00) Asuncion", "(UTC-04:00) Atlantic Time (Canada)", "(UTC-04:00) Cuiaba", "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan", "(UTC-04:00) Santiago", "(UTC-03:30) Newfoundland", "(UTC-03:00) Brasilia", "(UTC-03:00) Buenos Aires", "(UTC-03:00) Cayenne, Fortaleza", "(UTC-03:00) Greenland", "(UTC-03:00) Montevideo", "(UTC-03:00) Salvador", "(UTC-02:00) Coordinated Universal Time-02", "(UTC-02:00) Mid-Atlantic - Old", "(UTC-01:00) Azores", "(UTC-01:00) Cape Verde Is.", "(UTC) Casablanca", "(UTC) Coordinated Universal Time", "(UTC) Edinburgh, London", "(UTC+01:00) Edinburgh, London", "(UTC) Dublin, Lisbon", "(UTC) Monrovia, Reykjavik", "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague", "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", "(UTC+01:00) West Central Africa", "(UTC+01:00) Windhoek", "(UTC+02:00) Athens, Bucharest", "(UTC+02:00) Beirut", "(UTC+02:00) Cairo", "(UTC+02:00) Damascus", "(UTC+02:00) E. Europe", "(UTC+02:00) Harare, Pretoria", "(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", "(UTC+03:00) Istanbul", "(UTC+02:00) Jerusalem", "(UTC+02:00) Tripoli", "(UTC+03:00) Amman", "(UTC+03:00) Baghdad", "(UTC+03:00) Kaliningrad, Minsk", "(UTC+03:00) Kuwait, Riyadh", "(UTC+03:00) Nairobi", "(UTC+03:00) Moscow, St. Petersburg, Volgograd", "(UTC+04:00) Samara, Ulyanovsk, Saratov", "(UTC+03:30) Tehran", "(UTC+04:00) Abu Dhabi, Muscat", "(UTC+04:00) Baku", "(UTC+04:00) Port Louis", "(UTC+04:00) Tbilisi", "(UTC+04:00) Yerevan", "(UTC+04:30) Kabul", "(UTC+05:00) Ashgabat, Tashkent", "(UTC+05:00) Yekaterinburg", "(UTC+05:00) Islamabad, Karachi", "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", "(UTC+05:30) Sri Jayawardenepura", "(UTC+05:45) Kathmandu", "(UTC+06:00) Astana", "(UTC+06:00) Dhaka", "(UTC+06:30) Yangon (Rangoon)", "(UTC+07:00) Bangkok, Hanoi, Jakarta", "(UTC+07:00) Novosibirsk", "(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", "(UTC+08:00) Krasnoyarsk", "(UTC+08:00) Kuala Lumpur, Singapore", "(UTC+08:00) Perth", "(UTC+08:00) Taipei", "(UTC+08:00) Ulaanbaatar", "(UTC+09:00) Irkutsk", "(UTC+09:00) Osaka, Sapporo, Tokyo", "(UTC+09:00) Seoul", "(UTC+09:30) Adelaide", "(UTC+09:30) Darwin", "(UTC+10:00) Brisbane", "(UTC+10:00) Canberra, Melbourne, Sydney", "(UTC+10:00) Guam, Port Moresby", "(UTC+10:00) Hobart", "(UTC+10:00) Yakutsk", "(UTC+11:00) Solomon Is., New Caledonia", "(UTC+11:00) Vladivostok", "(UTC+12:00) Auckland, Wellington", "(UTC+12:00) Coordinated Universal Time+12", "(UTC+12:00) Fiji", "(UTC+12:00) Magadan", "(UTC+12:00) Petropavlovsk-Kamchatsky - Old", "(UTC+13:00) Nuku'alofa", "(UTC+13:00) Samoa"}, + "region": {"Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", "Africa/Algiers", "Africa/Asmara", "Africa/Bamako", "Africa/Bangui", "Africa/Banjul", "Africa/Bissau", "Africa/Blantyre", "Africa/Brazzaville", "Africa/Bujumbura", "Africa/Cairo", "Africa/Casablanca", "Africa/Ceuta", "Africa/Conakry", "Africa/Dakar", "Africa/Dar_es_Salaam", "Africa/Djibouti", "Africa/Douala", "Africa/El_Aaiun", "Africa/Freetown", "Africa/Gaborone", "Africa/Harare", "Africa/Johannesburg", "Africa/Juba", "Africa/Kampala", "Africa/Khartoum", "Africa/Kigali", "Africa/Kinshasa", "Africa/Lagos", "Africa/Libreville", "Africa/Lome", "Africa/Luanda", "Africa/Lubumbashi", "Africa/Lusaka", "Africa/Malabo", "Africa/Maputo", "Africa/Maseru", "Africa/Mbabane", "Africa/Mogadishu", "Africa/Monrovia", "Africa/Nairobi", "Africa/Ndjamena", "Africa/Niamey", "Africa/Nouakchott", "Africa/Ouagadougou", "Africa/Porto-Novo", "Africa/Sao_Tome", "Africa/Timbuktu", "Africa/Tripoli", "Africa/Tunis", "Africa/Windhoek", "America/Adak", "America/Anchorage", "America/Anguilla", "America/Antigua", "America/Araguaina", "America/Argentina/Buenos_Aires", "America/Argentina/Catamarca", "America/Argentina/ComodRivadavia", "America/Argentina/Cordoba", "America/Argentina/Jujuy", "America/Argentina/La_Rioja", "America/Argentina/Mendoza", "America/Argentina/Rio_Gallegos", "America/Argentina/Salta", "America/Argentina/San_Juan", "America/Argentina/San_Luis", "America/Argentina/Tucuman", "America/Argentina/Ushuaia", "America/Aruba", "America/Asuncion", "America/Atikokan", "America/Atka", "America/Bahia", "America/Bahia_Banderas", "America/Barbados", "America/Belem", "America/Belize", "America/Blanc-Sablon", "America/Boa_Vista", "America/Bogota", "America/Boise", "America/Buenos_Aires", "America/Cambridge_Bay", "America/Campo_Grande", "America/Cancun", "America/Caracas", "America/Catamarca", "America/Cayenne", "America/Cayman", "America/Chicago", "America/Chihuahua", "America/Coral_Harbour", "America/Cordoba", "America/Costa_Rica", "America/Creston", "America/Cuiaba", "America/Curacao", "America/Danmarkshavn", "America/Dawson", "America/Dawson_Creek", "America/Denver", "America/Detroit", "America/Dominica", "America/Edmonton", "America/Eirunepe", "America/El_Salvador", "America/Ensenada", "America/Fort_Nelson", "America/Fort_Wayne", "America/Fortaleza", "America/Glace_Bay", "America/Godthab", "America/Goose_Bay", "America/Grand_Turk", "America/Grenada", "America/Guadeloupe", "America/Guatemala", "America/Guayaquil", "America/Guyana", "America/Halifax", "America/Havana", "America/Hermosillo", "America/Indiana/Indianapolis", "America/Indiana/Knox", "America/Indiana/Marengo", "America/Indiana/Petersburg", "America/Indiana/Tell_City", "America/Indiana/Vevay", "America/Indiana/Vincennes", "America/Indiana/Winamac", "America/Indianapolis", "America/Inuvik", "America/Iqaluit", "America/Jamaica", "America/Jujuy", "America/Juneau", "America/Kentucky/Louisville", "America/Kentucky/Monticello", "America/Knox_IN", "America/Kralendijk", "America/La_Paz", "America/Lima", "America/Los_Angeles", "America/Louisville", "America/Lower_Princes", "America/Maceio", "America/Managua", "America/Manaus", "America/Marigot", "America/Martinique", "America/Matamoros", "America/Mazatlan", "America/Mendoza", "America/Menominee", "America/Merida", "America/Metlakatla", "America/Mexico_City", "America/Miquelon", "America/Moncton", "America/Monterrey", "America/Montevideo", "America/Montreal", "America/Montserrat", "America/Nassau", "America/New_York", "America/Nipigon", "America/Nome", "America/Noronha", "America/North_Dakota/Beulah", "America/North_Dakota/Center", "America/North_Dakota/New_Salem", "America/Ojinaga", "America/Panama", "America/Pangnirtung", "America/Paramaribo", "America/Phoenix", "America/Port_of_Spain", "America/Port-au-Prince", "America/Porto_Acre", "America/Porto_Velho", "America/Puerto_Rico", "America/Punta_Arenas", "America/Rainy_River", "America/Rankin_Inlet", "America/Recife", "America/Regina", "America/Resolute", "America/Rio_Branco", "America/Rosario", "America/Santa_Isabel", "America/Santarem", "America/Santiago", "America/Santo_Domingo", "America/Sao_Paulo", "America/Scoresbysund", "America/Shiprock", "America/Sitka", "America/St_Barthelemy", "America/St_Johns", "America/St_Kitts", "America/St_Lucia", "America/St_Thomas", "America/St_Vincent", "America/Swift_Current", "America/Tegucigalpa", "America/Thule", "America/Thunder_Bay", "America/Tijuana", "America/Toronto", "America/Tortola", "America/Vancouver", "America/Virgin", "America/Whitehorse", "America/Winnipeg", "America/Yakutat", "America/Yellowknife", "Antarctica/Casey", "Antarctica/Davis", "Antarctica/DumontDUrville", "Antarctica/Macquarie", "Antarctica/Mawson", "Antarctica/McMurdo", "Antarctica/Palmer", "Antarctica/Rothera", "Antarctica/South_Pole", "Antarctica/Syowa", "Antarctica/Troll", "Antarctica/Vostok", "Arctic/Longyearbyen", "Asia/Aden", "Asia/Almaty", "Asia/Amman", "Asia/Anadyr", "Asia/Aqtau", "Asia/Aqtobe", "Asia/Ashgabat", "Asia/Ashkhabad", "Asia/Atyrau", "Asia/Baghdad", "Asia/Bahrain", "Asia/Baku", "Asia/Bangkok", "Asia/Barnaul", "Asia/Beirut", "Asia/Bishkek", "Asia/Brunei", "Asia/Calcutta", "Asia/Chita", "Asia/Choibalsan", "Asia/Chongqing", "Asia/Chungking", "Asia/Colombo", "Asia/Dacca", "Asia/Damascus", "Asia/Dhaka", "Asia/Dili", "Asia/Dubai", "Asia/Dushanbe", "Asia/Famagusta", "Asia/Gaza", "Asia/Harbin", "Asia/Hebron", "Asia/Ho_Chi_Minh", "Asia/Hong_Kong", "Asia/Hovd", "Asia/Irkutsk", "Asia/Istanbul", "Asia/Jakarta", "Asia/Jayapura", "Asia/Jerusalem", "Asia/Kabul", "Asia/Kamchatka", "Asia/Karachi", "Asia/Kashgar", "Asia/Kathmandu", "Asia/Katmandu", "Asia/Khandyga", "Asia/Kolkata", "Asia/Krasnoyarsk", "Asia/Kuala_Lumpur", "Asia/Kuching", "Asia/Kuwait", "Asia/Macao", "Asia/Macau", "Asia/Magadan", "Asia/Makassar", "Asia/Manila", "Asia/Muscat", "Asia/Novokuznetsk", "Asia/Novosibirsk", "Asia/Omsk", "Asia/Oral", "Asia/Phnom_Penh", "Asia/Pontianak", "Asia/Pyongyang", "Asia/Qatar", "Asia/Qyzylorda", "Asia/Rangoon", "Asia/Riyadh", "Asia/Saigon", "Asia/Sakhalin", "Asia/Samarkand", "Asia/Seoul", "Asia/Shanghai", "Asia/Singapore", "Asia/Srednekolymsk", "Asia/Taipei", "Asia/Tashkent", "Asia/Tbilisi", "Asia/Tehran", "Asia/Tel_Aviv", "Asia/Thimbu", "Asia/Thimphu", "Asia/Tokyo", "Asia/Tomsk", "Asia/Ujung_Pandang", "Asia/Ulaanbaatar", "Asia/Ulan_Bator", "Asia/Urumqi", "Asia/Ust-Nera", "Asia/Vientiane", "Asia/Vladivostok", "Asia/Yakutsk", "Asia/Yangon", "Asia/Yekaterinburg", "Asia/Yerevan", "Atlantic/Azores", "Atlantic/Bermuda", "Atlantic/Canary", "Atlantic/Cape_Verde", "Atlantic/Faeroe", "Atlantic/Faroe", "Atlantic/Jan_Mayen", "Atlantic/Madeira", "Atlantic/Reykjavik", "Atlantic/South_Georgia", "Atlantic/St_Helena", "Atlantic/Stanley", "Australia/Adelaide", "Australia/Brisbane", "Australia/Broken_Hill", "Australia/Canberra", "Australia/Currie", "Australia/Darwin", "Australia/Eucla", "Australia/Hobart", "Australia/Lindeman", "Australia/Lord_Howe", "Australia/Melbourne", "Australia/Perth", "Australia/Sydney", "Australia/Yancowinna", "Etc/GMT", "Etc/GMT+0", "Etc/GMT+1", "Etc/GMT+10", "Etc/GMT+11", "Etc/GMT+12", "Etc/GMT+2", "Etc/GMT+3", "Etc/GMT+4", "Etc/GMT+5", "Etc/GMT+6", "Etc/GMT+7", "Etc/GMT+8", "Etc/GMT+9", "Etc/GMT0", "Etc/GMT-0", "Etc/GMT-1", "Etc/GMT-10", "Etc/GMT-11", "Etc/GMT-12", "Etc/GMT-13", "Etc/GMT-14", "Etc/GMT-2", "Etc/GMT-3", "Etc/GMT-4", "Etc/GMT-5", "Etc/GMT-6", "Etc/GMT-7", "Etc/GMT-8", "Etc/GMT-9", "Etc/UTC", "Europe/Amsterdam", "Europe/Andorra", "Europe/Astrakhan", "Europe/Athens", "Europe/Belfast", "Europe/Belgrade", "Europe/Berlin", "Europe/Bratislava", "Europe/Brussels", "Europe/Bucharest", "Europe/Budapest", "Europe/Busingen", "Europe/Chisinau", "Europe/Copenhagen", "Europe/Dublin", "Europe/Gibraltar", "Europe/Guernsey", "Europe/Helsinki", "Europe/Isle_of_Man", "Europe/Istanbul", "Europe/Jersey", "Europe/Kaliningrad", "Europe/Kiev", "Europe/Kirov", "Europe/Lisbon", "Europe/Ljubljana", "Europe/London", "Europe/Luxembourg", "Europe/Madrid", "Europe/Malta", "Europe/Mariehamn", "Europe/Minsk", "Europe/Monaco", "Europe/Moscow", "Asia/Nicosia", "Europe/Oslo", "Europe/Paris", "Europe/Podgorica", "Europe/Prague", "Europe/Riga", "Europe/Rome", "Europe/Samara", "Europe/San_Marino", "Europe/Sarajevo", "Europe/Saratov", "Europe/Simferopol", "Europe/Skopje", "Europe/Sofia", "Europe/Stockholm", "Europe/Tallinn", "Europe/Tirane", "Europe/Tiraspol", "Europe/Ulyanovsk", "Europe/Uzhgorod", "Europe/Vaduz", "Europe/Vatican", "Europe/Vienna", "Europe/Vilnius", "Europe/Volgograd", "Europe/Warsaw", "Europe/Zagreb", "Europe/Zaporozhye", "Europe/Zurich", "Indian/Antananarivo", "Indian/Chagos", "Indian/Christmas", "Indian/Cocos", "Indian/Comoro", "Indian/Kerguelen", "Indian/Mahe", "Indian/Maldives", "Indian/Mauritius", "Indian/Mayotte", "Indian/Reunion", "Pacific/Apia", "Pacific/Auckland", "Pacific/Bougainville", "Pacific/Chatham", "Pacific/Chuuk", "Pacific/Easter", "Pacific/Efate", "Pacific/Enderbury", "Pacific/Fakaofo", "Pacific/Fiji", "Pacific/Funafuti", "Pacific/Galapagos", "Pacific/Gambier", "Pacific/Guadalcanal", "Pacific/Guam", "Pacific/Honolulu", "Pacific/Johnston", "Pacific/Kiritimati", "Pacific/Kosrae", "Pacific/Kwajalein", "Pacific/Majuro", "Pacific/Marquesas", "Pacific/Midway", "Pacific/Nauru", "Pacific/Niue", "Pacific/Norfolk", "Pacific/Noumea", "Pacific/Pago_Pago", "Pacific/Palau", "Pacific/Pitcairn", "Pacific/Pohnpei", "Pacific/Ponape", "Pacific/Port_Moresby", "Pacific/Rarotonga", "Pacific/Saipan", "Pacific/Samoa", "Pacific/Tahiti", "Pacific/Tarawa", "Pacific/Tongatapu", "Pacific/Truk", "Pacific/Wake", "Pacific/Wallis", "Pacific/Yap"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/emoji.go b/vendor/github.com/brianvoe/gofakeit/v7/data/emoji.go new file mode 100644 index 0000000000..8f8ce80f95 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/emoji.go @@ -0,0 +1,5849 @@ +package data + +// Data is pull from https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json + +// Emoji consists of emoji information +var Emoji = map[string][]string{ + "emoji": { + "😀", + "😃", + "😄", + "😁", + "😆", + "😅", + "🤣", + "😂", + "🙂", + "🙃", + "😉", + "😊", + "😇", + "🥰", + "😍", + "🤩", + "😘", + "😗", + "☺️", + "😚", + "😙", + "😋", + "😛", + "😜", + "🤪", + "😝", + "🤑", + "🤗", + "🤭", + "🤫", + "🤔", + "🤐", + "🤨", + "😐", + "😑", + "😶", + "😏", + "😒", + "🙄", + "😬", + "🤥", + "😌", + "😔", + "😪", + "🤤", + "😴", + "😷", + "🤒", + "🤕", + "🤢", + "🤮", + "🤧", + "🥵", + "🥶", + "🥴", + "😵", + "🤯", + "🤠", + "🥳", + "😎", + "🤓", + "🧐", + "😕", + "😟", + "🙁", + "☹️", + "😮", + "😯", + "😲", + "😳", + "🥺", + "😦", + "😧", + "😨", + "😰", + "😥", + "😢", + "😭", + "😱", + "😖", + "😣", + "😞", + "😓", + "😩", + "😫", + "🥱", + "😤", + "😡", + "😠", + "🤬", + "😈", + "👿", + "💀", + "☠️", + "💩", + "🤡", + "👹", + "👺", + "👻", + "👽", + "👾", + "🤖", + "😺", + "😸", + "😹", + "😻", + "😼", + "😽", + "🙀", + "😿", + "😾", + "🙈", + "🙉", + "🙊", + "💋", + "💌", + "💘", + "💝", + "💖", + "💗", + "💓", + "💞", + "💕", + "💟", + "❣️", + "💔", + "❤️", + "🧡", + "💛", + "💚", + "💙", + "💜", + "🤎", + "🖤", + "🤍", + "💯", + "💢", + "💥", + "💫", + "💦", + "💨", + "🕳️", + "💣", + "💬", + "🗨️", + "🗯️", + "💭", + "💤", + "👋", + "🤚", + "🖐️", + "✋", + "🖖", + "👌", + "🤏", + "✌️", + "🤞", + "🤟", + "🤘", + "🤙", + "👈", + "👉", + "👆", + "🖕", + "👇", + "☝️", + "👍", + "👎", + "✊", + "👊", + "🤛", + "🤜", + "👏", + "🙌", + "👐", + "🤲", + "🤝", + "🙏", + "✍️", + "💅", + "🤳", + "💪", + "🦾", + "🦿", + "🦵", + "🦶", + "👂", + "🦻", + "👃", + "🧠", + "🦷", + "🦴", + "👀", + "👁️", + "👅", + "👄", + "👶", + "🧒", + "👦", + "👧", + "🧑", + "👱", + "👨", + "🧔", + "👨‍🦰", + "👨‍🦱", + "👨‍🦳", + "👨‍🦲", + "👩", + "👩‍🦰", + "🧑‍🦰", + "👩‍🦱", + "🧑‍🦱", + "👩‍🦳", + "🧑‍🦳", + "👩‍🦲", + "🧑‍🦲", + "👱‍♀️", + "👱‍♂️", + "🧓", + "👴", + "👵", + "🙍", + "🙍‍♂️", + "🙍‍♀️", + "🙎", + "🙎‍♂️", + "🙎‍♀️", + "🙅", + "🙅‍♂️", + "🙅‍♀️", + "🙆", + "🙆‍♂️", + "🙆‍♀️", + "💁", + "💁‍♂️", + "💁‍♀️", + "🙋", + "🙋‍♂️", + "🙋‍♀️", + "🧏", + "🧏‍♂️", + "🧏‍♀️", + "🙇", + "🙇‍♂️", + "🙇‍♀️", + "🤦", + "🤦‍♂️", + "🤦‍♀️", + "🤷", + "🤷‍♂️", + "🤷‍♀️", + "🧑‍⚕️", + "👨‍⚕️", + "👩‍⚕️", + "🧑‍🎓", + "👨‍🎓", + "👩‍🎓", + "🧑‍🏫", + "👨‍🏫", + "👩‍🏫", + "🧑‍⚖️", + "👨‍⚖️", + "👩‍⚖️", + "🧑‍🌾", + "👨‍🌾", + "👩‍🌾", + "🧑‍🍳", + "👨‍🍳", + "👩‍🍳", + "🧑‍🔧", + "👨‍🔧", + "👩‍🔧", + "🧑‍🏭", + "👨‍🏭", + "👩‍🏭", + "🧑‍💼", + "👨‍💼", + "👩‍💼", + "🧑‍🔬", + "👨‍🔬", + "👩‍🔬", + "🧑‍💻", + "👨‍💻", + "👩‍💻", + "🧑‍🎤", + "👨‍🎤", + "👩‍🎤", + "🧑‍🎨", + "👨‍🎨", + "👩‍🎨", + "🧑‍✈️", + "👨‍✈️", + "👩‍✈️", + "🧑‍🚀", + "👨‍🚀", + "👩‍🚀", + "🧑‍🚒", + "👨‍🚒", + "👩‍🚒", + "👮", + "👮‍♂️", + "👮‍♀️", + "🕵️", + "💂", + "💂‍♂️", + "💂‍♀️", + "👷", + "👷‍♂️", + "👷‍♀️", + "🤴", + "👸", + "👳", + "👳‍♂️", + "👳‍♀️", + "👲", + "🧕", + "🤵", + "🤵‍♂️", + "🤵‍♀️", + "👰", + "👰‍♂️", + "👰‍♀️", + "🤰", + "🤱", + "👩‍🍼", + "👨‍🍼", + "🧑‍🍼", + "👼", + "🎅", + "🤶", + "🧑‍🎄", + "🦸", + "🦸‍♂️", + "🦸‍♀️", + "🦹", + "🦹‍♂️", + "🦹‍♀️", + "🧙", + "🧙‍♂️", + "🧙‍♀️", + "🧚", + "🧚‍♂️", + "🧚‍♀️", + "🧛", + "🧛‍♂️", + "🧛‍♀️", + "🧜", + "🧜‍♂️", + "🧜‍♀️", + "🧝", + "🧝‍♂️", + "🧝‍♀️", + "🧞", + "🧞‍♂️", + "🧞‍♀️", + "🧟", + "🧟‍♂️", + "🧟‍♀️", + "💆", + "💆‍♂️", + "💆‍♀️", + "💇", + "💇‍♂️", + "💇‍♀️", + "🚶", + "🚶‍♂️", + "🚶‍♀️", + "🧍", + "🧍‍♂️", + "🧍‍♀️", + "🧎", + "🧎‍♂️", + "🧎‍♀️", + "🧑‍🦯", + "👨‍🦯", + "👩‍🦯", + "🧑‍🦼", + "👨‍🦼", + "👩‍🦼", + "🧑‍🦽", + "👨‍🦽", + "👩‍🦽", + "🏃", + "🏃‍♂️", + "🏃‍♀️", + "💃", + "🕺", + "🕴️", + "👯", + "👯‍♂️", + "👯‍♀️", + "🧖", + "🧖‍♂️", + "🧖‍♀️", + "🧗", + "🧗‍♂️", + "🧗‍♀️", + "🤺", + "🏇", + "⛷️", + "🏂", + "🏌️", + "🏄", + "🚣", + "🚣‍♂️", + "🚣‍♀️", + "🏊", + "⛹️", + "🏋️", + "🚴", + "🚴‍♂️", + "🚴‍♀️", + "🚵", + "🚵‍♂️", + "🚵‍♀️", + "🤸", + "🤸‍♂️", + "🤸‍♀️", + "🤼", + "🤼‍♂️", + "🤼‍♀️", + "🤽", + "🤽‍♂️", + "🤽‍♀️", + "🤾", + "🤾‍♂️", + "🤾‍♀️", + "🤹", + "🤹‍♂️", + "🤹‍♀️", + "🧘", + "🧘‍♂️", + "🧘‍♀️", + "🛀", + "🛌", + "🧑‍🤝‍🧑", + "👭", + "👫", + "👬", + "💏", + "👪", + "👨‍👩‍👦", + "👨‍👩‍👧", + "👨‍👩‍👧‍👦", + "👨‍👩‍👦‍👦", + "👨‍👩‍👧‍👧", + "👨‍👨‍👦", + "👨‍👨‍👧", + "👨‍👨‍👧‍👦", + "👨‍👨‍👦‍👦", + "👨‍👨‍👧‍👧", + "👩‍👩‍👦", + "👩‍👩‍👧", + "👩‍👩‍👧‍👦", + "👩‍👩‍👦‍👦", + "👩‍👩‍👧‍👧", + "👨‍👦", + "👨‍👦‍👦", + "👨‍👧", + "👨‍👧‍👦", + "👨‍👧‍👧", + "👩‍👦", + "👩‍👦‍👦", + "👩‍👧", + "👩‍👧‍👦", + "👩‍👧‍👧", + "🗣️", + "👤", + "👥", + "👣", + "🐵", + "🐒", + "🦍", + "🦧", + "🐶", + "🐕", + "🦮", + "🐩", + "🐺", + "🦊", + "🦝", + "🐱", + "🐈", + "🐈‍⬛", + "🦁", + "🐯", + "🐅", + "🐆", + "🐴", + "🐎", + "🦄", + "🦓", + "🦌", + "🐮", + "🐂", + "🐃", + "🐄", + "🐷", + "🐖", + "🐗", + "🐽", + "🐏", + "🐑", + "🐐", + "🐪", + "🐫", + "🦙", + "🦒", + "🐘", + "🦏", + "🦛", + "🐭", + "🐁", + "🐀", + "🐹", + "🐰", + "🐇", + "🐿️", + "🦔", + "🦇", + "🐻", + "🐻‍❄️", + "🐨", + "🐼", + "🦥", + "🦦", + "🦨", + "🦘", + "🦡", + "🐾", + "🦃", + "🐔", + "🐓", + "🐣", + "🐤", + "🐥", + "🐦", + "🐧", + "🕊️", + "🦅", + "🦆", + "🦢", + "🦉", + "🦩", + "🦚", + "🦜", + "🐸", + "🐊", + "🐢", + "🦎", + "🐍", + "🐲", + "🐉", + "🦕", + "🦖", + "🐳", + "🐋", + "🐬", + "🐟", + "🐠", + "🐡", + "🦈", + "🐙", + "🐚", + "🐌", + "🦋", + "🐛", + "🐜", + "🐝", + "🐞", + "🦗", + "🕷️", + "🕸️", + "🦂", + "🦟", + "🦠", + "💐", + "🌸", + "💮", + "🏵️", + "🌹", + "🥀", + "🌺", + "🌻", + "🌼", + "🌷", + "🌱", + "🌲", + "🌳", + "🌴", + "🌵", + "🌾", + "🌿", + "☘️", + "🍀", + "🍁", + "🍂", + "🍃", + "🍇", + "🍈", + "🍉", + "🍊", + "🍋", + "🍌", + "🍍", + "🥭", + "🍎", + "🍏", + "🍐", + "🍑", + "🍒", + "🍓", + "🥝", + "🍅", + "🥥", + "🥑", + "🍆", + "🥔", + "🥕", + "🌽", + "🌶️", + "🥒", + "🥬", + "🥦", + "🧄", + "🧅", + "🍄", + "🥜", + "🌰", + "🍞", + "🥐", + "🥖", + "🥨", + "🥯", + "🥞", + "🧇", + "🧀", + "🍖", + "🍗", + "🥩", + "🥓", + "🍔", + "🍟", + "🍕", + "🌭", + "🥪", + "🌮", + "🌯", + "🥙", + "🧆", + "🥚", + "🍳", + "🥘", + "🍲", + "🥣", + "🥗", + "🍿", + "🧈", + "🧂", + "🥫", + "🍱", + "🍘", + "🍙", + "🍚", + "🍛", + "🍜", + "🍝", + "🍠", + "🍢", + "🍣", + "🍤", + "🍥", + "🥮", + "🍡", + "🥟", + "🥠", + "🥡", + "🦀", + "🦞", + "🦐", + "🦑", + "🦪", + "🍦", + "🍧", + "🍨", + "🍩", + "🍪", + "🎂", + "🍰", + "🧁", + "🥧", + "🍫", + "🍬", + "🍭", + "🍮", + "🍯", + "🍼", + "🥛", + "🍵", + "🍶", + "🍾", + "🍷", + "🍸", + "🍹", + "🍺", + "🍻", + "🥂", + "🥃", + "🥤", + "🧃", + "🧉", + "🧊", + "🥢", + "🍽️", + "🍴", + "🥄", + "🔪", + "🏺", + "🌍", + "🌎", + "🌏", + "🌐", + "🗺️", + "🗾", + "🧭", + "🏔️", + "⛰️", + "🌋", + "🗻", + "🏕️", + "🏖️", + "🏜️", + "🏝️", + "🏞️", + "🏟️", + "🏛️", + "🏗️", + "🧱", + "🏘️", + "🏚️", + "🏠", + "🏡", + "🏢", + "🏣", + "🏤", + "🏥", + "🏦", + "🏨", + "🏩", + "🏪", + "🏫", + "🏬", + "🏭", + "🏯", + "🏰", + "💒", + "🗼", + "🗽", + "⛪", + "🕌", + "🛕", + "🕍", + "⛩️", + "🕋", + "⛲", + "⛺", + "🌁", + "🌃", + "🏙️", + "🌄", + "🌅", + "🌆", + "🌇", + "🌉", + "♨️", + "🎠", + "🎡", + "🎢", + "💈", + "🎪", + "🚂", + "🚃", + "🚄", + "🚅", + "🚆", + "🚇", + "🚈", + "🚉", + "🚊", + "🚝", + "🚞", + "🚋", + "🚌", + "🚍", + "🚎", + "🚐", + "🚑", + "🚒", + "🚓", + "🚔", + "🚕", + "🚖", + "🚗", + "🚘", + "🚙", + "🚚", + "🚛", + "🚜", + "🏎️", + "🏍️", + "🛵", + "🦽", + "🦼", + "🛺", + "🚲", + "🛴", + "🛹", + "🚏", + "🛣️", + "🛤️", + "🛢️", + "⛽", + "🚨", + "🚥", + "🚦", + "🛑", + "🚧", + "⚓", + "⛵", + "🛶", + "🚤", + "🛳️", + "⛴️", + "🛥️", + "🚢", + "✈️", + "🛩️", + "🛫", + "🛬", + "🪂", + "💺", + "🚁", + "🚟", + "🚠", + "🚡", + "🛰️", + "🚀", + "🛸", + "🛎️", + "🧳", + "⌛", + "⏳", + "⌚", + "⏰", + "⏱️", + "⏲️", + "🕰️", + "🕛", + "🕧", + "🕐", + "🕜", + "🕑", + "🕝", + "🕒", + "🕞", + "🕓", + "🕟", + "🕔", + "🕠", + "🕕", + "🕡", + "🕖", + "🕢", + "🕗", + "🕣", + "🕘", + "🕤", + "🕙", + "🕥", + "🕚", + "🕦", + "🌑", + "🌒", + "🌓", + "🌔", + "🌕", + "🌖", + "🌗", + "🌘", + "🌙", + "🌚", + "🌛", + "🌜", + "🌡️", + "☀️", + "🌝", + "🌞", + "🪐", + "⭐", + "🌟", + "🌠", + "🌌", + "☁️", + "⛅", + "⛈️", + "🌤️", + "🌥️", + "🌦️", + "🌧️", + "🌨️", + "🌩️", + "🌪️", + "🌫️", + "🌬️", + "🌀", + "🌈", + "🌂", + "☂️", + "☔", + "⛱️", + "⚡", + "❄️", + "☃️", + "⛄", + "☄️", + "🔥", + "💧", + "🌊", + "🎃", + "🎄", + "🎆", + "🎇", + "🧨", + "✨", + "🎈", + "🎉", + "🎊", + "🎋", + "🎍", + "🎎", + "🎏", + "🎐", + "🎑", + "🧧", + "🎀", + "🎁", + "🎗️", + "🎟️", + "🎫", + "🎖️", + "🏆", + "🏅", + "🥇", + "🥈", + "🥉", + "⚽", + "⚾", + "🥎", + "🏀", + "🏐", + "🏈", + "🏉", + "🎾", + "🥏", + "🎳", + "🏏", + "🏑", + "🏒", + "🥍", + "🏓", + "🏸", + "🥊", + "🥋", + "🥅", + "⛳", + "⛸️", + "🎣", + "🤿", + "🎽", + "🎿", + "🛷", + "🥌", + "🎯", + "🪀", + "🪁", + "🎱", + "🔮", + "🧿", + "🎮", + "🕹️", + "🎰", + "🎲", + "🧩", + "🧸", + "♠️", + "♥️", + "♦️", + "♣️", + "♟️", + "🃏", + "🀄", + "🎴", + "🎭", + "🖼️", + "🎨", + "🧵", + "🧶", + "👓", + "🕶️", + "🥽", + "🥼", + "🦺", + "👔", + "👕", + "👖", + "🧣", + "🧤", + "🧥", + "🧦", + "👗", + "👘", + "🥻", + "🩱", + "🩲", + "🩳", + "👙", + "👚", + "👛", + "👜", + "👝", + "🛍️", + "🎒", + "👞", + "👟", + "🥾", + "🥿", + "👠", + "👡", + "🩰", + "👢", + "👑", + "👒", + "🎩", + "🎓", + "🧢", + "⛑️", + "📿", + "💄", + "💍", + "💎", + "🔇", + "🔈", + "🔉", + "🔊", + "📢", + "📣", + "📯", + "🔔", + "🔕", + "🎼", + "🎵", + "🎶", + "🎙️", + "🎚️", + "🎛️", + "🎤", + "🎧", + "📻", + "🎷", + "🎸", + "🎹", + "🎺", + "🎻", + "🪕", + "🥁", + "📱", + "📲", + "☎️", + "📞", + "📟", + "📠", + "🔋", + "🔌", + "💻", + "🖥️", + "🖨️", + "⌨️", + "🖱️", + "🖲️", + "💽", + "💾", + "💿", + "📀", + "🧮", + "🎥", + "🎞️", + "📽️", + "🎬", + "📺", + "📷", + "📸", + "📹", + "📼", + "🔍", + "🔎", + "🕯️", + "💡", + "🔦", + "🏮", + "🪔", + "📔", + "📕", + "📖", + "📗", + "📘", + "📙", + "📚", + "📓", + "📒", + "📃", + "📜", + "📄", + "📰", + "🗞️", + "📑", + "🔖", + "🏷️", + "💰", + "💴", + "💵", + "💶", + "💷", + "💸", + "💳", + "🧾", + "💹", + "✉️", + "📧", + "📨", + "📩", + "📤", + "📥", + "📦", + "📫", + "📪", + "📬", + "📭", + "📮", + "🗳️", + "✏️", + "✒️", + "🖋️", + "🖊️", + "🖌️", + "🖍️", + "📝", + "💼", + "📁", + "📂", + "🗂️", + "📅", + "📆", + "🗒️", + "🗓️", + "📇", + "📈", + "📉", + "📊", + "📋", + "📌", + "📍", + "📎", + "🖇️", + "📏", + "📐", + "✂️", + "🗃️", + "🗄️", + "🗑️", + "🔒", + "🔓", + "🔏", + "🔐", + "🔑", + "🗝️", + "🔨", + "🪓", + "⛏️", + "⚒️", + "🛠️", + "🗡️", + "⚔️", + "🔫", + "🏹", + "🛡️", + "🔧", + "🔩", + "⚙️", + "🗜️", + "⚖️", + "🦯", + "🔗", + "⛓️", + "🧰", + "🧲", + "⚗️", + "🧪", + "🧫", + "🧬", + "🔬", + "🔭", + "📡", + "💉", + "🩸", + "💊", + "🩹", + "🩺", + "🚪", + "🛏️", + "🛋️", + "🪑", + "🚽", + "🚿", + "🛁", + "🪒", + "🧴", + "🧷", + "🧹", + "🧺", + "🧻", + "🧼", + "🧽", + "🧯", + "🛒", + "🚬", + "⚰️", + "⚱️", + "🗿", + "🏧", + "🚮", + "🚰", + "♿", + "🚹", + "🚺", + "🚻", + "🚼", + "🚾", + "🛂", + "🛃", + "🛄", + "🛅", + "⚠️", + "🚸", + "⛔", + "🚫", + "🚳", + "🚭", + "🚯", + "🚱", + "🚷", + "📵", + "🔞", + "☢️", + "☣️", + "⬆️", + "↗️", + "➡️", + "↘️", + "⬇️", + "↙️", + "⬅️", + "↖️", + "↕️", + "↔️", + "↩️", + "↪️", + "⤴️", + "⤵️", + "🔃", + "🔄", + "🔙", + "🔚", + "🔛", + "🔜", + "🔝", + "🛐", + "⚛️", + "🕉️", + "✡️", + "☸️", + "☯️", + "✝️", + "☦️", + "☪️", + "☮️", + "🕎", + "🔯", + "♈", + "♉", + "♊", + "♋", + "♌", + "♍", + "♎", + "♏", + "♐", + "♑", + "♒", + "♓", + "⛎", + "🔀", + "🔁", + "🔂", + "▶️", + "⏩", + "⏭️", + "⏯️", + "◀️", + "⏪", + "⏮️", + "🔼", + "⏫", + "🔽", + "⏬", + "⏸️", + "⏹️", + "⏺️", + "⏏️", + "🎦", + "🔅", + "🔆", + "📶", + "📳", + "📴", + "♀️", + "♂️", + "⚧️", + "✖️", + "➕", + "➖", + "➗", + "♾️", + "‼️", + "⁉️", + "❓", + "❔", + "❕", + "❗", + "〰️", + "💱", + "💲", + "⚕️", + "♻️", + "⚜️", + "🔱", + "📛", + "🔰", + "⭕", + "✅", + "☑️", + "✔️", + "❌", + "❎", + "➰", + "➿", + "〽️", + "✳️", + "✴️", + "❇️", + "©️", + "®️", + "™️", + "#️⃣", + "*️⃣", + "0️⃣", + "1️⃣", + "2️⃣", + "3️⃣", + "4️⃣", + "5️⃣", + "6️⃣", + "7️⃣", + "8️⃣", + "9️⃣", + "🔟", + "🔠", + "🔡", + "🔢", + "🔣", + "🔤", + "🅰️", + "🆎", + "🅱️", + "🆑", + "🆒", + "🆓", + "ℹ️", + "🆔", + "Ⓜ️", + "🆕", + "🆖", + "🅾️", + "🆗", + "🅿️", + "🆘", + "🆙", + "🆚", + "🈁", + "🈂️", + "🈷️", + "🈶", + "🈯", + "🉐", + "🈹", + "🈚", + "🈲", + "🉑", + "🈸", + "🈴", + "🈳", + "㊗️", + "㊙️", + "🈺", + "🈵", + "🔴", + "🟠", + "🟡", + "🟢", + "🔵", + "🟣", + "🟤", + "⚫", + "⚪", + "🟥", + "🟧", + "🟨", + "🟩", + "🟦", + "🟪", + "🟫", + "⬛", + "⬜", + "◼️", + "◻️", + "◾", + "◽", + "▪️", + "▫️", + "🔶", + "🔷", + "🔸", + "🔹", + "🔺", + "🔻", + "💠", + "🔘", + "🔳", + "🔲", + "🏁", + "🚩", + "🎌", + "🏴", + "🏳️", + "🏴‍☠️", + "🇦🇨", + "🇦🇩", + "🇦🇪", + "🇦🇫", + "🇦🇬", + "🇦🇮", + "🇦🇱", + "🇦🇲", + "🇦🇴", + "🇦🇶", + "🇦🇷", + "🇦🇸", + "🇦🇹", + "🇦🇺", + "🇦🇼", + "🇦🇽", + "🇦🇿", + "🇧🇦", + "🇧🇧", + "🇧🇩", + "🇧🇪", + "🇧🇫", + "🇧🇬", + "🇧🇭", + "🇧🇮", + "🇧🇯", + "🇧🇱", + "🇧🇲", + "🇧🇳", + "🇧🇴", + "🇧🇶", + "🇧🇷", + "🇧🇸", + "🇧🇹", + "🇧🇻", + "🇧🇼", + "🇧🇾", + "🇧🇿", + "🇨🇦", + "🇨🇨", + "🇨🇩", + "🇨🇫", + "🇨🇬", + "🇨🇭", + "🇨🇮", + "🇨🇰", + "🇨🇱", + "🇨🇲", + "🇨🇳", + "🇨🇴", + "🇨🇵", + "🇨🇷", + "🇨🇺", + "🇨🇻", + "🇨🇼", + "🇨🇽", + "🇨🇾", + "🇨🇿", + "🇩🇪", + "🇩🇬", + "🇩🇯", + "🇩🇰", + "🇩🇲", + "🇩🇴", + "🇩🇿", + "🇪🇦", + "🇪🇨", + "🇪🇪", + "🇪🇬", + "🇪🇭", + "🇪🇷", + "🇪🇸", + "🇪🇹", + "🇪🇺", + "🇫🇮", + "🇫🇯", + "🇫🇰", + "🇫🇲", + "🇫🇴", + "🇫🇷", + "🇬🇦", + "🇬🇧", + "🇬🇩", + "🇬🇪", + "🇬🇫", + "🇬🇬", + "🇬🇭", + "🇬🇮", + "🇬🇱", + "🇬🇲", + "🇬🇳", + "🇬🇵", + "🇬🇶", + "🇬🇷", + "🇬🇸", + "🇬🇹", + "🇬🇺", + "🇬🇼", + "🇬🇾", + "🇭🇰", + "🇭🇲", + "🇭🇳", + "🇭🇷", + "🇭🇹", + "🇭🇺", + "🇮🇨", + "🇮🇩", + "🇮🇪", + "🇮🇱", + "🇮🇲", + "🇮🇳", + "🇮🇴", + "🇮🇶", + "🇮🇷", + "🇮🇸", + "🇮🇹", + "🇯🇪", + "🇯🇲", + "🇯🇴", + "🇯🇵", + "🇰🇪", + "🇰🇬", + "🇰🇭", + "🇰🇮", + "🇰🇲", + "🇰🇳", + "🇰🇵", + "🇰🇷", + "🇰🇼", + "🇰🇾", + "🇰🇿", + "🇱🇦", + "🇱🇧", + "🇱🇨", + "🇱🇮", + "🇱🇰", + "🇱🇷", + "🇱🇸", + "🇱🇹", + "🇱🇺", + "🇱🇻", + "🇱🇾", + "🇲🇦", + "🇲🇨", + "🇲🇩", + "🇲🇪", + "🇲🇫", + "🇲🇬", + "🇲🇭", + "🇲🇰", + "🇲🇱", + "🇲🇲", + "🇲🇳", + "🇲🇴", + "🇲🇵", + "🇲🇶", + "🇲🇷", + "🇲🇸", + "🇲🇹", + "🇲🇺", + "🇲🇻", + "🇲🇼", + "🇲🇽", + "🇲🇾", + "🇲🇿", + "🇳🇦", + "🇳🇨", + "🇳🇪", + "🇳🇫", + "🇳🇬", + "🇳🇮", + "🇳🇱", + "🇳🇴", + "🇳🇵", + "🇳🇷", + "🇳🇺", + "🇳🇿", + "🇴🇲", + "🇵🇦", + "🇵🇪", + "🇵🇫", + "🇵🇬", + "🇵🇭", + "🇵🇰", + "🇵🇱", + "🇵🇲", + "🇵🇳", + "🇵🇷", + "🇵🇸", + "🇵🇹", + "🇵🇼", + "🇵🇾", + "🇶🇦", + "🇷🇪", + "🇷🇴", + "🇷🇸", + "🇷🇺", + "🇷🇼", + "🇸🇦", + "🇸🇧", + "🇸🇨", + "🇸🇩", + "🇸🇪", + "🇸🇬", + "🇸🇭", + "🇸🇮", + "🇸🇯", + "🇸🇰", + "🇸🇱", + "🇸🇲", + "🇸🇳", + "🇸🇴", + "🇸🇷", + "🇸🇸", + "🇸🇹", + "🇸🇻", + "🇸🇽", + "🇸🇾", + "🇸🇿", + "🇹🇦", + "🇹🇨", + "🇹🇩", + "🇹🇫", + "🇹🇬", + "🇹🇭", + "🇹🇯", + "🇹🇰", + "🇹🇱", + "🇹🇲", + "🇹🇳", + "🇹🇴", + "🇹🇷", + "🇹🇹", + "🇹🇻", + "🇹🇼", + "🇹🇿", + "🇺🇦", + "🇺🇬", + "🇺🇲", + "🇺🇳", + "🇺🇸", + "🇺🇾", + "🇺🇿", + "🇻🇦", + "🇻🇨", + "🇻🇪", + "🇻🇬", + "🇻🇮", + "🇻🇳", + "🇻🇺", + "🇼🇫", + "🇼🇸", + "🇽🇰", + "🇾🇪", + "🇾🇹", + "🇿🇦", + "🇿🇲", + "🇿🇼", + }, + "description": { + "grinning face", + "grinning face with big eyes", + "grinning face with smiling eyes", + "beaming face with smiling eyes", + "grinning squinting face", + "grinning face with sweat", + "rolling on the floor laughing", + "face with tears of joy", + "slightly smiling face", + "upside-down face", + "winking face", + "smiling face with smiling eyes", + "smiling face with halo", + "smiling face with hearts", + "smiling face with heart-eyes", + "star-struck", + "face blowing a kiss", + "kissing face", + "smiling face", + "kissing face with closed eyes", + "kissing face with smiling eyes", + "smiling face with tear", + "face savoring food", + "face with tongue", + "winking face with tongue", + "zany face", + "squinting face with tongue", + "money-mouth face", + "hugging face", + "face with hand over mouth", + "shushing face", + "thinking face", + "zipper-mouth face", + "face with raised eyebrow", + "neutral face", + "expressionless face", + "face without mouth", + "smirking face", + "unamused face", + "face with rolling eyes", + "grimacing face", + "lying face", + "relieved face", + "pensive face", + "sleepy face", + "drooling face", + "sleeping face", + "face with medical mask", + "face with thermometer", + "face with head-bandage", + "nauseated face", + "face vomiting", + "sneezing face", + "hot face", + "cold face", + "woozy face", + "dizzy face", + "exploding head", + "cowboy hat face", + "partying face", + "disguised face", + "smiling face with sunglasses", + "nerd face", + "face with monocle", + "confused face", + "worried face", + "slightly frowning face", + "frowning face", + "face with open mouth", + "hushed face", + "astonished face", + "flushed face", + "pleading face", + "frowning face with open mouth", + "anguished face", + "fearful face", + "anxious face with sweat", + "sad but relieved face", + "crying face", + "loudly crying face", + "face screaming in fear", + "confounded face", + "persevering face", + "disappointed face", + "downcast face with sweat", + "weary face", + "tired face", + "yawning face", + "face with steam from nose", + "pouting face", + "angry face", + "face with symbols on mouth", + "smiling face with horns", + "angry face with horns", + "skull", + "skull and crossbones", + "pile of poo", + "clown face", + "ogre", + "goblin", + "ghost", + "alien", + "alien monster", + "robot", + "grinning cat", + "grinning cat with smiling eyes", + "cat with tears of joy", + "smiling cat with heart-eyes", + "cat with wry smile", + "kissing cat", + "weary cat", + "crying cat", + "pouting cat", + "see-no-evil monkey", + "hear-no-evil monkey", + "speak-no-evil monkey", + "kiss mark", + "love letter", + "heart with arrow", + "heart with ribbon", + "sparkling heart", + "growing heart", + "beating heart", + "revolving hearts", + "two hearts", + "heart decoration", + "heart exclamation", + "broken heart", + "red heart", + "orange heart", + "yellow heart", + "green heart", + "blue heart", + "purple heart", + "brown heart", + "black heart", + "white heart", + "hundred points", + "anger symbol", + "collision", + "dizzy", + "sweat droplets", + "dashing away", + "hole", + "bomb", + "speech balloon", + "eye in speech bubble", + "left speech bubble", + "right anger bubble", + "thought balloon", + "zzz", + "waving hand", + "raised back of hand", + "hand with fingers splayed", + "raised hand", + "vulcan salute", + "OK hand", + "pinched fingers", + "pinching hand", + "victory hand", + "crossed fingers", + "love-you gesture", + "sign of the horns", + "call me hand", + "backhand index pointing left", + "backhand index pointing right", + "backhand index pointing up", + "middle finger", + "backhand index pointing down", + "index pointing up", + "thumbs up", + "thumbs down", + "raised fist", + "oncoming fist", + "left-facing fist", + "right-facing fist", + "clapping hands", + "raising hands", + "open hands", + "palms up together", + "handshake", + "folded hands", + "writing hand", + "nail polish", + "selfie", + "flexed biceps", + "mechanical arm", + "mechanical leg", + "leg", + "foot", + "ear", + "ear with hearing aid", + "nose", + "brain", + "anatomical heart", + "lungs", + "tooth", + "bone", + "eyes", + "eye", + "tongue", + "mouth", + "baby", + "child", + "boy", + "girl", + "person", + "person: blond hair", + "man", + "man: beard", + "man: red hair", + "man: curly hair", + "man: white hair", + "man: bald", + "woman", + "woman: red hair", + "person: red hair", + "woman: curly hair", + "person: curly hair", + "woman: white hair", + "person: white hair", + "woman: bald", + "person: bald", + "woman: blond hair", + "man: blond hair", + "older person", + "old man", + "old woman", + "person frowning", + "man frowning", + "woman frowning", + "person pouting", + "man pouting", + "woman pouting", + "person gesturing NO", + "man gesturing NO", + "woman gesturing NO", + "person gesturing OK", + "man gesturing OK", + "woman gesturing OK", + "person tipping hand", + "man tipping hand", + "woman tipping hand", + "person raising hand", + "man raising hand", + "woman raising hand", + "deaf person", + "deaf man", + "deaf woman", + "person bowing", + "man bowing", + "woman bowing", + "person facepalming", + "man facepalming", + "woman facepalming", + "person shrugging", + "man shrugging", + "woman shrugging", + "health worker", + "man health worker", + "woman health worker", + "student", + "man student", + "woman student", + "teacher", + "man teacher", + "woman teacher", + "judge", + "man judge", + "woman judge", + "farmer", + "man farmer", + "woman farmer", + "cook", + "man cook", + "woman cook", + "mechanic", + "man mechanic", + "woman mechanic", + "factory worker", + "man factory worker", + "woman factory worker", + "office worker", + "man office worker", + "woman office worker", + "scientist", + "man scientist", + "woman scientist", + "technologist", + "man technologist", + "woman technologist", + "singer", + "man singer", + "woman singer", + "artist", + "man artist", + "woman artist", + "pilot", + "man pilot", + "woman pilot", + "astronaut", + "man astronaut", + "woman astronaut", + "firefighter", + "man firefighter", + "woman firefighter", + "police officer", + "man police officer", + "woman police officer", + "detective", + "man detective", + "woman detective", + "guard", + "man guard", + "woman guard", + "ninja", + "construction worker", + "man construction worker", + "woman construction worker", + "prince", + "princess", + "person wearing turban", + "man wearing turban", + "woman wearing turban", + "person with skullcap", + "woman with headscarf", + "person in tuxedo", + "man in tuxedo", + "woman in tuxedo", + "person with veil", + "man with veil", + "woman with veil", + "pregnant woman", + "breast-feeding", + "woman feeding baby", + "man feeding baby", + "person feeding baby", + "baby angel", + "Santa Claus", + "Mrs. Claus", + "mx claus", + "superhero", + "man superhero", + "woman superhero", + "supervillain", + "man supervillain", + "woman supervillain", + "mage", + "man mage", + "woman mage", + "fairy", + "man fairy", + "woman fairy", + "vampire", + "man vampire", + "woman vampire", + "merperson", + "merman", + "mermaid", + "elf", + "man elf", + "woman elf", + "genie", + "man genie", + "woman genie", + "zombie", + "man zombie", + "woman zombie", + "person getting massage", + "man getting massage", + "woman getting massage", + "person getting haircut", + "man getting haircut", + "woman getting haircut", + "person walking", + "man walking", + "woman walking", + "person standing", + "man standing", + "woman standing", + "person kneeling", + "man kneeling", + "woman kneeling", + "person with white cane", + "man with white cane", + "woman with white cane", + "person in motorized wheelchair", + "man in motorized wheelchair", + "woman in motorized wheelchair", + "person in manual wheelchair", + "man in manual wheelchair", + "woman in manual wheelchair", + "person running", + "man running", + "woman running", + "woman dancing", + "man dancing", + "person in suit levitating", + "people with bunny ears", + "men with bunny ears", + "women with bunny ears", + "person in steamy room", + "man in steamy room", + "woman in steamy room", + "person climbing", + "man climbing", + "woman climbing", + "person fencing", + "horse racing", + "skier", + "snowboarder", + "person golfing", + "man golfing", + "woman golfing", + "person surfing", + "man surfing", + "woman surfing", + "person rowing boat", + "man rowing boat", + "woman rowing boat", + "person swimming", + "man swimming", + "woman swimming", + "person bouncing ball", + "man bouncing ball", + "woman bouncing ball", + "person lifting weights", + "man lifting weights", + "woman lifting weights", + "person biking", + "man biking", + "woman biking", + "person mountain biking", + "man mountain biking", + "woman mountain biking", + "person cartwheeling", + "man cartwheeling", + "woman cartwheeling", + "people wrestling", + "men wrestling", + "women wrestling", + "person playing water polo", + "man playing water polo", + "woman playing water polo", + "person playing handball", + "man playing handball", + "woman playing handball", + "person juggling", + "man juggling", + "woman juggling", + "person in lotus position", + "man in lotus position", + "woman in lotus position", + "person taking bath", + "person in bed", + "people holding hands", + "women holding hands", + "woman and man holding hands", + "men holding hands", + "kiss", + "kiss: woman, man", + "kiss: man, man", + "kiss: woman, woman", + "couple with heart", + "couple with heart: woman, man", + "couple with heart: man, man", + "couple with heart: woman, woman", + "family", + "family: man, woman, boy", + "family: man, woman, girl", + "family: man, woman, girl, boy", + "family: man, woman, boy, boy", + "family: man, woman, girl, girl", + "family: man, man, boy", + "family: man, man, girl", + "family: man, man, girl, boy", + "family: man, man, boy, boy", + "family: man, man, girl, girl", + "family: woman, woman, boy", + "family: woman, woman, girl", + "family: woman, woman, girl, boy", + "family: woman, woman, boy, boy", + "family: woman, woman, girl, girl", + "family: man, boy", + "family: man, boy, boy", + "family: man, girl", + "family: man, girl, boy", + "family: man, girl, girl", + "family: woman, boy", + "family: woman, boy, boy", + "family: woman, girl", + "family: woman, girl, boy", + "family: woman, girl, girl", + "speaking head", + "bust in silhouette", + "busts in silhouette", + "people hugging", + "footprints", + "monkey face", + "monkey", + "gorilla", + "orangutan", + "dog face", + "dog", + "guide dog", + "service dog", + "poodle", + "wolf", + "fox", + "raccoon", + "cat face", + "cat", + "black cat", + "lion", + "tiger face", + "tiger", + "leopard", + "horse face", + "horse", + "unicorn", + "zebra", + "deer", + "bison", + "cow face", + "ox", + "water buffalo", + "cow", + "pig face", + "pig", + "boar", + "pig nose", + "ram", + "ewe", + "goat", + "camel", + "two-hump camel", + "llama", + "giraffe", + "elephant", + "mammoth", + "rhinoceros", + "hippopotamus", + "mouse face", + "mouse", + "rat", + "hamster", + "rabbit face", + "rabbit", + "chipmunk", + "beaver", + "hedgehog", + "bat", + "bear", + "polar bear", + "koala", + "panda", + "sloth", + "otter", + "skunk", + "kangaroo", + "badger", + "paw prints", + "turkey", + "chicken", + "rooster", + "hatching chick", + "baby chick", + "front-facing baby chick", + "bird", + "penguin", + "dove", + "eagle", + "duck", + "swan", + "owl", + "dodo", + "feather", + "flamingo", + "peacock", + "parrot", + "frog", + "crocodile", + "turtle", + "lizard", + "snake", + "dragon face", + "dragon", + "sauropod", + "T-Rex", + "spouting whale", + "whale", + "dolphin", + "seal", + "fish", + "tropical fish", + "blowfish", + "shark", + "octopus", + "spiral shell", + "snail", + "butterfly", + "bug", + "ant", + "honeybee", + "beetle", + "lady beetle", + "cricket", + "cockroach", + "spider", + "spider web", + "scorpion", + "mosquito", + "fly", + "worm", + "microbe", + "bouquet", + "cherry blossom", + "white flower", + "rosette", + "rose", + "wilted flower", + "hibiscus", + "sunflower", + "blossom", + "tulip", + "seedling", + "potted plant", + "evergreen tree", + "deciduous tree", + "palm tree", + "cactus", + "sheaf of rice", + "herb", + "shamrock", + "four leaf clover", + "maple leaf", + "fallen leaf", + "leaf fluttering in wind", + "grapes", + "melon", + "watermelon", + "tangerine", + "lemon", + "banana", + "pineapple", + "mango", + "red apple", + "green apple", + "pear", + "peach", + "cherries", + "strawberry", + "blueberries", + "kiwi fruit", + "tomato", + "olive", + "coconut", + "avocado", + "eggplant", + "potato", + "carrot", + "ear of corn", + "hot pepper", + "bell pepper", + "cucumber", + "leafy green", + "broccoli", + "garlic", + "onion", + "mushroom", + "peanuts", + "chestnut", + "bread", + "croissant", + "baguette bread", + "flatbread", + "pretzel", + "bagel", + "pancakes", + "waffle", + "cheese wedge", + "meat on bone", + "poultry leg", + "cut of meat", + "bacon", + "hamburger", + "french fries", + "pizza", + "hot dog", + "sandwich", + "taco", + "burrito", + "tamale", + "stuffed flatbread", + "falafel", + "egg", + "cooking", + "shallow pan of food", + "pot of food", + "fondue", + "bowl with spoon", + "green salad", + "popcorn", + "butter", + "salt", + "canned food", + "bento box", + "rice cracker", + "rice ball", + "cooked rice", + "curry rice", + "steaming bowl", + "spaghetti", + "roasted sweet potato", + "oden", + "sushi", + "fried shrimp", + "fish cake with swirl", + "moon cake", + "dango", + "dumpling", + "fortune cookie", + "takeout box", + "crab", + "lobster", + "shrimp", + "squid", + "oyster", + "soft ice cream", + "shaved ice", + "ice cream", + "doughnut", + "cookie", + "birthday cake", + "shortcake", + "cupcake", + "pie", + "chocolate bar", + "candy", + "lollipop", + "custard", + "honey pot", + "baby bottle", + "glass of milk", + "hot beverage", + "teapot", + "teacup without handle", + "sake", + "bottle with popping cork", + "wine glass", + "cocktail glass", + "tropical drink", + "beer mug", + "clinking beer mugs", + "clinking glasses", + "tumbler glass", + "cup with straw", + "bubble tea", + "beverage box", + "mate", + "ice", + "chopsticks", + "fork and knife with plate", + "fork and knife", + "spoon", + "kitchen knife", + "amphora", + "globe showing Europe-Africa", + "globe showing Americas", + "globe showing Asia-Australia", + "globe with meridians", + "world map", + "map of Japan", + "compass", + "snow-capped mountain", + "mountain", + "volcano", + "mount fuji", + "camping", + "beach with umbrella", + "desert", + "desert island", + "national park", + "stadium", + "classical building", + "building construction", + "brick", + "rock", + "wood", + "hut", + "houses", + "derelict house", + "house", + "house with garden", + "office building", + "Japanese post office", + "post office", + "hospital", + "bank", + "hotel", + "love hotel", + "convenience store", + "school", + "department store", + "factory", + "Japanese castle", + "castle", + "wedding", + "Tokyo tower", + "Statue of Liberty", + "church", + "mosque", + "hindu temple", + "synagogue", + "shinto shrine", + "kaaba", + "fountain", + "tent", + "foggy", + "night with stars", + "cityscape", + "sunrise over mountains", + "sunrise", + "cityscape at dusk", + "sunset", + "bridge at night", + "hot springs", + "carousel horse", + "ferris wheel", + "roller coaster", + "barber pole", + "circus tent", + "locomotive", + "railway car", + "high-speed train", + "bullet train", + "train", + "metro", + "light rail", + "station", + "tram", + "monorail", + "mountain railway", + "tram car", + "bus", + "oncoming bus", + "trolleybus", + "minibus", + "ambulance", + "fire engine", + "police car", + "oncoming police car", + "taxi", + "oncoming taxi", + "automobile", + "oncoming automobile", + "sport utility vehicle", + "pickup truck", + "delivery truck", + "articulated lorry", + "tractor", + "racing car", + "motorcycle", + "motor scooter", + "manual wheelchair", + "motorized wheelchair", + "auto rickshaw", + "bicycle", + "kick scooter", + "skateboard", + "roller skate", + "bus stop", + "motorway", + "railway track", + "oil drum", + "fuel pump", + "police car light", + "horizontal traffic light", + "vertical traffic light", + "stop sign", + "construction", + "anchor", + "sailboat", + "canoe", + "speedboat", + "passenger ship", + "ferry", + "motor boat", + "ship", + "airplane", + "small airplane", + "airplane departure", + "airplane arrival", + "parachute", + "seat", + "helicopter", + "suspension railway", + "mountain cableway", + "aerial tramway", + "satellite", + "rocket", + "flying saucer", + "bellhop bell", + "luggage", + "hourglass done", + "hourglass not done", + "watch", + "alarm clock", + "stopwatch", + "timer clock", + "mantelpiece clock", + "twelve o’clock", + "twelve-thirty", + "one o’clock", + "one-thirty", + "two o’clock", + "two-thirty", + "three o’clock", + "three-thirty", + "four o’clock", + "four-thirty", + "five o’clock", + "five-thirty", + "six o’clock", + "six-thirty", + "seven o’clock", + "seven-thirty", + "eight o’clock", + "eight-thirty", + "nine o’clock", + "nine-thirty", + "ten o’clock", + "ten-thirty", + "eleven o’clock", + "eleven-thirty", + "new moon", + "waxing crescent moon", + "first quarter moon", + "waxing gibbous moon", + "full moon", + "waning gibbous moon", + "last quarter moon", + "waning crescent moon", + "crescent moon", + "new moon face", + "first quarter moon face", + "last quarter moon face", + "thermometer", + "sun", + "full moon face", + "sun with face", + "ringed planet", + "star", + "glowing star", + "shooting star", + "milky way", + "cloud", + "sun behind cloud", + "cloud with lightning and rain", + "sun behind small cloud", + "sun behind large cloud", + "sun behind rain cloud", + "cloud with rain", + "cloud with snow", + "cloud with lightning", + "tornado", + "fog", + "wind face", + "cyclone", + "rainbow", + "closed umbrella", + "umbrella", + "umbrella with rain drops", + "umbrella on ground", + "high voltage", + "snowflake", + "snowman", + "snowman without snow", + "comet", + "fire", + "droplet", + "water wave", + "jack-o-lantern", + "Christmas tree", + "fireworks", + "sparkler", + "firecracker", + "sparkles", + "balloon", + "party popper", + "confetti ball", + "tanabata tree", + "pine decoration", + "Japanese dolls", + "carp streamer", + "wind chime", + "moon viewing ceremony", + "red envelope", + "ribbon", + "wrapped gift", + "reminder ribbon", + "admission tickets", + "ticket", + "military medal", + "trophy", + "sports medal", + "1st place medal", + "2nd place medal", + "3rd place medal", + "soccer ball", + "baseball", + "softball", + "basketball", + "volleyball", + "american football", + "rugby football", + "tennis", + "flying disc", + "bowling", + "cricket game", + "field hockey", + "ice hockey", + "lacrosse", + "ping pong", + "badminton", + "boxing glove", + "martial arts uniform", + "goal net", + "flag in hole", + "ice skate", + "fishing pole", + "diving mask", + "running shirt", + "skis", + "sled", + "curling stone", + "direct hit", + "yo-yo", + "kite", + "pool 8 ball", + "crystal ball", + "magic wand", + "nazar amulet", + "video game", + "joystick", + "slot machine", + "game die", + "puzzle piece", + "teddy bear", + "piñata", + "nesting dolls", + "spade suit", + "heart suit", + "diamond suit", + "club suit", + "chess pawn", + "joker", + "mahjong red dragon", + "flower playing cards", + "performing arts", + "framed picture", + "artist palette", + "thread", + "sewing needle", + "yarn", + "knot", + "glasses", + "sunglasses", + "goggles", + "lab coat", + "safety vest", + "necktie", + "t-shirt", + "jeans", + "scarf", + "gloves", + "coat", + "socks", + "dress", + "kimono", + "sari", + "one-piece swimsuit", + "briefs", + "shorts", + "bikini", + "woman’s clothes", + "purse", + "handbag", + "clutch bag", + "shopping bags", + "backpack", + "thong sandal", + "man’s shoe", + "running shoe", + "hiking boot", + "flat shoe", + "high-heeled shoe", + "woman’s sandal", + "ballet shoes", + "woman’s boot", + "crown", + "woman’s hat", + "top hat", + "graduation cap", + "billed cap", + "military helmet", + "rescue worker’s helmet", + "prayer beads", + "lipstick", + "ring", + "gem stone", + "muted speaker", + "speaker low volume", + "speaker medium volume", + "speaker high volume", + "loudspeaker", + "megaphone", + "postal horn", + "bell", + "bell with slash", + "musical score", + "musical note", + "musical notes", + "studio microphone", + "level slider", + "control knobs", + "microphone", + "headphone", + "radio", + "saxophone", + "accordion", + "guitar", + "musical keyboard", + "trumpet", + "violin", + "banjo", + "drum", + "long drum", + "mobile phone", + "mobile phone with arrow", + "telephone", + "telephone receiver", + "pager", + "fax machine", + "battery", + "electric plug", + "laptop", + "desktop computer", + "printer", + "keyboard", + "computer mouse", + "trackball", + "computer disk", + "floppy disk", + "optical disk", + "dvd", + "abacus", + "movie camera", + "film frames", + "film projector", + "clapper board", + "television", + "camera", + "camera with flash", + "video camera", + "videocassette", + "magnifying glass tilted left", + "magnifying glass tilted right", + "candle", + "light bulb", + "flashlight", + "red paper lantern", + "diya lamp", + "notebook with decorative cover", + "closed book", + "open book", + "green book", + "blue book", + "orange book", + "books", + "notebook", + "ledger", + "page with curl", + "scroll", + "page facing up", + "newspaper", + "rolled-up newspaper", + "bookmark tabs", + "bookmark", + "label", + "money bag", + "coin", + "yen banknote", + "dollar banknote", + "euro banknote", + "pound banknote", + "money with wings", + "credit card", + "receipt", + "chart increasing with yen", + "envelope", + "e-mail", + "incoming envelope", + "envelope with arrow", + "outbox tray", + "inbox tray", + "package", + "closed mailbox with raised flag", + "closed mailbox with lowered flag", + "open mailbox with raised flag", + "open mailbox with lowered flag", + "postbox", + "ballot box with ballot", + "pencil", + "black nib", + "fountain pen", + "pen", + "paintbrush", + "crayon", + "memo", + "briefcase", + "file folder", + "open file folder", + "card index dividers", + "calendar", + "tear-off calendar", + "spiral notepad", + "spiral calendar", + "card index", + "chart increasing", + "chart decreasing", + "bar chart", + "clipboard", + "pushpin", + "round pushpin", + "paperclip", + "linked paperclips", + "straight ruler", + "triangular ruler", + "scissors", + "card file box", + "file cabinet", + "wastebasket", + "locked", + "unlocked", + "locked with pen", + "locked with key", + "key", + "old key", + "hammer", + "axe", + "pick", + "hammer and pick", + "hammer and wrench", + "dagger", + "crossed swords", + "pistol", + "boomerang", + "bow and arrow", + "shield", + "carpentry saw", + "wrench", + "screwdriver", + "nut and bolt", + "gear", + "clamp", + "balance scale", + "white cane", + "link", + "chains", + "hook", + "toolbox", + "magnet", + "ladder", + "alembic", + "test tube", + "petri dish", + "dna", + "microscope", + "telescope", + "satellite antenna", + "syringe", + "drop of blood", + "pill", + "adhesive bandage", + "stethoscope", + "door", + "elevator", + "mirror", + "window", + "bed", + "couch and lamp", + "chair", + "toilet", + "plunger", + "shower", + "bathtub", + "mouse trap", + "razor", + "lotion bottle", + "safety pin", + "broom", + "basket", + "roll of paper", + "bucket", + "soap", + "toothbrush", + "sponge", + "fire extinguisher", + "shopping cart", + "cigarette", + "coffin", + "headstone", + "funeral urn", + "moai", + "placard", + "ATM sign", + "litter in bin sign", + "potable water", + "wheelchair symbol", + "men’s room", + "women’s room", + "restroom", + "baby symbol", + "water closet", + "passport control", + "customs", + "baggage claim", + "left luggage", + "warning", + "children crossing", + "no entry", + "prohibited", + "no bicycles", + "no smoking", + "no littering", + "non-potable water", + "no pedestrians", + "no mobile phones", + "no one under eighteen", + "radioactive", + "biohazard", + "up arrow", + "up-right arrow", + "right arrow", + "down-right arrow", + "down arrow", + "down-left arrow", + "left arrow", + "up-left arrow", + "up-down arrow", + "left-right arrow", + "right arrow curving left", + "left arrow curving right", + "right arrow curving up", + "right arrow curving down", + "clockwise vertical arrows", + "counterclockwise arrows button", + "BACK arrow", + "END arrow", + "ON! arrow", + "SOON arrow", + "TOP arrow", + "place of worship", + "atom symbol", + "om", + "star of David", + "wheel of dharma", + "yin yang", + "latin cross", + "orthodox cross", + "star and crescent", + "peace symbol", + "menorah", + "dotted six-pointed star", + "Aries", + "Taurus", + "Gemini", + "Cancer", + "Leo", + "Virgo", + "Libra", + "Scorpio", + "Sagittarius", + "Capricorn", + "Aquarius", + "Pisces", + "Ophiuchus", + "shuffle tracks button", + "repeat button", + "repeat single button", + "play button", + "fast-forward button", + "next track button", + "play or pause button", + "reverse button", + "fast reverse button", + "last track button", + "upwards button", + "fast up button", + "downwards button", + "fast down button", + "pause button", + "stop button", + "record button", + "eject button", + "cinema", + "dim button", + "bright button", + "antenna bars", + "vibration mode", + "mobile phone off", + "female sign", + "male sign", + "transgender symbol", + "multiply", + "plus", + "minus", + "divide", + "infinity", + "double exclamation mark", + "exclamation question mark", + "question mark", + "white question mark", + "white exclamation mark", + "exclamation mark", + "wavy dash", + "currency exchange", + "heavy dollar sign", + "medical symbol", + "recycling symbol", + "fleur-de-lis", + "trident emblem", + "name badge", + "Japanese symbol for beginner", + "hollow red circle", + "check mark button", + "check box with check", + "check mark", + "cross mark", + "cross mark button", + "curly loop", + "double curly loop", + "part alternation mark", + "eight-spoked asterisk", + "eight-pointed star", + "sparkle", + "copyright", + "registered", + "trade mark", + "keycap: #", + "keycap: *", + "keycap: 0", + "keycap: 1", + "keycap: 2", + "keycap: 3", + "keycap: 4", + "keycap: 5", + "keycap: 6", + "keycap: 7", + "keycap: 8", + "keycap: 9", + "keycap: 10", + "input latin uppercase", + "input latin lowercase", + "input numbers", + "input symbols", + "input latin letters", + "A button (blood type)", + "AB button (blood type)", + "B button (blood type)", + "CL button", + "COOL button", + "FREE button", + "information", + "ID button", + "circled M", + "NEW button", + "NG button", + "O button (blood type)", + "OK button", + "P button", + "SOS button", + "UP! button", + "VS button", + "Japanese “here” button", + "Japanese “service charge” button", + "Japanese “monthly amount” button", + "Japanese “not free of charge” button", + "Japanese “reserved” button", + "Japanese “bargain” button", + "Japanese “discount” button", + "Japanese “free of charge” button", + "Japanese “prohibited” button", + "Japanese “acceptable” button", + "Japanese “application” button", + "Japanese “passing grade” button", + "Japanese “vacancy” button", + "Japanese “congratulations” button", + "Japanese “secret” button", + "Japanese “open for business” button", + "Japanese “no vacancy” button", + "red circle", + "orange circle", + "yellow circle", + "green circle", + "blue circle", + "purple circle", + "brown circle", + "black circle", + "white circle", + "red square", + "orange square", + "yellow square", + "green square", + "blue square", + "purple square", + "brown square", + "black large square", + "white large square", + "black medium square", + "white medium square", + "black medium-small square", + "white medium-small square", + "black small square", + "white small square", + "large orange diamond", + "large blue diamond", + "small orange diamond", + "small blue diamond", + "red triangle pointed up", + "red triangle pointed down", + "diamond with a dot", + "radio button", + "white square button", + "black square button", + "chequered flag", + "triangular flag", + "crossed flags", + "black flag", + "white flag", + "rainbow flag", + "transgender flag", + "pirate flag", + "flag: Ascension Island", + "flag: Andorra", + "flag: United Arab Emirates", + "flag: Afghanistan", + "flag: Antigua & Barbuda", + "flag: Anguilla", + "flag: Albania", + "flag: Armenia", + "flag: Angola", + "flag: Antarctica", + "flag: Argentina", + "flag: American Samoa", + "flag: Austria", + "flag: Australia", + "flag: Aruba", + "flag: Åland Islands", + "flag: Azerbaijan", + "flag: Bosnia & Herzegovina", + "flag: Barbados", + "flag: Bangladesh", + "flag: Belgium", + "flag: Burkina Faso", + "flag: Bulgaria", + "flag: Bahrain", + "flag: Burundi", + "flag: Benin", + "flag: St. Barthélemy", + "flag: Bermuda", + "flag: Brunei", + "flag: Bolivia", + "flag: Caribbean Netherlands", + "flag: Brazil", + "flag: Bahamas", + "flag: Bhutan", + "flag: Bouvet Island", + "flag: Botswana", + "flag: Belarus", + "flag: Belize", + "flag: Canada", + "flag: Cocos (Keeling) Islands", + "flag: Congo - Kinshasa", + "flag: Central African Republic", + "flag: Congo - Brazzaville", + "flag: Switzerland", + "flag: Côte d’Ivoire", + "flag: Cook Islands", + "flag: Chile", + "flag: Cameroon", + "flag: China", + "flag: Colombia", + "flag: Clipperton Island", + "flag: Costa Rica", + "flag: Cuba", + "flag: Cape Verde", + "flag: Curaçao", + "flag: Christmas Island", + "flag: Cyprus", + "flag: Czechia", + "flag: Germany", + "flag: Diego Garcia", + "flag: Djibouti", + "flag: Denmark", + "flag: Dominica", + "flag: Dominican Republic", + "flag: Algeria", + "flag: Ceuta & Melilla", + "flag: Ecuador", + "flag: Estonia", + "flag: Egypt", + "flag: Western Sahara", + "flag: Eritrea", + "flag: Spain", + "flag: Ethiopia", + "flag: European Union", + "flag: Finland", + "flag: Fiji", + "flag: Falkland Islands", + "flag: Micronesia", + "flag: Faroe Islands", + "flag: France", + "flag: Gabon", + "flag: United Kingdom", + "flag: Grenada", + "flag: Georgia", + "flag: French Guiana", + "flag: Guernsey", + "flag: Ghana", + "flag: Gibraltar", + "flag: Greenland", + "flag: Gambia", + "flag: Guinea", + "flag: Guadeloupe", + "flag: Equatorial Guinea", + "flag: Greece", + "flag: South Georgia & South Sandwich Islands", + "flag: Guatemala", + "flag: Guam", + "flag: Guinea-Bissau", + "flag: Guyana", + "flag: Hong Kong SAR China", + "flag: Heard & McDonald Islands", + "flag: Honduras", + "flag: Croatia", + "flag: Haiti", + "flag: Hungary", + "flag: Canary Islands", + "flag: Indonesia", + "flag: Ireland", + "flag: Israel", + "flag: Isle of Man", + "flag: India", + "flag: British Indian Ocean Territory", + "flag: Iraq", + "flag: Iran", + "flag: Iceland", + "flag: Italy", + "flag: Jersey", + "flag: Jamaica", + "flag: Jordan", + "flag: Japan", + "flag: Kenya", + "flag: Kyrgyzstan", + "flag: Cambodia", + "flag: Kiribati", + "flag: Comoros", + "flag: St. Kitts & Nevis", + "flag: North Korea", + "flag: South Korea", + "flag: Kuwait", + "flag: Cayman Islands", + "flag: Kazakhstan", + "flag: Laos", + "flag: Lebanon", + "flag: St. Lucia", + "flag: Liechtenstein", + "flag: Sri Lanka", + "flag: Liberia", + "flag: Lesotho", + "flag: Lithuania", + "flag: Luxembourg", + "flag: Latvia", + "flag: Libya", + "flag: Morocco", + "flag: Monaco", + "flag: Moldova", + "flag: Montenegro", + "flag: St. Martin", + "flag: Madagascar", + "flag: Marshall Islands", + "flag: North Macedonia", + "flag: Mali", + "flag: Myanmar (Burma)", + "flag: Mongolia", + "flag: Macao SAR China", + "flag: Northern Mariana Islands", + "flag: Martinique", + "flag: Mauritania", + "flag: Montserrat", + "flag: Malta", + "flag: Mauritius", + "flag: Maldives", + "flag: Malawi", + "flag: Mexico", + "flag: Malaysia", + "flag: Mozambique", + "flag: Namibia", + "flag: New Caledonia", + "flag: Niger", + "flag: Norfolk Island", + "flag: Nigeria", + "flag: Nicaragua", + "flag: Netherlands", + "flag: Norway", + "flag: Nepal", + "flag: Nauru", + "flag: Niue", + "flag: New Zealand", + "flag: Oman", + "flag: Panama", + "flag: Peru", + "flag: French Polynesia", + "flag: Papua New Guinea", + "flag: Philippines", + "flag: Pakistan", + "flag: Poland", + "flag: St. Pierre & Miquelon", + "flag: Pitcairn Islands", + "flag: Puerto Rico", + "flag: Palestinian Territories", + "flag: Portugal", + "flag: Palau", + "flag: Paraguay", + "flag: Qatar", + "flag: Réunion", + "flag: Romania", + "flag: Serbia", + "flag: Russia", + "flag: Rwanda", + "flag: Saudi Arabia", + "flag: Solomon Islands", + "flag: Seychelles", + "flag: Sudan", + "flag: Sweden", + "flag: Singapore", + "flag: St. Helena", + "flag: Slovenia", + "flag: Svalbard & Jan Mayen", + "flag: Slovakia", + "flag: Sierra Leone", + "flag: San Marino", + "flag: Senegal", + "flag: Somalia", + "flag: Suriname", + "flag: South Sudan", + "flag: São Tomé & Príncipe", + "flag: El Salvador", + "flag: Sint Maarten", + "flag: Syria", + "flag: Eswatini", + "flag: Tristan da Cunha", + "flag: Turks & Caicos Islands", + "flag: Chad", + "flag: French Southern Territories", + "flag: Togo", + "flag: Thailand", + "flag: Tajikistan", + "flag: Tokelau", + "flag: Timor-Leste", + "flag: Turkmenistan", + "flag: Tunisia", + "flag: Tonga", + "flag: Turkey", + "flag: Trinidad & Tobago", + "flag: Tuvalu", + "flag: Taiwan", + "flag: Tanzania", + "flag: Ukraine", + "flag: Uganda", + "flag: U.S. Outlying Islands", + "flag: United Nations", + "flag: United States", + "flag: Uruguay", + "flag: Uzbekistan", + "flag: Vatican City", + "flag: St. Vincent & Grenadines", + "flag: Venezuela", + "flag: British Virgin Islands", + "flag: U.S. Virgin Islands", + "flag: Vietnam", + "flag: Vanuatu", + "flag: Wallis & Futuna", + "flag: Samoa", + "flag: Kosovo", + "flag: Yemen", + "flag: Mayotte", + "flag: South Africa", + "flag: Zambia", + "flag: Zimbabwe", + "flag: England", + "flag: Scotland", + "flag: Wales", + }, + "category": { + "Smileys & Emotion", + "People & Body", + "Animals & Nature", + "Food & Drink", + "Travel & Places", + "Activities", + "Objects", + "Symbols", + "Flags", + }, + "alias": { + "grinning", + "smiley", + "smile", + "grin", + "laughing", + "satisfied", + "sweat_smile", + "rofl", + "joy", + "slightly_smiling_face", + "upside_down_face", + "wink", + "blush", + "innocent", + "smiling_face_with_three_hearts", + "heart_eyes", + "star_struck", + "kissing_heart", + "kissing", + "relaxed", + "kissing_closed_eyes", + "kissing_smiling_eyes", + "smiling_face_with_tear", + "yum", + "stuck_out_tongue", + "stuck_out_tongue_winking_eye", + "zany_face", + "stuck_out_tongue_closed_eyes", + "money_mouth_face", + "hugs", + "hand_over_mouth", + "shushing_face", + "thinking", + "zipper_mouth_face", + "raised_eyebrow", + "neutral_face", + "expressionless", + "no_mouth", + "smirk", + "unamused", + "roll_eyes", + "grimacing", + "lying_face", + "relieved", + "pensive", + "sleepy", + "drooling_face", + "sleeping", + "mask", + "face_with_thermometer", + "face_with_head_bandage", + "nauseated_face", + "vomiting_face", + "sneezing_face", + "hot_face", + "cold_face", + "woozy_face", + "dizzy_face", + "exploding_head", + "cowboy_hat_face", + "partying_face", + "disguised_face", + "sunglasses", + "nerd_face", + "monocle_face", + "confused", + "worried", + "slightly_frowning_face", + "frowning_face", + "open_mouth", + "hushed", + "astonished", + "flushed", + "pleading_face", + "frowning", + "anguished", + "fearful", + "cold_sweat", + "disappointed_relieved", + "cry", + "sob", + "scream", + "confounded", + "persevere", + "disappointed", + "sweat", + "weary", + "tired_face", + "yawning_face", + "triumph", + "rage", + "pout", + "angry", + "cursing_face", + "smiling_imp", + "imp", + "skull", + "skull_and_crossbones", + "hankey", + "poop", + "shit", + "clown_face", + "japanese_ogre", + "japanese_goblin", + "ghost", + "alien", + "space_invader", + "robot", + "smiley_cat", + "smile_cat", + "joy_cat", + "heart_eyes_cat", + "smirk_cat", + "kissing_cat", + "scream_cat", + "crying_cat_face", + "pouting_cat", + "see_no_evil", + "hear_no_evil", + "speak_no_evil", + "kiss", + "love_letter", + "cupid", + "gift_heart", + "sparkling_heart", + "heartpulse", + "heartbeat", + "revolving_hearts", + "two_hearts", + "heart_decoration", + "heavy_heart_exclamation", + "broken_heart", + "heart", + "orange_heart", + "yellow_heart", + "green_heart", + "blue_heart", + "purple_heart", + "brown_heart", + "black_heart", + "white_heart", + "100", + "anger", + "boom", + "collision", + "dizzy", + "sweat_drops", + "dash", + "hole", + "bomb", + "speech_balloon", + "eye_speech_bubble", + "left_speech_bubble", + "right_anger_bubble", + "thought_balloon", + "zzz", + "wave", + "raised_back_of_hand", + "raised_hand_with_fingers_splayed", + "hand", + "raised_hand", + "vulcan_salute", + "ok_hand", + "pinched_fingers", + "pinching_hand", + "v", + "crossed_fingers", + "love_you_gesture", + "metal", + "call_me_hand", + "point_left", + "point_right", + "point_up_2", + "middle_finger", + "fu", + "point_down", + "point_up", + "+1", + "thumbsup", + "-1", + "thumbsdown", + "fist_raised", + "fist", + "fist_oncoming", + "facepunch", + "punch", + "fist_left", + "fist_right", + "clap", + "raised_hands", + "open_hands", + "palms_up_together", + "handshake", + "pray", + "writing_hand", + "nail_care", + "selfie", + "muscle", + "mechanical_arm", + "mechanical_leg", + "leg", + "foot", + "ear", + "ear_with_hearing_aid", + "nose", + "brain", + "anatomical_heart", + "lungs", + "tooth", + "bone", + "eyes", + "eye", + "tongue", + "lips", + "baby", + "child", + "boy", + "girl", + "adult", + "blond_haired_person", + "man", + "bearded_person", + "red_haired_man", + "curly_haired_man", + "white_haired_man", + "bald_man", + "woman", + "red_haired_woman", + "person_red_hair", + "curly_haired_woman", + "person_curly_hair", + "white_haired_woman", + "person_white_hair", + "bald_woman", + "person_bald", + "blond_haired_woman", + "blonde_woman", + "blond_haired_man", + "older_adult", + "older_man", + "older_woman", + "frowning_person", + "frowning_man", + "frowning_woman", + "pouting_face", + "pouting_man", + "pouting_woman", + "no_good", + "no_good_man", + "ng_man", + "no_good_woman", + "ng_woman", + "ok_person", + "ok_man", + "ok_woman", + "tipping_hand_person", + "information_desk_person", + "tipping_hand_man", + "sassy_man", + "tipping_hand_woman", + "sassy_woman", + "raising_hand", + "raising_hand_man", + "raising_hand_woman", + "deaf_person", + "deaf_man", + "deaf_woman", + "bow", + "bowing_man", + "bowing_woman", + "facepalm", + "man_facepalming", + "woman_facepalming", + "shrug", + "man_shrugging", + "woman_shrugging", + "health_worker", + "man_health_worker", + "woman_health_worker", + "student", + "man_student", + "woman_student", + "teacher", + "man_teacher", + "woman_teacher", + "judge", + "man_judge", + "woman_judge", + "farmer", + "man_farmer", + "woman_farmer", + "cook", + "man_cook", + "woman_cook", + "mechanic", + "man_mechanic", + "woman_mechanic", + "factory_worker", + "man_factory_worker", + "woman_factory_worker", + "office_worker", + "man_office_worker", + "woman_office_worker", + "scientist", + "man_scientist", + "woman_scientist", + "technologist", + "man_technologist", + "woman_technologist", + "singer", + "man_singer", + "woman_singer", + "artist", + "man_artist", + "woman_artist", + "pilot", + "man_pilot", + "woman_pilot", + "astronaut", + "man_astronaut", + "woman_astronaut", + "firefighter", + "man_firefighter", + "woman_firefighter", + "police_officer", + "cop", + "policeman", + "policewoman", + "detective", + "male_detective", + "female_detective", + "guard", + "guardsman", + "guardswoman", + "ninja", + "construction_worker", + "construction_worker_man", + "construction_worker_woman", + "prince", + "princess", + "person_with_turban", + "man_with_turban", + "woman_with_turban", + "man_with_gua_pi_mao", + "woman_with_headscarf", + "person_in_tuxedo", + "man_in_tuxedo", + "woman_in_tuxedo", + "person_with_veil", + "man_with_veil", + "woman_with_veil", + "bride_with_veil", + "pregnant_woman", + "breast_feeding", + "woman_feeding_baby", + "man_feeding_baby", + "person_feeding_baby", + "angel", + "santa", + "mrs_claus", + "mx_claus", + "superhero", + "superhero_man", + "superhero_woman", + "supervillain", + "supervillain_man", + "supervillain_woman", + "mage", + "mage_man", + "mage_woman", + "fairy", + "fairy_man", + "fairy_woman", + "vampire", + "vampire_man", + "vampire_woman", + "merperson", + "merman", + "mermaid", + "elf", + "elf_man", + "elf_woman", + "genie", + "genie_man", + "genie_woman", + "zombie", + "zombie_man", + "zombie_woman", + "massage", + "massage_man", + "massage_woman", + "haircut", + "haircut_man", + "haircut_woman", + "walking", + "walking_man", + "walking_woman", + "standing_person", + "standing_man", + "standing_woman", + "kneeling_person", + "kneeling_man", + "kneeling_woman", + "person_with_probing_cane", + "man_with_probing_cane", + "woman_with_probing_cane", + "person_in_motorized_wheelchair", + "man_in_motorized_wheelchair", + "woman_in_motorized_wheelchair", + "person_in_manual_wheelchair", + "man_in_manual_wheelchair", + "woman_in_manual_wheelchair", + "runner", + "running", + "running_man", + "running_woman", + "woman_dancing", + "dancer", + "man_dancing", + "business_suit_levitating", + "dancers", + "dancing_men", + "dancing_women", + "sauna_person", + "sauna_man", + "sauna_woman", + "climbing", + "climbing_man", + "climbing_woman", + "person_fencing", + "horse_racing", + "skier", + "snowboarder", + "golfing", + "golfing_man", + "golfing_woman", + "surfer", + "surfing_man", + "surfing_woman", + "rowboat", + "rowing_man", + "rowing_woman", + "swimmer", + "swimming_man", + "swimming_woman", + "bouncing_ball_person", + "bouncing_ball_man", + "basketball_man", + "bouncing_ball_woman", + "basketball_woman", + "weight_lifting", + "weight_lifting_man", + "weight_lifting_woman", + "bicyclist", + "biking_man", + "biking_woman", + "mountain_bicyclist", + "mountain_biking_man", + "mountain_biking_woman", + "cartwheeling", + "man_cartwheeling", + "woman_cartwheeling", + "wrestling", + "men_wrestling", + "women_wrestling", + "water_polo", + "man_playing_water_polo", + "woman_playing_water_polo", + "handball_person", + "man_playing_handball", + "woman_playing_handball", + "juggling_person", + "man_juggling", + "woman_juggling", + "lotus_position", + "lotus_position_man", + "lotus_position_woman", + "bath", + "sleeping_bed", + "people_holding_hands", + "two_women_holding_hands", + "couple", + "two_men_holding_hands", + "couplekiss", + "couplekiss_man_woman", + "couplekiss_man_man", + "couplekiss_woman_woman", + "couple_with_heart", + "couple_with_heart_woman_man", + "couple_with_heart_man_man", + "couple_with_heart_woman_woman", + "family", + "family_man_woman_boy", + "family_man_woman_girl", + "family_man_woman_girl_boy", + "family_man_woman_boy_boy", + "family_man_woman_girl_girl", + "family_man_man_boy", + "family_man_man_girl", + "family_man_man_girl_boy", + "family_man_man_boy_boy", + "family_man_man_girl_girl", + "family_woman_woman_boy", + "family_woman_woman_girl", + "family_woman_woman_girl_boy", + "family_woman_woman_boy_boy", + "family_woman_woman_girl_girl", + "family_man_boy", + "family_man_boy_boy", + "family_man_girl", + "family_man_girl_boy", + "family_man_girl_girl", + "family_woman_boy", + "family_woman_boy_boy", + "family_woman_girl", + "family_woman_girl_boy", + "family_woman_girl_girl", + "speaking_head", + "bust_in_silhouette", + "busts_in_silhouette", + "people_hugging", + "footprints", + "monkey_face", + "monkey", + "gorilla", + "orangutan", + "dog", + "dog2", + "guide_dog", + "service_dog", + "poodle", + "wolf", + "fox_face", + "raccoon", + "cat", + "cat2", + "black_cat", + "lion", + "tiger", + "tiger2", + "leopard", + "horse", + "racehorse", + "unicorn", + "zebra", + "deer", + "bison", + "cow", + "ox", + "water_buffalo", + "cow2", + "pig", + "pig2", + "boar", + "pig_nose", + "ram", + "sheep", + "goat", + "dromedary_camel", + "camel", + "llama", + "giraffe", + "elephant", + "mammoth", + "rhinoceros", + "hippopotamus", + "mouse", + "mouse2", + "rat", + "hamster", + "rabbit", + "rabbit2", + "chipmunk", + "beaver", + "hedgehog", + "bat", + "bear", + "polar_bear", + "koala", + "panda_face", + "sloth", + "otter", + "skunk", + "kangaroo", + "badger", + "feet", + "paw_prints", + "turkey", + "chicken", + "rooster", + "hatching_chick", + "baby_chick", + "hatched_chick", + "bird", + "penguin", + "dove", + "eagle", + "duck", + "swan", + "owl", + "dodo", + "feather", + "flamingo", + "peacock", + "parrot", + "frog", + "crocodile", + "turtle", + "lizard", + "snake", + "dragon_face", + "dragon", + "sauropod", + "t-rex", + "whale", + "whale2", + "dolphin", + "flipper", + "seal", + "fish", + "tropical_fish", + "blowfish", + "shark", + "octopus", + "shell", + "snail", + "butterfly", + "bug", + "ant", + "bee", + "honeybee", + "beetle", + "lady_beetle", + "cricket", + "cockroach", + "spider", + "spider_web", + "scorpion", + "mosquito", + "fly", + "worm", + "microbe", + "bouquet", + "cherry_blossom", + "white_flower", + "rosette", + "rose", + "wilted_flower", + "hibiscus", + "sunflower", + "blossom", + "tulip", + "seedling", + "potted_plant", + "evergreen_tree", + "deciduous_tree", + "palm_tree", + "cactus", + "ear_of_rice", + "herb", + "shamrock", + "four_leaf_clover", + "maple_leaf", + "fallen_leaf", + "leaves", + "grapes", + "melon", + "watermelon", + "tangerine", + "orange", + "mandarin", + "lemon", + "banana", + "pineapple", + "mango", + "apple", + "green_apple", + "pear", + "peach", + "cherries", + "strawberry", + "blueberries", + "kiwi_fruit", + "tomato", + "olive", + "coconut", + "avocado", + "eggplant", + "potato", + "carrot", + "corn", + "hot_pepper", + "bell_pepper", + "cucumber", + "leafy_green", + "broccoli", + "garlic", + "onion", + "mushroom", + "peanuts", + "chestnut", + "bread", + "croissant", + "baguette_bread", + "flatbread", + "pretzel", + "bagel", + "pancakes", + "waffle", + "cheese", + "meat_on_bone", + "poultry_leg", + "cut_of_meat", + "bacon", + "hamburger", + "fries", + "pizza", + "hotdog", + "sandwich", + "taco", + "burrito", + "tamale", + "stuffed_flatbread", + "falafel", + "egg", + "fried_egg", + "shallow_pan_of_food", + "stew", + "fondue", + "bowl_with_spoon", + "green_salad", + "popcorn", + "butter", + "salt", + "canned_food", + "bento", + "rice_cracker", + "rice_ball", + "rice", + "curry", + "ramen", + "spaghetti", + "sweet_potato", + "oden", + "sushi", + "fried_shrimp", + "fish_cake", + "moon_cake", + "dango", + "dumpling", + "fortune_cookie", + "takeout_box", + "crab", + "lobster", + "shrimp", + "squid", + "oyster", + "icecream", + "shaved_ice", + "ice_cream", + "doughnut", + "cookie", + "birthday", + "cake", + "cupcake", + "pie", + "chocolate_bar", + "candy", + "lollipop", + "custard", + "honey_pot", + "baby_bottle", + "milk_glass", + "coffee", + "teapot", + "tea", + "sake", + "champagne", + "wine_glass", + "cocktail", + "tropical_drink", + "beer", + "beers", + "clinking_glasses", + "tumbler_glass", + "cup_with_straw", + "bubble_tea", + "beverage_box", + "mate", + "ice_cube", + "chopsticks", + "plate_with_cutlery", + "fork_and_knife", + "spoon", + "hocho", + "knife", + "amphora", + "earth_africa", + "earth_americas", + "earth_asia", + "globe_with_meridians", + "world_map", + "japan", + "compass", + "mountain_snow", + "mountain", + "volcano", + "mount_fuji", + "camping", + "beach_umbrella", + "desert", + "desert_island", + "national_park", + "stadium", + "classical_building", + "building_construction", + "bricks", + "rock", + "wood", + "hut", + "houses", + "derelict_house", + "house", + "house_with_garden", + "office", + "post_office", + "european_post_office", + "hospital", + "bank", + "hotel", + "love_hotel", + "convenience_store", + "school", + "department_store", + "factory", + "japanese_castle", + "european_castle", + "wedding", + "tokyo_tower", + "statue_of_liberty", + "church", + "mosque", + "hindu_temple", + "synagogue", + "shinto_shrine", + "kaaba", + "fountain", + "tent", + "foggy", + "night_with_stars", + "cityscape", + "sunrise_over_mountains", + "sunrise", + "city_sunset", + "city_sunrise", + "bridge_at_night", + "hotsprings", + "carousel_horse", + "ferris_wheel", + "roller_coaster", + "barber", + "circus_tent", + "steam_locomotive", + "railway_car", + "bullettrain_side", + "bullettrain_front", + "train2", + "metro", + "light_rail", + "station", + "tram", + "monorail", + "mountain_railway", + "train", + "bus", + "oncoming_bus", + "trolleybus", + "minibus", + "ambulance", + "fire_engine", + "police_car", + "oncoming_police_car", + "taxi", + "oncoming_taxi", + "car", + "red_car", + "oncoming_automobile", + "blue_car", + "pickup_truck", + "truck", + "articulated_lorry", + "tractor", + "racing_car", + "motorcycle", + "motor_scooter", + "manual_wheelchair", + "motorized_wheelchair", + "auto_rickshaw", + "bike", + "kick_scooter", + "skateboard", + "roller_skate", + "busstop", + "motorway", + "railway_track", + "oil_drum", + "fuelpump", + "rotating_light", + "traffic_light", + "vertical_traffic_light", + "stop_sign", + "construction", + "anchor", + "boat", + "sailboat", + "canoe", + "speedboat", + "passenger_ship", + "ferry", + "motor_boat", + "ship", + "airplane", + "small_airplane", + "flight_departure", + "flight_arrival", + "parachute", + "seat", + "helicopter", + "suspension_railway", + "mountain_cableway", + "aerial_tramway", + "artificial_satellite", + "rocket", + "flying_saucer", + "bellhop_bell", + "luggage", + "hourglass", + "hourglass_flowing_sand", + "watch", + "alarm_clock", + "stopwatch", + "timer_clock", + "mantelpiece_clock", + "clock12", + "clock1230", + "clock1", + "clock130", + "clock2", + "clock230", + "clock3", + "clock330", + "clock4", + "clock430", + "clock5", + "clock530", + "clock6", + "clock630", + "clock7", + "clock730", + "clock8", + "clock830", + "clock9", + "clock930", + "clock10", + "clock1030", + "clock11", + "clock1130", + "new_moon", + "waxing_crescent_moon", + "first_quarter_moon", + "moon", + "waxing_gibbous_moon", + "full_moon", + "waning_gibbous_moon", + "last_quarter_moon", + "waning_crescent_moon", + "crescent_moon", + "new_moon_with_face", + "first_quarter_moon_with_face", + "last_quarter_moon_with_face", + "thermometer", + "sunny", + "full_moon_with_face", + "sun_with_face", + "ringed_planet", + "star", + "star2", + "stars", + "milky_way", + "cloud", + "partly_sunny", + "cloud_with_lightning_and_rain", + "sun_behind_small_cloud", + "sun_behind_large_cloud", + "sun_behind_rain_cloud", + "cloud_with_rain", + "cloud_with_snow", + "cloud_with_lightning", + "tornado", + "fog", + "wind_face", + "cyclone", + "rainbow", + "closed_umbrella", + "open_umbrella", + "umbrella", + "parasol_on_ground", + "zap", + "snowflake", + "snowman_with_snow", + "snowman", + "comet", + "fire", + "droplet", + "ocean", + "jack_o_lantern", + "christmas_tree", + "fireworks", + "sparkler", + "firecracker", + "sparkles", + "balloon", + "tada", + "confetti_ball", + "tanabata_tree", + "bamboo", + "dolls", + "flags", + "wind_chime", + "rice_scene", + "red_envelope", + "ribbon", + "gift", + "reminder_ribbon", + "tickets", + "ticket", + "medal_military", + "trophy", + "medal_sports", + "1st_place_medal", + "2nd_place_medal", + "3rd_place_medal", + "soccer", + "baseball", + "softball", + "basketball", + "volleyball", + "football", + "rugby_football", + "tennis", + "flying_disc", + "bowling", + "cricket_game", + "field_hockey", + "ice_hockey", + "lacrosse", + "ping_pong", + "badminton", + "boxing_glove", + "martial_arts_uniform", + "goal_net", + "golf", + "ice_skate", + "fishing_pole_and_fish", + "diving_mask", + "running_shirt_with_sash", + "ski", + "sled", + "curling_stone", + "dart", + "yo_yo", + "kite", + "8ball", + "crystal_ball", + "magic_wand", + "nazar_amulet", + "video_game", + "joystick", + "slot_machine", + "game_die", + "jigsaw", + "teddy_bear", + "pi_ata", + "nesting_dolls", + "spades", + "hearts", + "diamonds", + "clubs", + "chess_pawn", + "black_joker", + "mahjong", + "flower_playing_cards", + "performing_arts", + "framed_picture", + "art", + "thread", + "sewing_needle", + "yarn", + "knot", + "eyeglasses", + "dark_sunglasses", + "goggles", + "lab_coat", + "safety_vest", + "necktie", + "shirt", + "tshirt", + "jeans", + "scarf", + "gloves", + "coat", + "socks", + "dress", + "kimono", + "sari", + "one_piece_swimsuit", + "swim_brief", + "shorts", + "bikini", + "womans_clothes", + "purse", + "handbag", + "pouch", + "shopping", + "school_satchel", + "thong_sandal", + "mans_shoe", + "shoe", + "athletic_shoe", + "hiking_boot", + "flat_shoe", + "high_heel", + "sandal", + "ballet_shoes", + "boot", + "crown", + "womans_hat", + "tophat", + "mortar_board", + "billed_cap", + "military_helmet", + "rescue_worker_helmet", + "prayer_beads", + "lipstick", + "ring", + "gem", + "mute", + "speaker", + "sound", + "loud_sound", + "loudspeaker", + "mega", + "postal_horn", + "bell", + "no_bell", + "musical_score", + "musical_note", + "notes", + "studio_microphone", + "level_slider", + "control_knobs", + "microphone", + "headphones", + "radio", + "saxophone", + "accordion", + "guitar", + "musical_keyboard", + "trumpet", + "violin", + "banjo", + "drum", + "long_drum", + "iphone", + "calling", + "phone", + "telephone", + "telephone_receiver", + "pager", + "fax", + "battery", + "electric_plug", + "computer", + "desktop_computer", + "printer", + "keyboard", + "computer_mouse", + "trackball", + "minidisc", + "floppy_disk", + "cd", + "dvd", + "abacus", + "movie_camera", + "film_strip", + "film_projector", + "clapper", + "tv", + "camera", + "camera_flash", + "video_camera", + "vhs", + "mag", + "mag_right", + "candle", + "bulb", + "flashlight", + "izakaya_lantern", + "lantern", + "diya_lamp", + "notebook_with_decorative_cover", + "closed_book", + "book", + "open_book", + "green_book", + "blue_book", + "orange_book", + "books", + "notebook", + "ledger", + "page_with_curl", + "scroll", + "page_facing_up", + "newspaper", + "newspaper_roll", + "bookmark_tabs", + "bookmark", + "label", + "moneybag", + "coin", + "yen", + "dollar", + "euro", + "pound", + "money_with_wings", + "credit_card", + "receipt", + "chart", + "email", + "envelope", + "e-mail", + "incoming_envelope", + "envelope_with_arrow", + "outbox_tray", + "inbox_tray", + "package", + "mailbox", + "mailbox_closed", + "mailbox_with_mail", + "mailbox_with_no_mail", + "postbox", + "ballot_box", + "pencil2", + "black_nib", + "fountain_pen", + "pen", + "paintbrush", + "crayon", + "memo", + "pencil", + "briefcase", + "file_folder", + "open_file_folder", + "card_index_dividers", + "date", + "calendar", + "spiral_notepad", + "spiral_calendar", + "card_index", + "chart_with_upwards_trend", + "chart_with_downwards_trend", + "bar_chart", + "clipboard", + "pushpin", + "round_pushpin", + "paperclip", + "paperclips", + "straight_ruler", + "triangular_ruler", + "scissors", + "card_file_box", + "file_cabinet", + "wastebasket", + "lock", + "unlock", + "lock_with_ink_pen", + "closed_lock_with_key", + "key", + "old_key", + "hammer", + "axe", + "pick", + "hammer_and_pick", + "hammer_and_wrench", + "dagger", + "crossed_swords", + "gun", + "boomerang", + "bow_and_arrow", + "shield", + "carpentry_saw", + "wrench", + "screwdriver", + "nut_and_bolt", + "gear", + "clamp", + "balance_scale", + "probing_cane", + "link", + "chains", + "hook", + "toolbox", + "magnet", + "ladder", + "alembic", + "test_tube", + "petri_dish", + "dna", + "microscope", + "telescope", + "satellite", + "syringe", + "drop_of_blood", + "pill", + "adhesive_bandage", + "stethoscope", + "door", + "elevator", + "mirror", + "window", + "bed", + "couch_and_lamp", + "chair", + "toilet", + "plunger", + "shower", + "bathtub", + "mouse_trap", + "razor", + "lotion_bottle", + "safety_pin", + "broom", + "basket", + "roll_of_paper", + "bucket", + "soap", + "toothbrush", + "sponge", + "fire_extinguisher", + "shopping_cart", + "smoking", + "coffin", + "headstone", + "funeral_urn", + "moyai", + "placard", + "atm", + "put_litter_in_its_place", + "potable_water", + "wheelchair", + "mens", + "womens", + "restroom", + "baby_symbol", + "wc", + "passport_control", + "customs", + "baggage_claim", + "left_luggage", + "warning", + "children_crossing", + "no_entry", + "no_entry_sign", + "no_bicycles", + "no_smoking", + "do_not_litter", + "non-potable_water", + "no_pedestrians", + "no_mobile_phones", + "underage", + "radioactive", + "biohazard", + "arrow_up", + "arrow_upper_right", + "arrow_right", + "arrow_lower_right", + "arrow_down", + "arrow_lower_left", + "arrow_left", + "arrow_upper_left", + "arrow_up_down", + "left_right_arrow", + "leftwards_arrow_with_hook", + "arrow_right_hook", + "arrow_heading_up", + "arrow_heading_down", + "arrows_clockwise", + "arrows_counterclockwise", + "back", + "end", + "on", + "soon", + "top", + "place_of_worship", + "atom_symbol", + "om", + "star_of_david", + "wheel_of_dharma", + "yin_yang", + "latin_cross", + "orthodox_cross", + "star_and_crescent", + "peace_symbol", + "menorah", + "six_pointed_star", + "aries", + "taurus", + "gemini", + "cancer", + "leo", + "virgo", + "libra", + "scorpius", + "sagittarius", + "capricorn", + "aquarius", + "pisces", + "ophiuchus", + "twisted_rightwards_arrows", + "repeat", + "repeat_one", + "arrow_forward", + "fast_forward", + "next_track_button", + "play_or_pause_button", + "arrow_backward", + "rewind", + "previous_track_button", + "arrow_up_small", + "arrow_double_up", + "arrow_down_small", + "arrow_double_down", + "pause_button", + "stop_button", + "record_button", + "eject_button", + "cinema", + "low_brightness", + "high_brightness", + "signal_strength", + "vibration_mode", + "mobile_phone_off", + "female_sign", + "male_sign", + "transgender_symbol", + "heavy_multiplication_x", + "heavy_plus_sign", + "heavy_minus_sign", + "heavy_division_sign", + "infinity", + "bangbang", + "interrobang", + "question", + "grey_question", + "grey_exclamation", + "exclamation", + "heavy_exclamation_mark", + "wavy_dash", + "currency_exchange", + "heavy_dollar_sign", + "medical_symbol", + "recycle", + "fleur_de_lis", + "trident", + "name_badge", + "beginner", + "o", + "white_check_mark", + "ballot_box_with_check", + "heavy_check_mark", + "x", + "negative_squared_cross_mark", + "curly_loop", + "loop", + "part_alternation_mark", + "eight_spoked_asterisk", + "eight_pointed_black_star", + "sparkle", + "copyright", + "registered", + "tm", + "hash", + "asterisk", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "keycap_ten", + "capital_abcd", + "abcd", + "1234", + "symbols", + "abc", + "a", + "ab", + "b", + "cl", + "cool", + "free", + "information_source", + "id", + "m", + "new", + "ng", + "o2", + "ok", + "parking", + "sos", + "up", + "vs", + "koko", + "sa", + "u6708", + "u6709", + "u6307", + "ideograph_advantage", + "u5272", + "u7121", + "u7981", + "accept", + "u7533", + "u5408", + "u7a7a", + "congratulations", + "secret", + "u55b6", + "u6e80", + "red_circle", + "orange_circle", + "yellow_circle", + "green_circle", + "large_blue_circle", + "purple_circle", + "brown_circle", + "black_circle", + "white_circle", + "red_square", + "orange_square", + "yellow_square", + "green_square", + "blue_square", + "purple_square", + "brown_square", + "black_large_square", + "white_large_square", + "black_medium_square", + "white_medium_square", + "black_medium_small_square", + "white_medium_small_square", + "black_small_square", + "white_small_square", + "large_orange_diamond", + "large_blue_diamond", + "small_orange_diamond", + "small_blue_diamond", + "small_red_triangle", + "small_red_triangle_down", + "diamond_shape_with_a_dot_inside", + "radio_button", + "white_square_button", + "black_square_button", + "checkered_flag", + "triangular_flag_on_post", + "crossed_flags", + "black_flag", + "white_flag", + "rainbow_flag", + "transgender_flag", + "pirate_flag", + "ascension_island", + "andorra", + "united_arab_emirates", + "afghanistan", + "antigua_barbuda", + "anguilla", + "albania", + "armenia", + "angola", + "antarctica", + "argentina", + "american_samoa", + "austria", + "australia", + "aruba", + "aland_islands", + "azerbaijan", + "bosnia_herzegovina", + "barbados", + "bangladesh", + "belgium", + "burkina_faso", + "bulgaria", + "bahrain", + "burundi", + "benin", + "st_barthelemy", + "bermuda", + "brunei", + "bolivia", + "caribbean_netherlands", + "brazil", + "bahamas", + "bhutan", + "bouvet_island", + "botswana", + "belarus", + "belize", + "canada", + "cocos_islands", + "congo_kinshasa", + "central_african_republic", + "congo_brazzaville", + "switzerland", + "cote_divoire", + "cook_islands", + "chile", + "cameroon", + "cn", + "colombia", + "clipperton_island", + "costa_rica", + "cuba", + "cape_verde", + "curacao", + "christmas_island", + "cyprus", + "czech_republic", + "de", + "diego_garcia", + "djibouti", + "denmark", + "dominica", + "dominican_republic", + "algeria", + "ceuta_melilla", + "ecuador", + "estonia", + "egypt", + "western_sahara", + "eritrea", + "es", + "ethiopia", + "eu", + "european_union", + "finland", + "fiji", + "falkland_islands", + "micronesia", + "faroe_islands", + "fr", + "gabon", + "gb", + "uk", + "grenada", + "georgia", + "french_guiana", + "guernsey", + "ghana", + "gibraltar", + "greenland", + "gambia", + "guinea", + "guadeloupe", + "equatorial_guinea", + "greece", + "south_georgia_south_sandwich_islands", + "guatemala", + "guam", + "guinea_bissau", + "guyana", + "hong_kong", + "heard_mcdonald_islands", + "honduras", + "croatia", + "haiti", + "hungary", + "canary_islands", + "indonesia", + "ireland", + "israel", + "isle_of_man", + "india", + "british_indian_ocean_territory", + "iraq", + "iran", + "iceland", + "it", + "jersey", + "jamaica", + "jordan", + "jp", + "kenya", + "kyrgyzstan", + "cambodia", + "kiribati", + "comoros", + "st_kitts_nevis", + "north_korea", + "kr", + "kuwait", + "cayman_islands", + "kazakhstan", + "laos", + "lebanon", + "st_lucia", + "liechtenstein", + "sri_lanka", + "liberia", + "lesotho", + "lithuania", + "luxembourg", + "latvia", + "libya", + "morocco", + "monaco", + "moldova", + "montenegro", + "st_martin", + "madagascar", + "marshall_islands", + "macedonia", + "mali", + "myanmar", + "mongolia", + "macau", + "northern_mariana_islands", + "martinique", + "mauritania", + "montserrat", + "malta", + "mauritius", + "maldives", + "malawi", + "mexico", + "malaysia", + "mozambique", + "namibia", + "new_caledonia", + "niger", + "norfolk_island", + "nigeria", + "nicaragua", + "netherlands", + "norway", + "nepal", + "nauru", + "niue", + "new_zealand", + "oman", + "panama", + "peru", + "french_polynesia", + "papua_new_guinea", + "philippines", + "pakistan", + "poland", + "st_pierre_miquelon", + "pitcairn_islands", + "puerto_rico", + "palestinian_territories", + "portugal", + "palau", + "paraguay", + "qatar", + "reunion", + "romania", + "serbia", + "ru", + "rwanda", + "saudi_arabia", + "solomon_islands", + "seychelles", + "sudan", + "sweden", + "singapore", + "st_helena", + "slovenia", + "svalbard_jan_mayen", + "slovakia", + "sierra_leone", + "san_marino", + "senegal", + "somalia", + "suriname", + "south_sudan", + "sao_tome_principe", + "el_salvador", + "sint_maarten", + "syria", + "swaziland", + "tristan_da_cunha", + "turks_caicos_islands", + "chad", + "french_southern_territories", + "togo", + "thailand", + "tajikistan", + "tokelau", + "timor_leste", + "turkmenistan", + "tunisia", + "tonga", + "tr", + "trinidad_tobago", + "tuvalu", + "taiwan", + "tanzania", + "ukraine", + "uganda", + "us_outlying_islands", + "united_nations", + "us", + "uruguay", + "uzbekistan", + "vatican_city", + "st_vincent_grenadines", + "venezuela", + "british_virgin_islands", + "us_virgin_islands", + "vietnam", + "vanuatu", + "wallis_futuna", + "samoa", + "kosovo", + "yemen", + "mayotte", + "south_africa", + "zambia", + "zimbabwe", + "england", + "scotland", + "wales", + }, + "tag": { + "smile", + "happy", + "joy", + "haha", + "laugh", + "pleased", + "hot", + "lol", + "laughing", + "tears", + "flirt", + "proud", + "angel", + "love", + "crush", + "eyes", + "blush", + "tongue", + "lick", + "prank", + "silly", + "goofy", + "wacky", + "rich", + "quiet", + "whoops", + "silence", + "hush", + "suspicious", + "meh", + "mute", + "smug", + "liar", + "whew", + "tired", + "zzz", + "sick", + "ill", + "hurt", + "barf", + "disgusted", + "achoo", + "heat", + "sweating", + "freezing", + "ice", + "groggy", + "mind", + "blown", + "celebration", + "birthday", + "cool", + "geek", + "glasses", + "nervous", + "surprise", + "impressed", + "wow", + "speechless", + "amazed", + "gasp", + "puppy", + "stunned", + "scared", + "shocked", + "oops", + "phew", + "sweat", + "sad", + "tear", + "cry", + "bawling", + "horror", + "struggling", + "upset", + "whine", + "angry", + "mad", + "annoyed", + "foul", + "devil", + "evil", + "horns", + "dead", + "danger", + "poison", + "pirate", + "crap", + "monster", + "halloween", + "ufo", + "game", + "retro", + "monkey", + "blind", + "ignore", + "deaf", + "lipstick", + "email", + "envelope", + "heart", + "chocolates", + "score", + "perfect", + "explode", + "star", + "water", + "workout", + "wind", + "blow", + "fast", + "boom", + "comment", + "thinking", + "sleeping", + "goodbye", + "highfive", + "stop", + "prosper", + "spock", + "victory", + "peace", + "luck", + "hopeful", + "approve", + "ok", + "disapprove", + "bury", + "power", + "attack", + "praise", + "applause", + "hooray", + "deal", + "please", + "hope", + "wish", + "beauty", + "manicure", + "flex", + "bicep", + "strong", + "hear", + "sound", + "listen", + "smell", + "look", + "see", + "watch", + "taste", + "kiss", + "child", + "newborn", + "mustache", + "father", + "dad", + "girls", + "halt", + "denied", + "information", + "respect", + "thanks", + "doctor", + "nurse", + "graduation", + "school", + "professor", + "justice", + "chef", + "business", + "research", + "coder", + "rockstar", + "painter", + "space", + "law", + "cop", + "sleuth", + "helmet", + "crown", + "royal", + "hijab", + "groom", + "marriage", + "wedding", + "nursing", + "christmas", + "santa", + "wizard", + "spa", + "exercise", + "marathon", + "dress", + "dancer", + "bunny", + "steamy", + "bouldering", + "basketball", + "gym", + "meditation", + "shower", + "couple", + "date", + "home", + "parents", + "user", + "users", + "group", + "team", + "feet", + "tracks", + "pet", + "dog", + "speed", + "desert", + "thanksgiving", + "slow", + "dinosaur", + "sea", + "beach", + "bug", + "germ", + "flowers", + "flower", + "spring", + "plant", + "wood", + "canada", + "autumn", + "leaf", + "fruit", + "aubergine", + "spicy", + "toast", + "meat", + "chicken", + "burger", + "breakfast", + "paella", + "curry", + "noodle", + "pasta", + "tempura", + "party", + "dessert", + "sweet", + "milk", + "cafe", + "espresso", + "green", + "bottle", + "bubbly", + "drink", + "summer", + "vacation", + "drinks", + "cheers", + "whisky", + "dining", + "dinner", + "cutlery", + "cut", + "chop", + "globe", + "world", + "international", + "global", + "travel", + "camping", + "karl", + "skyline", + "train", + "bicycle", + "911", + "emergency", + "semaphore", + "wip", + "ship", + "cruise", + "flight", + "orbit", + "launch", + "time", + "morning", + "night", + "weather", + "cloud", + "swirl", + "rain", + "beach_umbrella", + "lightning", + "thunder", + "winter", + "cold", + "burn", + "festival", + "shiny", + "present", + "award", + "contest", + "winner", + "gold", + "silver", + "bronze", + "sports", + "skating", + "target", + "pool", + "billiards", + "fortune", + "play", + "controller", + "console", + "dice", + "gambling", + "theater", + "drama", + "design", + "paint", + "shirt", + "formal", + "pants", + "bag", + "bags", + "sneaker", + "sport", + "running", + "shoe", + "king", + "queen", + "hat", + "classy", + "education", + "college", + "university", + "makeup", + "engaged", + "diamond", + "volume", + "announcement", + "notification", + "off", + "music", + "podcast", + "sing", + "earphones", + "rock", + "piano", + "smartphone", + "mobile", + "call", + "incoming", + "phone", + "desktop", + "screen", + "save", + "film", + "video", + "photo", + "search", + "zoom", + "idea", + "light", + "library", + "document", + "press", + "tag", + "dollar", + "cream", + "money", + "subscription", + "letter", + "shipping", + "note", + "directory", + "calendar", + "schedule", + "graph", + "metrics", + "stats", + "location", + "trash", + "security", + "private", + "lock", + "password", + "tool", + "shoot", + "weapon", + "archery", + "science", + "laboratory", + "investigate", + "signal", + "health", + "hospital", + "needle", + "medicine", + "wc", + "bath", + "toilet", + "cigarette", + "funeral", + "stone", + "accessibility", + "restroom", + "airport", + "limit", + "block", + "forbidden", + "return", + "sync", + "shuffle", + "loop", + "movie", + "wifi", + "confused", + "bang", + "environment", + "trademark", + "number", + "letters", + "numbers", + "alphabet", + "fresh", + "yes", + "help", + "milestone", + "finish", + "pride", + "keeling", + "ivory", + "china", + "flag", + "germany", + "spain", + "france", + "french", + "british", + "italy", + "japan", + "korea", + "burma", + "russia", + "turkey", + "united", + "america", + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/errors.go b/vendor/github.com/brianvoe/gofakeit/v7/data/errors.go new file mode 100644 index 0000000000..75647cf81c --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/errors.go @@ -0,0 +1,122 @@ +package data + +var Error = map[string][]string{ + "object": { + "argument", + "buffer", + "connection", + "database", + "header", + "hostname", + "method", + "object", + "parameter", + "pointer", + "port", + "protocol", + "request", + "response", + "server", + "service", + "signature", + "tag", + "undefined", + "url", + "uri", + "variable", + }, + "generic": { + "error", + "syntax error", + "requested {errorobject} is unavailable", + "failed to {hackerverb} {errorobject}", + "expected {errorobject} is undefined", + "[object Object]", + "no such variable", + "{errorobject} not initialized", + "variable assigned before declaration", + }, + "database": { + "sql error", + "database connection error", + "table does not exist", + "unique key constraint", + "table migration failed", + "bad connection", + "destination pointer is nil", + }, + "grpc": { + "connection refused", + "connection closed", + "connection is shut down", + "client protocol error", + }, + "http": { + "cross-origin-resource-policy error", + "feature not supported", + "trailer header without chunked transfer encoding", + "no multipart boundary param in Content-Type", + "request Content-Type isn't multipart/form-data", + "header too long", + "entity body too short", + "missing ContentLength in HEAD response", + "named cookie not present", + "invalid method", + "connection has been hijacked", + "request method or response status code does not allow body", + "wrote more than the declared Content-Length", + "{httpmethod} not allowed", + }, + "http_client": { // 400s + "bad request", // 400 + "unauthorized", // 401 + "payment required", // 402 + "forbidden", // 403 + "not found", // 404 + "method not allowed", // 405 + "not acceptable", // 406 + "proxy authentication required", // 407 + "request timeout", // 408 + "conflict", // 409 + "gone", // 410 + "length required", // 411 + "precondition failed", // 412 + "payload too large", // 413 + "URI too long", // 414 + "unsupported media type", // 415 + "range not satisfiable", // 416 + "expectation failed", // 417 + "im a teapot", // 418 + }, + "http_server": { // 500s + "internal server error", // 500 + "not implemented", // 501 + "bad gateway", // 502 + "service unavailable", // 503 + "gateway timeout", // 504 + "http version not supported", // 505 + "variant also negotiates", // 506 + "insufficient storage", // 507 + "loop detected", // 508 + "not extended", // 510 + "network authentication required", // 511 + }, + "runtime": { + "panic: runtime error: invalid memory address or nil pointer dereference", + "address out of bounds", + "undefined has no such property 'length'", + "not enough arguments", + "expected 2 arguments, got 3", + }, + "validation": { + "invalid format", + "missing required field", + "{inputname} is required", + "{inputname} max length exceeded", + "{inputname} must be at exactly 16 characters", + "{inputname} must be at exactly 32 bytes", + "failed to parse {inputname}", + "date is in the past", + "payment details cannot be verified", + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/files.go b/vendor/github.com/brianvoe/gofakeit/v7/data/files.go new file mode 100644 index 0000000000..363b840017 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/files.go @@ -0,0 +1,7 @@ +package data + +// Files consists of file information +var Files = map[string][]string{ + "mime_type": {"x-world/x-3dmf", "application/octet-stream", "application/x-authorware-bin", "application/x-authorware-map", "application/x-authorware-seg", "text/vnd.abc", "text/html", "video/animaflex", "application/postscript", "audio/aiff", "audio/x-aiff", "audio/aiff", "audio/x-aiff", "audio/aiff", "audio/x-aiff", "application/x-aim", "text/x-audiosoft-intra", "application/x-navi-animation", "application/x-nokia-9000-communicator-add-on-software", "application/mime", "application/octet-stream", "application/arj", "application/octet-stream", "image/x-jg", "video/x-ms-asf", "text/x-asm", "text/asp", "application/x-mplayer2", "video/x-ms-asf", "video/x-ms-asf-plugin", "audio/basic", "audio/x-au", "application/x-troff-msvideo", "video/avi", "video/msvideo", "video/x-msvideo", "video/avs-video", "application/x-bcpio", "application/mac-binary", "application/macbinary", "application/octet-stream", "application/x-binary", "application/x-macbinary", "image/bmp", "image/bmp", "image/x-windows-bmp", "application/book", "application/book", "application/x-bzip2", "application/x-bsh", "application/x-bzip", "application/x-bzip2", "text/plain", "text/x-c", "text/plain", "application/vnd.ms-pki.seccat", "text/plain", "text/x-c", "application/clariscad", "application/x-cocoa", "application/cdf", "application/x-cdf", "application/x-netcdf", "application/pkix-cert", "application/x-x509-ca-cert", "application/x-chat", "application/x-chat", "application/java", "application/java-byte-code", "application/x-java-class", "application/octet-stream", "text/plain", "text/plain", "application/x-cpio", "text/x-c", "application/mac-compactpro", "application/x-compactpro", "application/x-cpt", "application/pkcs-crl", "application/pkix-crl", "application/pkix-cert", "application/x-x509-ca-cert", "application/x-x509-user-cert", "application/x-csh", "text/x-script.csh", "application/x-pointplus", "text/css", "text/plain", "application/x-director", "application/x-deepv", "text/plain", "application/x-x509-ca-cert", "video/x-dv", "application/x-director", "video/dl", "video/x-dl", "application/msword", "application/msword", "application/commonground", "application/drafting", "application/octet-stream", "video/x-dv", "application/x-dvi", "drawing/x-dwf (old)", "model/vnd.dwf", "application/acad", "image/vnd.dwg", "image/x-dwg", "application/dxf", "image/vnd.dwg", "image/x-dwg", "application/x-director", "text/x-script.elisp", "application/x-bytecode.elisp (compiled elisp)", "application/x-elc", "application/x-envoy", "application/postscript", "application/x-esrehber", "text/x-setext", "application/envoy", "application/x-envoy", "application/octet-stream", "text/plain", "text/x-fortran", "text/x-fortran", "text/plain", "text/x-fortran", "application/vnd.fdf", "application/fractals", "image/fif", "video/fli", "video/x-fli", "image/florian", "text/vnd.fmi.flexstor", "video/x-atomic3d-feature", "text/plain", "text/x-fortran", "image/vnd.fpx", "image/vnd.net-fpx", "application/freeloader", "audio/make", "text/plain", "image/g3fax", "image/gif", "video/gl", "video/x-gl", "audio/x-gsm", "audio/x-gsm", "application/x-gsp", "application/x-gss", "application/x-gtar", "application/x-compressed", "application/x-gzip", "application/x-gzip", "multipart/x-gzip", "text/plain", "text/x-h", "application/x-hdf", "application/x-helpfile", "application/vnd.hp-hpgl", "text/plain", "text/x-h", "text/x-script", "application/hlp", "application/x-helpfile", "application/x-winhelp", "application/vnd.hp-hpgl", "application/vnd.hp-hpgl", "application/binhex", "application/binhex4", "application/mac-binhex", "application/mac-binhex40", "application/x-binhex40", "application/x-mac-binhex40", "application/hta", "text/x-component", "text/html", "text/html", "text/html", "text/webviewhtml", "text/html", "x-conference/x-cooltalk", "image/x-icon", "text/plain", "image/ief", "image/ief", "application/iges", "model/iges", "application/iges", "model/iges", "application/x-ima", "application/x-httpd-imap", "application/inf", "application/x-internett-signup", "application/x-ip2", "video/x-isvideo", "audio/it", "application/x-inventor", "i-world/i-vrml", "application/x-livescreen", "audio/x-jam", "text/plain", "text/x-java-source", "text/plain", "text/x-java-source", "application/x-java-commerce", "image/jpeg", "image/pjpeg", "image/jpeg", "image/jpeg", "image/pjpeg", "image/jpeg", "image/pjpeg", "image/jpeg", "image/pjpeg", "image/x-jps", "application/x-javascript", "image/jutvision", "audio/midi", "music/x-karaoke", "application/x-ksh", "text/x-script.ksh", "audio/nspaudio", "audio/x-nspaudio", "audio/x-liveaudio", "application/x-latex", "application/lha", "application/octet-stream", "application/x-lha", "application/octet-stream", "text/plain", "audio/nspaudio", "audio/x-nspaudio", "text/plain", "application/x-lisp", "text/x-script.lisp", "text/plain", "text/x-la-asf", "application/x-latex", "application/octet-stream", "application/x-lzh", "application/lzx", "application/octet-stream", "application/x-lzx", "text/plain", "text/x-m", "video/mpeg", "audio/mpeg", "video/mpeg", "audio/x-mpequrl", "application/x-troff-man", "application/x-navimap", "text/plain", "application/mbedlet", "application/mcad", "application/x-mathcad", "image/vasa", "text/mcf", "application/netmc", "application/x-troff-me", "message/rfc822", "message/rfc822", "application/x-midi", "audio/midi", "audio/x-mid", "audio/x-midi", "music/crescendo", "x-music/x-midi", "application/x-midi", "audio/midi", "audio/x-mid", "audio/x-midi", "music/crescendo", "x-music/x-midi", "application/x-frame", "application/x-mif", "message/rfc822", "www/mime", "video/x-motion-jpeg", "application/base64", "application/x-meme", "application/base64", "audio/mod", "audio/x-mod", "video/quicktime", "video/quicktime", "video/x-sgi-movie", "audio/mpeg", "audio/x-mpeg", "video/mpeg", "video/x-mpeg", "video/x-mpeq2a", "audio/mpeg3", "audio/x-mpeg-3", "video/mpeg", "video/x-mpeg", "audio/mpeg", "video/mpeg", "application/x-project", "video/mpeg", "video/mpeg", "audio/mpeg", "video/mpeg", "audio/mpeg", "application/vnd.ms-project", "application/x-project", "application/x-project", "application/x-project", "application/marc", "application/x-troff-ms", "video/x-sgi-movie", "audio/make", "application/x-vnd.audioexplosion.mzz", "image/naplps", "image/naplps", "application/x-netcdf", "application/vnd.nokia.configuration-message", "image/x-niff", "image/x-niff", "application/x-mix-transfer", "application/x-conference", "application/x-navidoc", "application/octet-stream", "application/oda", "application/x-omc", "application/x-omcdatamaker", "application/x-omcregerator", "text/x-pascal", "application/pkcs10", "application/x-pkcs10", "application/pkcs-12", "application/x-pkcs12", "application/x-pkcs7-signature", "application/pkcs7-mime", "application/x-pkcs7-mime", "application/pkcs7-mime", "application/x-pkcs7-mime", "application/x-pkcs7-certreqresp", "application/pkcs7-signature", "application/pro_eng", "text/pascal", "image/x-portable-bitmap", "application/vnd.hp-pcl", "application/x-pcl", "image/x-pict", "image/x-pcx", "chemical/x-pdb", "application/pdf", "audio/make", "audio/make.my.funk", "image/x-portable-graymap", "image/x-portable-greymap", "image/pict", "image/pict", "application/x-newton-compatible-pkg", "application/vnd.ms-pki.pko", "text/plain", "text/x-script.perl", "application/x-pixclscript", "image/x-xpixmap", "text/x-script.perl-module", "application/x-pagemaker", "application/x-pagemaker", "image/png", "application/x-portable-anymap", "image/x-portable-anymap", "application/mspowerpoint", "application/vnd.ms-powerpoint", "model/x-pov", "application/vnd.ms-powerpoint", "image/x-portable-pixmap", "application/mspowerpoint", "application/vnd.ms-powerpoint", "application/mspowerpoint", "application/powerpoint", "application/vnd.ms-powerpoint", "application/x-mspowerpoint", "application/mspowerpoint", "application/x-freelance", "application/pro_eng", "application/postscript", "application/octet-stream", "paleovu/x-pv", "application/vnd.ms-powerpoint", "text/x-script.phyton", "application/x-bytecode.python", "audio/vnd.qcelp", "x-world/x-3dmf", "x-world/x-3dmf", "image/x-quicktime", "video/quicktime", "video/x-qtc", "image/x-quicktime", "image/x-quicktime", "audio/x-pn-realaudio", "audio/x-pn-realaudio-plugin", "audio/x-realaudio", "audio/x-pn-realaudio", "application/x-cmu-raster", "image/cmu-raster", "image/x-cmu-raster", "image/cmu-raster", "text/x-script.rexx", "image/vnd.rn-realflash", "image/x-rgb", "application/vnd.rn-realmedia", "audio/x-pn-realaudio", "audio/mid", "audio/x-pn-realaudio", "audio/x-pn-realaudio", "audio/x-pn-realaudio-plugin", "application/ringing-tones", "application/vnd.nokia.ringing-tone", "application/vnd.rn-realplayer", "application/x-troff", "image/vnd.rn-realpix", "audio/x-pn-realaudio-plugin", "text/richtext", "text/vnd.rn-realtext", "application/rtf", "application/x-rtf", "text/richtext", "application/rtf", "text/richtext", "video/vnd.rn-realvideo", "text/x-asm", "audio/s3m", "application/octet-stream", "application/x-tbook", "application/x-lotusscreencam", "text/x-script.guile", "text/x-script.scheme", "video/x-scm", "text/plain", "application/sdp", "application/x-sdp", "application/sounder", "application/sea", "application/x-sea", "application/set", "text/sgml", "text/x-sgml", "text/sgml", "text/x-sgml", "application/x-bsh", "application/x-sh", "application/x-shar", "text/x-script.sh", "application/x-bsh", "application/x-shar", "text/html", "text/x-server-parsed-html", "audio/x-psid", "application/x-sit", "application/x-stuffit", "application/x-koan", "application/x-koan", "application/x-koan", "application/x-koan", "application/x-seelogo", "application/smil", "application/smil", "audio/basic", "audio/x-adpcm", "application/solids", "application/x-pkcs7-certificates", "text/x-speech", "application/futuresplash", "application/x-sprite", "application/x-sprite", "application/x-wais-source", "text/x-server-parsed-html", "application/streamingmedia", "application/vnd.ms-pki.certstore", "application/step", "application/sla", "application/vnd.ms-pki.stl", "application/x-navistyle", "application/step", "application/x-sv4cpio", "application/x-sv4crc", "image/vnd.dwg", "image/x-dwg", "application/x-world", "x-world/x-svr", "application/x-shockwave-flash", "application/x-troff", "text/x-speech", "application/x-tar", "application/toolbook", "application/x-tbook", "application/x-tcl", "text/x-script.tcl", "text/x-script.tcsh", "application/x-tex", "application/x-texinfo", "application/x-texinfo", "application/plain", "text/plain", "application/gnutar", "application/x-compressed", "image/tiff", "image/x-tiff", "image/tiff", "image/x-tiff", "application/x-troff", "audio/tsp-audio", "application/dsptype", "audio/tsplayer", "text/tab-separated-values", "image/florian", "text/plain", "text/x-uil", "text/uri-list", "text/uri-list", "application/i-deas", "text/uri-list", "text/uri-list", "application/x-ustar", "multipart/x-ustar", "application/octet-stream", "text/x-uuencode", "text/x-uuencode", "application/x-cdlink", "text/x-vcalendar", "application/vda", "video/vdo", "application/groupwise", "video/vivo", "video/vnd.vivo", "video/vivo", "video/vnd.vivo", "application/vocaltec-media-desc", "application/vocaltec-media-file", "audio/voc", "audio/x-voc", "video/vosaic", "audio/voxware", "audio/x-twinvq-plugin", "audio/x-twinvq", "audio/x-twinvq-plugin", "application/x-vrml", "model/vrml", "x-world/x-vrml", "x-world/x-vrt", "application/x-visio", "application/x-visio", "application/x-visio", "application/wordperfect6.0", "application/wordperfect6.1", "application/msword", "audio/wav", "audio/x-wav", "application/x-qpro", "image/vnd.wap.wbmp", "application/vnd.xara", "application/msword", "application/x-123", "windows/metafile", "text/vnd.wap.wml", "application/vnd.wap.wmlc", "text/vnd.wap.wmlscript", "application/vnd.wap.wmlscriptc", "application/msword", "application/wordperfect", "application/wordperfect", "application/wordperfect6.0", "application/wordperfect", "application/wordperfect", "application/x-wpwin", "application/x-lotus", "application/mswrite", "application/x-wri", "application/x-world", "model/vrml", "x-world/x-vrml", "model/vrml", "x-world/x-vrml", "text/scriplet", "application/x-wais-source", "application/x-wintalk", "image/x-xbitmap", "image/x-xbm", "image/xbm", "video/x-amt-demorun", "xgl/drawing", "image/vnd.xiff", "application/excel", "application/excel", "application/x-excel", "application/x-msexcel", "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/excel", "application/x-excel", "application/excel", "application/x-excel", "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/x-msexcel", "application/excel", "application/x-excel", "application/excel", "application/x-excel", "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/x-msexcel", "audio/xm", "application/xml", "text/xml", "xgl/movie", "application/x-vnd.ls-xpix", "image/x-xpixmap", "image/xpm", "image/png", "video/x-amt-showrun", "image/x-xwd", "image/x-xwindowdump", "chemical/x-pdb", "application/x-compress", "application/x-compressed", "application/x-compressed", "application/x-zip-compressed", "application/zip", "multipart/x-zip", "application/octet-stream", "text/x-script.zsh"}, + "extension": {"doc", "docx", "log", "msg", "odt", "pages", "rtf", "tex", "txt", "wpd", "wps", "csv", "dat", "gbr", "ged", "key", "keychain", "pps", "ppt", "pptx", "sdf", "tar", "vcf", "xml", "aif", "iff", "mid", "mpa", "ra", "wav", "wma", "asf", "asx", "avi", "flv", "mov", "mpg", "rm", "srt", "swf", "vob", "wmv", "max", "obj", "bmp", "dds", "gif", "jpg", "png", "psd", "pspimage", "tga", "thm", "tif", "tiff", "yuv", "ai", "eps", "ps", "svg", "indd", "pct", "pdf", "xlr", "xls", "xlsx", "accdb", "db", "dbf", "mdb", "pdb", "sql", "apk", "app", "bat", "cgi", "com", "exe", "gadget", "jar", "pif", "vb", "wsf", "dem", "gam", "nes", "rom", "sav", "dwg", "dxf", "gpx", "kml", "kmz", "asp", "aspx", "cer", "cfm", "csr", "css", "htm", "html", "js", "jsp", "php", "rss", "xhtml", "crx", "plugin", "fnt", "fon", "otf", "ttf", "cab", "cpl", "cur", "deskthemepack", "dll", "dmp", "drv", "icns", "ico", "lnk", "sys", "cfg", "ini", "prf", "hqx", "mim", "uue", "cbr", "deb", "gz", "pkg", "rar", "rpm", "sitx", "gz", "zip", "zipx", "bin", "cue", "dmg", "iso", "mdf", "toast", "vcd", "class", "cpp", "cs", "dtd", "fla", "java", "lua", "pl", "py", "sh", "sln", "swift", "vcxproj", "xcodeproj", "bak", "tmp", "crdownload", "ics", "msi", "part", "torrent"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/food.go b/vendor/github.com/brianvoe/gofakeit/v7/data/food.go new file mode 100644 index 0000000000..0726c17e9b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/food.go @@ -0,0 +1,13 @@ +package data + +// Food consists of food information +var Food = map[string][]string{ + "fruit": {"Apple", "Apricot", "Avocado", "Banana", "Bilberry", "Blackberry", "Blackcurrant", "Blueberry", "Currant", "Cherry", "Cherimoya", "Clementine", "Date", "Damson", "Durian", "Eggplant", "Elderberry", "Feijoa", "Gooseberry", "Grape", "Grapefruit", "Guava", "Huckleberry", "Jackfruit", "Jambul", "Kiwi", "Kumquat", "Legume", "Lemon", "Lime", "Lychee", "Mango", "Mangostine", "Melon", "Cantaloupe", "Honeydew", "Watermelon", "Rock melon", "Nectarine", "Orange", "Peach", "Pear", "Pitaya", "Physalis", "Plum", "Pineapple", "Pomegranate", "Raisin", "Raspberry", "Rambutan", "Redcurrant", "Satsuma", "Strawberry", "Tangerine", "Tomato", "Watermelon"}, + "vegetable": {"Amaranth Leaves", "Arrowroot", "Artichoke", "Arugula", "Asparagus", "Bamboo Shoots", "Beans, Green", "Beets", "Belgian Endive", "Bitter Melon*", "Bok Choy", "Broadbeans", "Broccoli", "Broccoli Rabe", "Brussel Sprouts", "Cabbage", "Carrot", "Cassava", "Cauliflower", "Celeriac", "Celery", "Chicory", "Collards", "Corn", "Crookneck", "Cucumber", "Daikon", "Dandelion Greens", "Eggplant", "Fennel", "Fiddleheads", "Ginger Root", "Horseradish", "Jicama", "Kale", "Kohlrabi", "Leeks", "Lettuce", "Mushrooms", "Mustard Greens", "Okra", "Onion", "Parsnip", "Peas", "Pepper", "Potato", "Pumpkin", "Radicchio", "Radishes", "Rutabaga", "Salsify", "Shallots", "Snow Peas", "Sorrel", "Soybeans", "Spaghetti Squash", "Spinach", "Squash", "Sugar Snap Peas", "Sweet Potato", "Swiss Chard", "Tomato", "Turnip", "Watercress", "Yam Root", "Zucchini"}, + "breakfast": {"berry cream cheese coffee cake", "broiled cinnamon toast", "breakfast casserole seasoned with country gravy", "mamas fruit cobbler", "shirleys plain or blueberry muffins", "toasted sunny side up egg and cheese sandwiches", "3 meat breakfast pizza", "moms cheat doughnuts", "old fashioned banana muffins", "blackberry breakfast bars", "pikelets australian pancakes", "pumpkin ginger scones with cinnamon chips", "tomato and mushroom omelette", "asparagus omelette wraps", "poached eggs technique", "scrambled egg sandwiches with onions and red peppers", "cheesecake kugel", "chicken and egg on rice oyako donburi", "bacon egg casserole", "ginger lemon muffins", "lizs morning glory muffins", "scrambled eggs oeufs brouills", "nats cucumber cream cheese bagel", "easy breakfast casserole", "6 week bran muffins auntie annes muffins", "awesome orange chocolate muffins", "baked swiss cheese omelet", "melt in your mouth blueberry muffins", "baked pears", "flaeskeaeggekage danish bacon egg pancake omelet", "sleepy twisted sisters g n g breakfast ramekin", "lemon buttercream pancakes with blueberries", "chef flowers simple sunday brunch omelette", "blueberry bakery muffins", "cardamom sour cream waffles", "sausage gravy for biscuits and gravy", "creamy scrambled eggs in the microwave", "english muffins with bacon butter", "original praline bacon recipe", "christmas caramel rolls easy", "blueberry banana happy face pancakes", "whole grain pancake mix", "fresh mango bread", "canadian bacon cheese omelet", "pumpkin french toast with toasted walnuts", "green mountain granola", "italian eggs with bacon", "a faster egg muffin", "country scrambled eggs", "everyday french breakfast baguette and jam with chocolate milk", "mexi eggs in a hole", "fruited irish oatmeal", "ham omelet deluxe", "danish bubble", "best buttermilk pancakes", "egg flowers", "vanilla fruit dip", "eggs in a basket", "grandmas swedish thin pancakes", "cinnamon maple granola", "wake up stuffed french breakfast panini", "quinoa muffins", "grilled cheese on raisin bread", "castillian hot chocolate", "banana blueberry oatmeal bread", "caramel pull aparts", "purple cow", "chili jack oven omelet", "cheery cherry muffins", "israeli breakfast salad", "muffin toppings", "migas lite for 2", "easy danish kringle", "oatmeal cookie granola"}, + "lunch": {"no bake hersheys bar pie", "worm sandwiches", "quesadillas for one or two", "pearls sesame noodles", "patty melt", "fresh tomato sandwiches saturday lunch on longmeadow farm", "onion burgers by john t edge the longmeadow farm", "fresh tomato and cucumber salad", "hoisin marinated wing pieces", "feta marinated", "spicy roasted butternut seeds pumpkin seeds", "honey chipotle pecans", "baked ham glazed with pineapple and chipotle peppers", "reuben sandwich our way", "toasted sunny side up egg and cheese sandwiches", "mrs allens date loaf", "3 meat breakfast pizza", "body and soul health muffins", "grilled blue cheese burgers", "kittencals beef burritos", "spinach and mandarin orange salad", "coconut pound cake", "scallop saute", "open faced crab sandwiches", "the traditional cyprus sandwich with halloumi onions and tomato", "toasted ham and cheese supreme", "scrambled egg sandwiches with onions and red peppers", "cucumber open faced sandwiches", "chicken and egg on rice oyako donburi", "blt sandwich", "grilled chicken pesto panini", "mushroom and chicken grilled quesadillas", "delicious cheesy bacon and green onion potato skins", "grilled chili lime chicken", "fried almonds", "the greatful bread sandwich", "egg salad club sandwiches or shrimp salad club", "nifs peanut butter banana muffins", "parmesan fish in the oven", "caramelized onion focaccia bread machine", "nats cucumber cream cheese bagel", "chicken with cashews", "lemon parsley popcorn", "not your ordinary chocolate chip cookies liqueur laced", "katos tasty salmon cream cheese surprise", "greek inspired salad", "tomato basil american cheese sandwich", "club sandwich", "bacon and egg salad sandwiches", "apple cheese bites", "two cheese panini with tomato olive pesto", "delicious and simple fruit dip", "tex mex 7 layer salad", "grilled peanut butter and jelly sandwich", "simply simple cucumber slices in vinegar dressing longmeadow", "ww greek inspired scrambled egg wraps", "baby greens with mustard vinaigrette", "patty melts", "ribs", "chocolate angel food cake", "spinach with lemon garlic", "green goddess dressing", "leftover rice muffins", "cajun garlic fingers", "fresh mango bread", "california crab salad", "hot salty nuts", "beef for tacos", "hidden valley wraps", "omas boterkoek dutch buttercake", "apple butterflies", "don t burn your fingers garlic bread", "beer wisconsin bratwurst", "salmon with bourbon and brown sugar glaze", "lemon coconut muffins", "the godfather of grilled cheese sandwiches", "green mountain granola", "tuna red onion and parsley salad", "tortellini skewers", "italian meatball hoagies", "crispy fried chicken spring rolls", "rotisserie style chicken in the crock pot", "creamed peas on toast", "bergy dim sum 5 steamed shrimp dumplings", "chocolate almond roca bar", "number 400 seafood casserole", "chocolate rainbow krispies treats", "spinach salad with blue cheese", "hash", "fake crab salad sandwiches", "guacamole stuffed deviled eggs", "weight watchers veggie barley soup 1 pt for 1 cup", "hummus with a twist", "bellissimo panini", "carls jr western bacon cheeseburger copycat by todd wilbur", "salami havarti and cole slaw sandwiches", "garlic herbed roasted red skin potatoes", "grilled cheese on raisin bread", "hearty grilled cheese", "italian deli wraps", "strammer max german warm sandwich", "quick elephant ears", "salata marouli romaine lettuce salad", "goat cheese black olive mashed potatoes", "tomato cucumber avocado sandwich", "purple cow", "chocolate coconut dream bars", "homemade popsicles", "ginger soy salmon", "sweet and sour pork balls", "spicy chicken soup with hints of lemongrass and coconut milk", "another buffalo wings recipe", "famous white wings", "amazing sweet italian sausage pasta soup", "sausage sandwich italian style", "copycat taco bell chicken enchilada bowl", "simple pan fried chicken breasts", "1 2 3 black bean salsa dip", "quick chile relleno casserole", "bacon spaghetti squash", "fantastic banana bran muffins", "garbanzo vegetarian burgers", "mediterranean tuna stuffed tomato", "sugared cinnamon almonds", "queen margherita pizza", "insanely easy chickpea salad", "habit forming shrimp dip", "turkey swiss panini", "pumpkin chocolate chip muffins", "grilled havarti and avocado sandwiches", "english muffin pizzas", "oatmeal cookie granola"}, + "dinner": {"kittencals caesar tortellini salad", "no bake hersheys bar pie", "lindas special potato salad", "kittencals parmesan orzo", "pearls sesame noodles", "roasted potatoes and green beans", "kittencals really great old fashioned lemonade", "lindas chunky garlic mashed potatoes", "kittencals pan fried asparagus", "cafe mocha latte", "fresh tomato and cucumber salad", "peanut butter gooey cake", "foolproof standing prime rib roast paula deen", "mamas fruit cobbler", "hoisin marinated wing pieces", "feta marinated", "the realtors cream cheese corn", "savory pita chips", "jalapeno pepper jelly chicken", "kashmir lamb with spinach", "oven fried zucchini sticks", "best ever bruschetta", "maple cinnamon coffee", "kick a fried onion rings", "guava mojito", "confit d oignon french onion marmalade", "flounder stuffed with shrimp and crabmeat", "mrs allens date loaf", "swedish cucumber salad pressgurka", "authentic pork lo mein chinese", "golden five spice sticky chicken", "basil tomato salad", "white chocolate cheesecake", "celery and blue cheese salad", "kittencals crock pot french dip roast", "lindas asian salmon", "spinach and mandarin orange salad", "coconut pound cake", "scallop saute", "spicy catfish tenders with cajun tartar sauce", "just like deweys candied walnut and grape salad", "strawberry pavlova", "grilled pork chops with lime cilantro garlic", "smoky barbecue beef brisket crock pot", "quick and easy chicken in cream sauce", "fried chorizo with garlic", "cucumber open faced sandwiches", "rachael rays mimosa", "tortellini bow tie pasta salad", "tonkatsu japanese pork cutlet", "mushroom and chicken grilled quesadillas", "delicious cheesy bacon and green onion potato skins", "roasted beet salad with horseradish cream dressing", "islands bananas foster", "apricot glazed roasted asparagus low fat", "frozen kahlua creme", "fried almonds", "just peachy grillin ribs rsc", "death by chocolate cake", "parmesan fish in the oven", "calico peas", "creamy cucumber dill dip", "emerils stewed black eyed peas", "german style eiskaffee iced coffee drink", "strawberry angel trifle", "spinach salad with feta cheese", "french napoleons", "ultimate crab and spinach manicotti with parmesan cheese sauce", "sweet and sour stir fry shrimp with broccoli and red bell pepper", "crispy noodle salad with sweet and sour dressing", "crunchy rosemary potatoes", "roasted cherry or grape tomatoes", "blackened skillet shrimp", "parslied new potatoes", "tropical baked chicken", "sweet and sour kielbasa kabobs", "fantastic mushrooms with garlic butter and parmesan", "asparagus with lemon butter crumbs", "creamy garlic prawns", "kittencals banana almond muffins with almond streusel", "ww shrimp scampi", "kittencals tender microwave corn with husks on", "nude beach", "kittencals greek garden salad with greek style dressing", "roasted broccoli with cherry tomatoes", "kittencals chicken cacciatore", "buttermilk mashed potatoes with country mustard", "tilapia in thai sauce", "cream cheese potato soup", "brown sugar roasted salmon with maple mustard dill sauce", "baby greens with mustard vinaigrette", "ribs", "new england roasted cornish game hens", "chocolate angel food cake", "creamy strawberries", "spinach with lemon garlic", "green goddess dressing", "jamaican pork tenderloin", "awesome twice baked potatoes", "sausage mushroom appetizers", "roasted garlic soup with parmesan", "crushed red potatoes with garlic", "15 minute no fry chicken enchiladas honest", "uncle bills caesar canadian style", "raspberry cranberry salad with sour cream cream cheese topping", "hot salty nuts", "acorn squash for 2", "pumpkin knot yeast rolls", "caramelized onion dip spread", "roasted asparagus with sage and lemon butter", "spanish garlic shrimp taverna", "baby greens with pears gorgonzola and pecans", "grilled or baked salmon with lavender", "ruth walls german apple cake", "healthy italian breadsticks or pizza crust", "strawberry and cream cheese parfait", "marinated grilled tuna steak", "kittencals extra crispy fried chicken breast", "de constructed chicken cordon bleu", "moroccan cinnamon coffee with orange flower water", "lemon and parsley potatoes", "bergy dim sum 5 steamed shrimp dumplings", "chocolate almond roca bar", "garlic mashed potatoes and cashew gravy", "number 400 seafood casserole", "sherry buttered shrimp", "spinach salad with blue cheese", "cookie monster fruit salad", "asian broccoli salad", "pink poodle", "butterflied leg of lamb with lots of garlic and rosemary", "gorgonzola and toasted walnut salad", "maple coffee", "chocolate chip bundt cake with chocolate glaze", "crock pot caramelized onion pot roast", "mashed potatoes with bacon and cheddar", "provencal olives", "creole potato salad", "wild addicting dip", "baby shower pink cloud punch", "i did it my way tossed salad", "lubys cafeteria butternut brownie pie", "spiced poached pears", "lemon cajun stir fry", "iced banana cream", "potato ham onion chipotle soup", "chicken and penne casserole", "kahlua hot chocolate", "chicken and yoghurt curry", "oriental asparagus and mushrooms", "guacamole stuffed deviled eggs", "orzo with tomatoes feta and green onions", "kathy dessert baked bananas zwt ii asia", "hummus with pine nuts turkish style", "caramel delight", "whipped cream cream cheese frosting", "broccoli and cranberry salad", "raspberry lemonade", "pan broiled steak with whiskey sauce", "t g i fridays mudslide", "herb crusted fish fillets", "agua de valencia knock your socks off spanish cava punch", "orange brownie", "jiffy punch", "steak balmoral and whisky sauce from the witchery by the castle", "julies alabama white sauce", "ww potato gratin 5 points", "bo kaap cape malay curry powder south african spice mixture", "garlic herbed roasted red skin potatoes", "tasty broccoli salad", "risotto with pesto and mascarpone", "red potato and green bean saute", "caribbean sunset", "sriracha honey roasted broccoli", "salata marouli romaine lettuce salad", "goat cheese black olive mashed potatoes", "swirled cranberry cheesecake", "curried pea soup", "long island iced tea applebees tgi fridays style", "chocolate coconut dream bars", "bbq salmon filet", "blue margaritas", "sweet and sour pork balls", "spanish shrimp", "orange glazed pork chops", "heavenly lemon bread pudding", "spicy chicken soup with hints of lemongrass and coconut milk", "sweet onion and mashed potato bake", "smoky clam chowder", "cornish game hens with peach glaze", "garlic prime rib", "german apple cake with cream cheese frosting", "amazing sweet italian sausage pasta soup", "fresh orange slices with honey and cinnamon", "blackened tuna bites with cajun mustard", "tuna cobb salad", "greek shrimp with rigatoni", "creamy beet salad", "caponata eggplant and lots of good things", "lemon and oregano lamb loin chops", "pork chops with apples stuffing", "bacon spaghetti squash", "layered bean taco dip", "creamy lemon tarts", "strawberry and baileys fool", "italian style roast", "sourdough rosemary potato bread", "cracker barrel baby carrots", "portuguese tomato rice", "chocolate covered dipped strawberries", "caf a la russe chocolate coffee", "herbed potato with cottage cheese", "your basic tossed salad", "panzanella salad with bacon tomato and basil"}, + "drink": {"water", "tea", "milk", "juice", "coffee", "soda", "smoothie", "beer", "wine"}, + "snack": {"hoisin marinated wing pieces", "feta marinated", "spicy roasted butternut seeds pumpkin seeds", "honey chipotle pecans", "best ever bruschetta", "body and soul health muffins", "kittencals beef burritos", "the traditional cyprus sandwich with halloumi onions and tomato", "delicious cheesy bacon and green onion potato skins", "fried almonds", "nifs peanut butter banana muffins", "lemon parsley popcorn", "not your ordinary chocolate chip cookies liqueur laced", "delicious and simple fruit dip", "fresh mango bread", "hot salty nuts", "omas boterkoek dutch buttercake", "apple butterflies", "lemon coconut muffins", "green mountain granola", "crispy fried chicken spring rolls", "guacamole stuffed deviled eggs", "hummus with a twist", "quick elephant ears", "homemade popsicles", "1 2 3 black bean salsa dip", "fantastic banana bran muffins", "sugared cinnamon almonds", "pumpkin chocolate chip muffins", "oatmeal cookie granola"}, + "dessert": {"no bake hersheys bar pie", "big ol cowboy cookies", "crackle top molasses cookies", "old fashion oatmeal pie", "cranberry nut swirls", "butter balls", "peanut butter gooey cake", "mamas fruit cobbler", "pink stuff cherry pie filling pineapple dessert", "chocolate star cookies", "midsummer swedish strawberry compote jordgubbskrm", "foolproof one bowl banana cake", "creamy apple dessert", "walnut chews", "yummy bread pudding", "white chocolate cheesecake", "hersheys kiss peanut butter cookies", "coconut pound cake", "frosted rhubarb cookies", "strawberry pavlova", "cookies n cream ice cream", "perfect pumpkin pie", "gluten free dutch sugar cookies", "raw apple crumble no bake", "cheesecake kugel", "moo less chocolate pie", "chocolate macadamia nut brownies", "disneyland snickerdoodles", "islands bananas foster", "frozen kahlua creme", "nifs peanut butter banana muffins", "peach cobbler with oatmeal cookie topping", "christmas cardamom butter cookies", "death by chocolate cake", "moms southern pecan pie", "the best brownies ever", "jerrys chocolate ice cream", "strawberry angel trifle", "zucchini mock apple pie", "low fat chocolate peanut butter dessert", "creamy raspberry mallow pie", "french napoleons", "pie crust cinnamon rolls", "not your ordinary chocolate chip cookies liqueur laced", "foolproof dark chocolate fudge", "whole wheat sugar cookies", "awesome kahlua cake", "up those antioxidants with blueberry sauce", "grammie millers swedish apple pie", "glendas flourless peanut butter cookies", "my best banana pudding dessert", "viskos praline sauce", "perfect purple punch", "reindeer bark", "lindas bloodshot eyeballs", "moroccan fruit salad", "apple dumpling bake", "simons pumpkin bread pudding", "baileys flourless peanut butter cookies", "a 1 cherry cobbler tart a1", "monkey balls", "chocolate angel food cake", "creamy strawberries", "harvest cake", "deep dark chocolate moist cake", "spooktacular halloween graveyard cake", "cream cheese walnut drop cookies", "omas boterkoek dutch buttercake", "kates basic crepes", "banana spice bars", "ruth walls german apple cake", "low fat low cholesterol chocolate cake cupcakes", "lower fat peanut butter rice krispies bars", "nutella rolls", "fruit salad pudding", "strawberry and cream cheese parfait", "apple dessert quick", "betty crocker chocolate chip cookies 1971 mens favorites 22", "so there reeses peanut butter bars", "moms buttery apple cake", "chocolate almond roca bar", "turtles", "sesame toffee", "chocolate rainbow krispies treats", "dirt cups for kids", "ultimate seven layer bars", "raisin oat cookies", "snickers bar cookies", "french pie pastry", "sour cream pumpkin bundt cake", "microwave nut brittle", "cinnamon rolls buns", "nutella mousse", "blueberry sour cream cake", "angelic strawberry frozen yogurt", "chocolate chip bundt cake with chocolate glaze", "creole cake", "apricot banana squares", "banana snack cake with delicious cream cheese frosting", "pineapple coconut empanadas", "awesome chocolate butterscotch chip cookies", "easy homemade almond roca", "sonic strawberry cheesecake shake", "lubys cafeteria butternut brownie pie", "spiced poached pears", "chocolate mocha pudding low carb", "iced banana cream", "kathy dessert baked bananas zwt ii asia", "whipped cream cream cheese frosting", "italian biscotti al la syd", "died and went to heaven chocolate cake diabetic version", "coffee and chocolate pudding", "mimis maine blueberry cobbler", "cherry cola float", "linzer bars", "confectioners sugar cookies", "double chocolate mint chip cookies", "quick elephant ears", "swirled cranberry cheesecake", "mexican rice pudding", "eclair torte", "spiced pumpkin pie", "caramel breakfast cake", "lime granita", "chocolate coconut dream bars", "blueberry banana pie", "grannys gingersnaps", "homemade popsicles", "heavenly lemon bread pudding", "pizzelles", "mckinley tea cakes", "lazy day cobbler", "old school deja vu chocolate peanut butter squares", "cheesecake pie", "aunt zanas amish sugar cookies eggless", "amish cream pie", "chocolate chip cookie dough ice cream", "snickerdoodles dream", "chocolate cheese fudge", "german apple cake with cream cheese frosting", "fresh orange slices with honey and cinnamon", "frozen oreo cookie dessert", "blueberry crunch", "amaretto bon bon balls", "red cherry pie", "creamy lemon tarts", "brownie truffles", "strawberry and baileys fool", "easy danish kringle", "chocolate covered dipped strawberries", "caf a la russe chocolate coffee"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/hacker.go b/vendor/github.com/brianvoe/gofakeit/v7/data/hacker.go new file mode 100644 index 0000000000..08a5f86ad5 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/hacker.go @@ -0,0 +1,20 @@ +package data + +// Hacker consists of random hacker phrases +var Hacker = map[string][]string{ + "abbreviation": {"TCP", "HTTP", "SDD", "RAM", "GB", "CSS", "SSL", "AGP", "SQL", "FTP", "PCI", "AI", "ADP", "RSS", "XML", "EXE", "COM", "HDD", "THX", "SMTP", "SMS", "USB", "PNG", "SAS", "IB", "SCSI", "JSON", "XSS", "JBOD"}, + "adjective": {"auxiliary", "primary", "back-end", "digital", "open-source", "virtual", "cross-platform", "redundant", "online", "haptic", "multi-byte", "bluetooth", "wireless", "1080p", "neural", "optical", "solid state", "mobile"}, + "noun": {"driver", "protocol", "bandwidth", "panel", "microchip", "program", "port", "card", "array", "interface", "system", "sensor", "firewall", "hard drive", "pixel", "alarm", "feed", "monitor", "application", "transmitter", "bus", "circuit", "capacitor", "matrix"}, + "verb": {"back up", "bypass", "hack", "override", "compress", "copy", "navigate", "index", "connect", "generate", "quantify", "calculate", "synthesize", "input", "transmit", "program", "reboot", "parse", "read", "write", "load", "render", "validate", "verify", "sign", "decrypt", "encrypt", "construct", "deconstruct", "compile", "transpile", "bundle", "lock", "unlock", "buffer", "format"}, + "ingverb": {"backing up", "bypassing", "hacking", "overriding", "compressing", "copying", "navigating", "indexing", "connecting", "generating", "quantifying", "calculating", "synthesizing", "transmitting", "programming", "parsing"}, + "phrase": { + "If we {hackerverb} the {hackernoun}, we can get to the {hackerabbreviation} {hackernoun} through the {hackeradjective} {hackerabbreviation} {hackernoun}!", + "We need to {hackerverb} the {hackeradjective} {hackerabbreviation} {hackernoun}!", + "Try to {hackerverb} the {hackerabbreviation} {hackernoun}, maybe it will {hackerverb} the {hackeradjective} {hackernoun}!", + "You can't {hackerverb} the {hackernoun} without {hackeringverb} the {hackeradjective} {hackerabbreviation} {hackernoun}!", + "Use the {hackeradjective} {hackerabbreviation} {hackernoun}, then you can {hackerverb} the {hackeradjective} {hackernoun}!", + "The {hackerabbreviation} {hackernoun} is down, {hackerverb} the {hackeradjective} {hackernoun} so we can {hackerverb} the {hackerabbreviation} {hackernoun}!", + "{hackeringverb} the {hackernoun} won't do anything, we need to {hackerverb} the {hackeradjective} {hackerabbreviation} {hackernoun}!", + "I'll {hackerverb} the {hackeradjective} {hackerabbreviation} {hackernoun}, that should {hackerverb} the {hackerabbreviation} {hackernoun}!", + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/hipster.go b/vendor/github.com/brianvoe/gofakeit/v7/data/hipster.go new file mode 100644 index 0000000000..f036f4639b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/hipster.go @@ -0,0 +1,6 @@ +package data + +// Hipster consists of random hipster words +var Hipster = map[string][]string{ + "word": {"Wes Anderson", "chicharrones", "narwhal", "food truck", "marfa", "aesthetic", "keytar", "art party", "sustainable", "forage", "mlkshk", "gentrify", "locavore", "swag", "hoodie", "microdosing", "VHS", "before they sold out", "pabst", "plaid", "Thundercats", "freegan", "scenester", "hella", "occupy", "truffaut", "raw denim", "beard", "post-ironic", "photo booth", "twee", "90's", "pitchfork", "cray", "cornhole", "kale chips", "pour-over", "yr", "five dollar toast", "kombucha", "you probably haven't heard of them", "mustache", "fixie", "try-hard", "franzen", "kitsch", "austin", "stumptown", "keffiyeh", "whatever", "tumblr", "DIY", "shoreditch", "biodiesel", "vegan", "pop-up", "banjo", "kogi", "cold-pressed", "letterpress", "chambray", "butcher", "synth", "trust fund", "hammock", "farm-to-table", "intelligentsia", "loko", "ugh", "offal", "poutine", "gastropub", "Godard", "jean shorts", "sriracha", "dreamcatcher", "leggings", "fashion axe", "church-key", "meggings", "tote bag", "disrupt", "readymade", "helvetica", "flannel", "meh", "roof", "hashtag", "knausgaard", "cronut", "schlitz", "green juice", "waistcoat", "normcore", "viral", "ethical", "actually", "fingerstache", "humblebrag", "deep v", "wayfarers", "tacos", "taxidermy", "selvage", "put a bird on it", "ramps", "portland", "retro", "kickstarter", "bushwick", "brunch", "distillery", "migas", "flexitarian", "XOXO", "small batch", "messenger bag", "heirloom", "tofu", "bicycle rights", "bespoke", "salvia", "wolf", "selfies", "echo", "park", "listicle", "craft beer", "chartreuse", "sartorial", "pinterest", "mumblecore", "kinfolk", "vinyl", "etsy", "umami", "8-bit", "polaroid", "banh mi", "crucifix", "bitters", "brooklyn", "PBR&B", "drinking", "vinegar", "squid", "tattooed", "skateboard", "vice", "authentic", "literally", "lomo", "celiac", "health", "goth", "artisan", "chillwave", "blue bottle", "pickled", "next level", "neutra", "organic", "Yuccie", "paleo", "blog", "single-origin coffee", "seitan", "street", "gluten-free", "mixtape", "venmo", "irony", "everyday", "carry", "slow-carb", "3 wolf moon", "direct trade", "lo-fi", "tousled", "tilde", "semiotics", "cred", "chia", "master", "cleanse", "ennui", "quinoa", "pug", "iPhone", "fanny pack", "cliche", "cardigan", "asymmetrical", "meditation", "YOLO", "typewriter", "pork belly", "shabby chic", "+1", "lumbersexual", "williamsburg"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/html.go b/vendor/github.com/brianvoe/gofakeit/v7/data/html.go new file mode 100644 index 0000000000..5787edd8ae --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/html.go @@ -0,0 +1,7 @@ +package data + +// Html consists of various html information +var Html = map[string][]string{ + "svg": {"rect", "circle", "ellipse", "line", "polyline", "polygon"}, + "input_name": {"title", "first_name", "last_name", "suffix", "address", "postal_code", "city", "state", "country", "date_of_birth", "card_number", "description", "message", "status"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/internet.go b/vendor/github.com/brianvoe/gofakeit/v7/data/internet.go new file mode 100644 index 0000000000..ae7561af91 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/internet.go @@ -0,0 +1,11 @@ +package data + +// Internet consists of various internet information +var Internet = map[string][]string{ + "browser": {"firefox", "chrome", "internetExplorer", "opera", "safari"}, + "domain_suffix": {"com", "biz", "info", "name", "net", "org", "io"}, + "http_method": {"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"}, + "http_version": {"HTTP/1.0", "HTTP/1.1", "HTTP/2.0"}, + "http_status_simple": {"200", "301", "302", "400", "404", "500"}, + "http_status_general": {"100", "200", "201", "203", "204", "205", "301", "302", "304", "400", "401", "403", "404", "405", "406", "416", "500", "501", "502", "503", "504"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/job.go b/vendor/github.com/brianvoe/gofakeit/v7/data/job.go new file mode 100644 index 0000000000..905dd74ee0 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/job.go @@ -0,0 +1,8 @@ +package data + +// Job consists of job data +var Job = map[string][]string{ + "title": {"Administrator", "Agent", "Analyst", "Architect", "Assistant", "Associate", "Consultant", "Coordinator", "Designer", "Developer", "Director", "Engineer", "Executive", "Facilitator", "Liaison", "Manager", "Officer", "Orchestrator", "Planner", "Producer", "Representative", "Specialist", "Strategist", "Supervisor", "Technician"}, + "descriptor": {"Central", "Chief", "Corporate", "Customer", "Direct", "District", "Dynamic", "Dynamic", "Forward", "Future", "Global", "Human", "Internal", "International", "Investor", "Lead", "Legacy", "National", "Principal", "Product", "Regional", "Senior"}, + "level": {"Accountability", "Accounts", "Applications", "Assurance", "Brand", "Branding", "Communications", "Configuration", "Creative", "Data", "Directives", "Division", "Factors", "Functionality", "Group", "Identity", "Implementation", "Infrastructure", "Integration", "Interactions", "Intranet", "Marketing", "Markets", "Metrics", "Mobility", "Operations", "Optimization", "Paradigm", "Program", "Quality", "Research", "Response", "Security", "Solutions", "Tactics", "Usability", "Web"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/languages.go b/vendor/github.com/brianvoe/gofakeit/v7/data/languages.go new file mode 100644 index 0000000000..5fdfc9e6fe --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/languages.go @@ -0,0 +1,9 @@ +package data + +// Languages consists of address information +var Languages = map[string][]string{ + "short": {"aa", "ab", "ae", "af", "ak", "am", "an", "ar", "as", "av", "ay", "az", "ba", "be", "bg", "bh", "bi", "bm", "bn", "bo", "br", "bs", "ca", "ce", "ch", "co", "cr", "cs", "cv", "cy", "da", "de", "dv", "dz", "ee", "en", "eo", "es", "et", "eu", "fa", "ff", "fi", "fj", "fo", "fr", "fy", "ga", "gd", "gl", "gn", "gu", "gv", "ha", "he", "hi", "ho", "hr", "ht", "hu", "hy", "hz", "ia", "id", "ie", "ig", "ii", "ik", "io", "is", "it", "iu", "ja", "jv", "ka", "kg", "ki", "kj", "kk", "kl", "km", "kn", "ko", "kr", "ks", "ku", "kv", "kw", "ky", "la", "lb", "lg", "li", "ln", "lo", "lt", "lu", "lv", "mg", "mh", "mi", "mk", "ml", "mn", "mr", "ms", "mt", "my", "na", "ne", "ng", "nl", "no", "nv", "ny", "oc", "oj", "om", "or", "os", "pa", "pi", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "ru", "rw", "sa", "sc", "sd", "se", "sg", "si", "sk", "sl", "sm", "sn", "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt", "tw", "ty", "ug", "uk", "ur", "uz", "ve", "vi", "wa", "wo", "xh", "yi", "yo", "za", "zh", "zu"}, + "long": {"Afar", "Abkhazian", "Avestan", "Afrikaans", "Akan", "Amharic", "Aragonese", "Arabic", "Assamese", "Avaric", "Aymara", "Azerbaijani", "Bashkir", "Belarusian", "Bulgarian", "Bihari", "Bislama", "Bambara", "Bengali", "Tibetan", "Breton", "Bosnian", "Catalan", "Chechen", "Chamorro", "Corsican", "Cree", "Czech", "Chuvash", "Welsh", "Danish", "German", "Divehi", "Dzongkha", "Ewe", "English", "Esperanto", "Spanish", "Estonian", "Basque", "Persian", "Fulah", "Finnish", "Fijian", "Faroese", "French", "Western Frisian", "Irish", "Gaelic", "Galician", "Guarani", "Gujarati", "Manx", "Hausa", "Hebrew", "Hindi", "Hiri Motu", "Croatian", "Haitian", "Hungarian", "Armenian", "Herero", "Interlingua", "Indonesian", "Interlingue", "Igbo", "Sichuan Yi", "Inupiaq", "Ido", "Icelandic", "Italian", "Inuktitut", "Japanese", "Javanese", "Georgian", "Kongo", "Kikuyu", "Kuanyama", "Kazakh", "Kalaallisut", "Central Khmer", "Kannada", "Korean", "Kanuri", "Kashmiri", "Kurdish", "Komi", "Cornish", "Kirghiz", "Latin", "Luxembourgish", "Ganda", "Limburgan", "Lingala", "Lao", "Lithuanian", "Luba-Katanga", "Latvian", "Malagasy", "Marshallese", "Maori", "Macedonian", "Malayalam", "Mongolian", "Marathi", "Malay", "Maltese", "Burmese", "Nauru", "Nepali", "Ndonga", "Dutch", "Norwegian", "Navajo", "Chichewa", "Occitan", "Ojibwa", "Oromo", "Oriya", "Ossetian", "Panjabi", "Pali", "Polish", "Pushto", "Portuguese", "Quechua", "Romansh", "Rundi", "Romanian", "Russian", "Kinyarwanda", "Sanskrit", "Sardinian", "Sindhi", "Northern Sami", "Sango", "Sinhala", "Slovak", "Slovenian", "Samoan", "Shona", "Somali", "Albanian", "Serbian", "Swati", "Sotho", "Sundanese", "Swedish", "Swahili", "Tamil", "Telugu", "Tajik", "Thai", "Tigrinya", "Turkmen", "Tagalog", "Tswana", "Tonga", "Turkish", "Tsonga", "Tatar", "Twi", "Tahitian", "Uighur", "Ukrainian", "Urdu", "Uzbek", "Venda", "Vietnamese", "Walloon", "Wolof", "Xhosa", "Yiddish", "Yoruba", "Zhuang", "Chinese", "Zulu"}, + "bcp": {"ar-SA", "cs-CZ", "da-DK", "de-DE", "el-GR", "en-AU", "en-GB", "en-IE", "en-US", "en-ZA", "es-ES", "es-MX", "fi-FI", "fr-CA", "fr-FR", "he-IL", "hi-IN", "hu-HU", "id-ID", "it-IT", "ja-JP", "ko-KR", "nl-BE", "nl-NL", "no-NO", "pl-PL", "pt-BR", "pt-PT", "ro-RO", "ru-RU", "sk-SK", "sv-SE", "th-TH", "tr-TR", "zh-CN", "zh-HK", "zh-TW"}, + "programming": {"A# .NET", "A# (Axiom)", "A-0 System", "A+", "A++", "ABAP", "ABC", "ABC ALGOL", "ABLE", "ABSET", "ABSYS", "ACC", "Accent", "Ace DASL", "ACL2", "ACT-III", "Action!", "ActionScript", "Ada", "Adenine", "Agda", "Agilent VEE", "Agora", "AIMMS", "Alef", "ALF", "ALGOL 58", "ALGOL 60", "ALGOL 68", "ALGOL W", "Alice", "Alma-0", "AmbientTalk", "Amiga E", "AMOS", "AMPL", "APL", "App Inventor for Android's visual block language", "AppleScript", "Arc", "ARexx", "Argus", "AspectJ", "Assembly language", "ATS", "Ateji PX", "AutoHotkey", "Autocoder", "AutoIt", "AutoLISP / Visual LISP", "Averest", "AWK", "Axum", "B", "Babbage", "Bash", "BASIC", "bc", "BCPL", "BeanShell", "Batch (Windows/Dos)", "Bertrand", "BETA", "Bigwig", "Bistro", "BitC", "BLISS", "Blue", "Bon", "Boo", "Boomerang", "Bourne shell", "bash", "ksh", "BREW", "BPEL", "C", "C--", "C++", "C#", "C/AL", "Caché ObjectScript", "C Shell", "Caml", "Candle", "Cayenne", "CDuce", "Cecil", "Cel", "Cesil", "Ceylon", "CFEngine", "CFML", "Cg", "Ch", "Chapel", "CHAIN", "Charity", "Charm", "Chef", "CHILL", "CHIP-8", "chomski", "ChucK", "CICS", "Cilk", "CL", "Claire", "Clarion", "Clean", "Clipper", "CLIST", "Clojure", "CLU", "CMS-2", "COBOL", "Cobra", "CODE", "CoffeeScript", "Cola", "ColdC", "ColdFusion", "COMAL", "Combined Programming Language", "COMIT", "Common Intermediate Language", "Common Lisp", "COMPASS", "Component Pascal", "Constraint Handling Rules", "Converge", "Cool", "Coq", "Coral 66", "Corn", "CorVision", "COWSEL", "CPL", "csh", "CSP", "Csound", "CUDA", "Curl", "Curry", "Cyclone", "Cython", "D", "DASL", "DASL", "Dart", "DataFlex", "Datalog", "DATATRIEVE", "dBase", "dc", "DCL", "Deesel", "Delphi", "DCL", "DinkC", "DIBOL", "Dog", "Draco", "DRAKON", "Dylan", "DYNAMO", "E", "E#", "Ease", "Easy PL/I", "Easy Programming Language", "EASYTRIEVE PLUS", "ECMAScript", "Edinburgh IMP", "EGL", "Eiffel", "ELAN", "Elixir", "Elm", "Emacs Lisp", "Emerald", "Epigram", "EPL", "Erlang", "es", "Escapade", "Escher", "ESPOL", "Esterel", "Etoys", "Euclid", "Euler", "Euphoria", "EusLisp Robot Programming Language", "CMS EXEC", "EXEC 2", "Executable UML", "F", "F#", "Factor", "Falcon", "Fancy", "Fantom", "FAUST", "Felix", "Ferite", "FFP", "Fjölnir", "FL", "Flavors", "Flex", "FLOW-MATIC", "FOCAL", "FOCUS", "FOIL", "FORMAC", "@Formula", "Forth", "Fortran", "Fortress", "FoxBase", "FoxPro", "FP", "FPr", "Franz Lisp", "F-Script", "FSProg", "G", "Google Apps Script", "Game Maker Language", "GameMonkey Script", "GAMS", "GAP", "G-code", "Genie", "GDL", "Gibiane", "GJ", "GEORGE", "GLSL", "GNU E", "GM", "Go", "Go!", "GOAL", "Gödel", "Godiva", "GOM (Good Old Mad)", "Goo", "Gosu", "GOTRAN", "GPSS", "GraphTalk", "GRASS", "Groovy", "Hack (programming language)", "HAL/S", "Hamilton C shell", "Harbour", "Hartmann pipelines", "Haskell", "Haxe", "High Level Assembly", "HLSL", "Hop", "Hope", "Hugo", "Hume", "HyperTalk", "IBM Basic assembly language", "IBM HAScript", "IBM Informix-4GL", "IBM RPG", "ICI", "Icon", "Id", "IDL", "Idris", "IMP", "Inform", "Io", "Ioke", "IPL", "IPTSCRAE", "ISLISP", "ISPF", "ISWIM", "J", "J#", "J++", "JADE", "Jako", "JAL", "Janus", "JASS", "Java", "JavaScript", "JCL", "JEAN", "Join Java", "JOSS", "Joule", "JOVIAL", "Joy", "JScript", "JScript .NET", "JavaFX Script", "Julia", "Jython", "K", "Kaleidoscope", "Karel", "Karel++", "KEE", "Kixtart", "KIF", "Kojo", "Kotlin", "KRC", "KRL", "KUKA", "KRYPTON", "ksh", "L", "L# .NET", "LabVIEW", "Ladder", "Lagoona", "LANSA", "Lasso", "LaTeX", "Lava", "LC-3", "Leda", "Legoscript", "LIL", "LilyPond", "Limbo", "Limnor", "LINC", "Lingo", "Linoleum", "LIS", "LISA", "Lisaac", "Lisp", "Lite-C", "Lithe", "Little b", "Logo", "Logtalk", "LPC", "LSE", "LSL", "LiveCode", "LiveScript", "Lua", "Lucid", "Lustre", "LYaPAS", "Lynx", "M2001", "M4", "Machine code", "MAD", "MAD/I", "Magik", "Magma", "make", "Maple", "MAPPER", "MARK-IV", "Mary", "MASM Microsoft Assembly x86", "Mathematica", "MATLAB", "Maxima", "Macsyma", "Max", "MaxScript", "Maya (MEL)", "MDL", "Mercury", "Mesa", "Metacard", "Metafont", "MetaL", "Microcode", "MicroScript", "MIIS", "MillScript", "MIMIC", "Mirah", "Miranda", "MIVA Script", "ML", "Moby", "Model 204", "Modelica", "Modula", "Modula-2", "Modula-3", "Mohol", "MOO", "Mortran", "Mouse", "MPD", "CIL", "MSL", "MUMPS", "NASM", "NATURAL", "Napier88", "Neko", "Nemerle", "nesC", "NESL", "Net.Data", "NetLogo", "NetRexx", "NewLISP", "NEWP", "Newspeak", "NewtonScript", "NGL", "Nial", "Nice", "Nickle", "NPL", "Not eXactly C", "Not Quite C", "NSIS", "Nu", "NWScript", "NXT-G", "o:XML", "Oak", "Oberon", "Obix", "OBJ2", "Object Lisp", "ObjectLOGO", "Object REXX", "Object Pascal", "Objective-C", "Objective-J", "Obliq", "Obol", "OCaml", "occam", "occam-π", "Octave", "OmniMark", "Onyx", "Opa", "Opal", "OpenCL", "OpenEdge ABL", "OPL", "OPS5", "OptimJ", "Orc", "ORCA/Modula-2", "Oriel", "Orwell", "Oxygene", "Oz", "P#", "ParaSail (programming language)", "PARI/GP", "Pascal", "Pawn", "PCASTL", "PCF", "PEARL", "PeopleCode", "Perl", "PDL", "PHP", "Phrogram", "Pico", "Picolisp", "Pict", "Pike", "PIKT", "PILOT", "Pipelines", "Pizza", "PL-11", "PL/0", "PL/B", "PL/C", "PL/I", "PL/M", "PL/P", "PL/SQL", "PL360", "PLANC", "Plankalkül", "Planner", "PLEX", "PLEXIL", "Plus", "POP-11", "PostScript", "PortablE", "Powerhouse", "PowerBuilder", "PowerShell", "PPL", "Processing", "Processing.js", "Prograph", "PROIV", "Prolog", "PROMAL", "Promela", "PROSE modeling language", "PROTEL", "ProvideX", "Pro*C", "Pure", "Python", "Q (equational programming language)", "Q (programming language from Kx Systems)", "Qalb", "Qi", "QtScript", "QuakeC", "QPL", "R", "R++", "Racket", "RAPID", "Rapira", "Ratfiv", "Ratfor", "rc", "REBOL", "Red", "Redcode", "REFAL", "Reia", "Revolution", "rex", "REXX", "Rlab", "RobotC", "ROOP", "RPG", "RPL", "RSL", "RTL/2", "Ruby", "RuneScript", "Rust", "S", "S2", "S3", "S-Lang", "S-PLUS", "SA-C", "SabreTalk", "SAIL", "SALSA", "SAM76", "SAS", "SASL", "Sather", "Sawzall", "SBL", "Scala", "Scheme", "Scilab", "Scratch", "Script.NET", "Sed", "Seed7", "Self", "SenseTalk", "SequenceL", "SETL", "Shift Script", "SIMPOL", "Shakespeare", "SIGNAL", "SiMPLE", "SIMSCRIPT", "Simula", "Simulink", "SISAL", "SLIP", "SMALL", "Smalltalk", "Small Basic", "SML", "Snap!", "SNOBOL", "SPITBOL", "Snowball", "SOL", "Span", "SPARK", "SPIN", "SP/k", "SPS", "Squeak", "Squirrel", "SR", "S/SL", "Stackless Python", "Starlogo", "Strand", "Stata", "Stateflow", "Subtext", "SuperCollider", "SuperTalk", "Swift (Apple programming language)", "Swift (parallel scripting language)", "SYMPL", "SyncCharts", "SystemVerilog", "T", "TACL", "TACPOL", "TADS", "TAL", "Tcl", "Tea", "TECO", "TELCOMP", "TeX", "TEX", "TIE", "Timber", "TMG", "Tom", "TOM", "Topspeed", "TPU", "Trac", "TTM", "T-SQL", "TTCN", "Turing", "TUTOR", "TXL", "TypeScript", "Turbo C++", "Ubercode", "UCSD Pascal", "Umple", "Unicon", "Uniface", "UNITY", "Unix shell", "UnrealScript", "Vala", "VBA", "VBScript", "Verilog", "VHDL", "Visual Basic", "Visual Basic .NET", "Visual DataFlex", "Visual DialogScript", "Visual Fortran", "Visual FoxPro", "Visual J++", "Visual J#", "Visual Objects", "Visual Prolog", "VSXu", "Vvvv", "WATFIV, WATFOR", "WebDNA", "WebQL", "Windows PowerShell", "Winbatch", "Wolfram", "Wyvern", "X++", "X#", "X10", "XBL", "XC", "XMOS architecture", "xHarbour", "XL", "Xojo", "XOTcl", "XPL", "XPL0", "XQuery", "XSB", "XSLT", "XPath", "Xtend", "Yorick", "YQL", "Z notation", "Zeno", "ZOPL", "ZPL"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/log_level.go b/vendor/github.com/brianvoe/gofakeit/v7/data/log_level.go new file mode 100644 index 0000000000..01d98b63c6 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/log_level.go @@ -0,0 +1,8 @@ +package data + +// LogLevels consists of log levels for several types +var LogLevels = map[string][]string{ + "general": {"error", "warning", "info", "fatal", "trace", "debug"}, + "syslog": {"emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"}, + "apache": {"emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", "trace1-8"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/lorem.go b/vendor/github.com/brianvoe/gofakeit/v7/data/lorem.go new file mode 100644 index 0000000000..b0a8f8a137 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/lorem.go @@ -0,0 +1,6 @@ +package data + +// Lorem consists of lorem ipsum information +var Lorem = map[string][]string{ + "word": {"alias", "consequatur", "aut", "perferendis", "sit", "voluptatem", "accusantium", "doloremque", "aperiam", "eaque", "ipsa", "quae", "ab", "illo", "inventore", "veritatis", "et", "quasi", "architecto", "beatae", "vitae", "dicta", "sunt", "explicabo", "aspernatur", "aut", "odit", "aut", "fugit", "sed", "quia", "consequuntur", "magni", "dolores", "eos", "qui", "ratione", "voluptatem", "sequi", "nesciunt", "neque", "dolorem", "ipsum", "quia", "dolor", "sit", "amet", "consectetur", "adipisci", "velit", "sed", "quia", "non", "numquam", "eius", "modi", "tempora", "incidunt", "ut", "labore", "et", "dolore", "magnam", "aliquam", "quaerat", "voluptatem", "ut", "enim", "ad", "minima", "veniam", "quis", "nostrum", "exercitationem", "ullam", "corporis", "nemo", "enim", "ipsam", "voluptatem", "quia", "voluptas", "sit", "suscipit", "laboriosam", "nisi", "ut", "aliquid", "ex", "ea", "commodi", "consequatur", "quis", "autem", "vel", "eum", "iure", "reprehenderit", "qui", "in", "ea", "voluptate", "velit", "esse", "quam", "nihil", "molestiae", "et", "iusto", "odio", "dignissimos", "ducimus", "qui", "blanditiis", "praesentium", "laudantium", "totam", "rem", "voluptatum", "deleniti", "atque", "corrupti", "quos", "dolores", "et", "quas", "molestias", "excepturi", "sint", "occaecati", "cupiditate", "non", "provident", "sed", "ut", "perspiciatis", "unde", "omnis", "iste", "natus", "error", "similique", "sunt", "in", "culpa", "qui", "officia", "deserunt", "mollitia", "animi", "id", "est", "laborum", "et", "dolorum", "fuga", "et", "harum", "quidem", "rerum", "facilis", "est", "et", "expedita", "distinctio", "nam", "libero", "tempore", "cum", "soluta", "nobis", "est", "eligendi", "optio", "cumque", "nihil", "impedit", "quo", "porro", "quisquam", "est", "qui", "minus", "id", "quod", "maxime", "placeat", "facere", "possimus", "omnis", "voluptas", "assumenda", "est", "omnis", "dolor", "repellendus", "temporibus", "autem", "quibusdam", "et", "aut", "consequatur", "vel", "illum", "qui", "dolorem", "eum", "fugiat", "quo", "voluptas", "nulla", "pariatur", "at", "vero", "eos", "et", "accusamus", "officiis", "debitis", "aut", "rerum", "necessitatibus", "saepe", "eveniet", "ut", "et", "voluptates", "repudiandae", "sint", "et", "molestiae", "non", "recusandae", "itaque", "earum", "rerum", "hic", "tenetur", "a", "sapiente", "delectus", "ut", "aut", "reiciendis", "voluptatibus", "maiores", "doloribus", "asperiores", "repellat"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/minecraft.go b/vendor/github.com/brianvoe/gofakeit/v7/data/minecraft.go new file mode 100644 index 0000000000..015de8af48 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/minecraft.go @@ -0,0 +1,23 @@ +package data + +// Minecraft consists of various minecraft items +var Minecraft = map[string][]string{ + "ore": {"coal", "copper", "iron", "gold", "redstone", "lapis", "diamond", "emerald"}, + "wood": {"oak", "spruce", "birch", "jungle", "acacia", "dark oak"}, + "armortier": {"leather", "chainmail", "iron", "gold", "diamond", "netherite"}, + "armorpart": {"helmet", "chestplate", "leggings", "boots"}, + "weapon": {"sword", "bow", "arrow", "trident", "shield"}, + "tool": {"pickaxe", "axe", "shovel", "hoe", "fishing rod"}, + "dye": {"white", "orange", "magenta", "light blue", "yellow", "lime", "pink", "gray", "light gray", "cyan", "purple", "blue", "brown", "green", "red", "black"}, + "food": {"apple", "baked potato", "beetroot", "beetroot soup", "bread", "cake", "carrot", "chorus fruit", "cooked chicken", "cooked cod", "cooked mutton", "cooked salmon", "cookie", "enchanted golden apple", "golden apple", "glow berry", "golden carrot", "honey bottle", "melon slice", "mushroom stew", "poisonous potato", "potato", "pufferfish", "pumpkin pie", "rabbit stew", "raw beef", "raw chicken", "raw cod", "raw mutton", "raw porkchop", "raw rabbit", "raw salmon", "rotten flesh", "spider eye", "steak", "suspicous stew", "sweet berry", "tropical fish"}, + "animal": {"chicken", "cow", "pig", "rabbit", "sheep", "wolf"}, + "villagerjob": {"armourer", "butcher", "carpenter", "cleric", "farmer", "fisherman", "fletcher", "leatherworker", "librarian", "mason", "nitwit", "shepherd", "toolsmith", "weaponsmith"}, + "villagerstation": {"composter", "smoker", "barrel", "loom", "blast furnace", "brewing stand", "cauldron", "fletching table", "cartography table", "lectern", "smithing table", "stonecutter", "grindstone"}, + "villagerlevel": {"novice", "apprentice", "journeyman", "expert", "master"}, + "mobpassive": {"axolotl", "bat", "cat", "chicken", "cod", "cow", "donkey", "fox", "glow squid", "horse", "mooshroom", "mule", "ocelot", "parrot", "pig", "pufferfish", "rabbit", "salmon", "sheep", "skeleton horse", "snow golem", "squid", "strider", "tropical fish", "turtle", "villager", "wandering trader"}, + "mobneutral": {"bee", "cave spider", "dolphin", "enderman", "goat", "iron golem", "llama", "panda", "piglin", "polar bear", "spider", "trader llama", "wolf", "zombified piglin"}, + "mobhostile": {"blaze", "chicken jockey", "creeper", "drowned", "elder guardian", "endermite", "evoker", "ghast", "guardian", "hoglin phantom", "husk", "magma cube", "phantom", "piglin brute", "pillager", "ravager", "shulker", "silverfish", "skeleton", "skeleton horseman", "slime", "spider jockey", "stray", "vex", "vindicator", "witch", "wither skeleton", "zoglin", "zombie", "zombie villager"}, + "mobboss": {"ender dragon", "wither"}, + "biome": {"plain", "forest", "jungle", "mountain", "desert", "taiga", "snowy tundra", "ice spike", "swamp", "savannah", "badlands", "beach", "stone shore", "river", "ocean", "mushroom island", "the nether", "the end"}, + "weather": {"clear", "rain", "thunder"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/movie.go b/vendor/github.com/brianvoe/gofakeit/v7/data/movie.go new file mode 100644 index 0000000000..9a381ac117 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/movie.go @@ -0,0 +1,130 @@ +package data + +// From IMDB - Top 250 Movies subset to 100 +var Movies = map[string][]string{ + "name": { + "12 Years a Slave", + "1917", + "2001: A Space Odyssey", + "3 Idiots", + "A Beautiful Mind", + "A Clockwork Orange", + "Alien", + "American Beauty", + "American History X", + "Apocalypse Now", + "Avengers: Infinity War", + "Back to the Future", + "Batman Begins", + "Ben-Hur", + "Blade Runner", + "Casablanca", + "Casino", + "Catch Me If You Can", + "Das Leben der Anderen", + "Dead Poets Society", + "Die Hard", + "Django Unchained", + "Fight Club", + "Finding Nemo", + "Forrest Gump", + "Full Metal Jacket", + "Gandhi", + "Gladiator", + "Gone with the Wind", + "Good Will Hunting", + "Goodfellas", + "Green Book", + "Groundhog Day", + "Harry Potter and the Deathly Hallows - Part 2", + "Heat", + "Inception", + "Indiana Jones and the Last Crusade", + "Inglourious Basterds", + "Interstellar", + "Into the Wild", + "Intouchables", + "Joker", + "Judgment at Nuremberg", + "Jurassic Park", + "Kill Bill: Vol. 1", + "L.A. Confidential", + "La vita è bella", + "Lock, Stock and Two Smoking Barrels", + "Léon", + "Mad Max: Fury Road", + "Memento", + "Million Dollar Baby", + "Monsters, Inc.", + "Monty Python and the Holy Grail", + "No Country for Old Men", + "Once Upon a Time in America", + "One Flew Over the Cuckoo's Nest", + "Pirates of the Caribbean: The Curse of the Black Pearl", + "Platoon", + "Prisoners", + "Psycho", + "Pulp Fiction", + "Raiders of the Lost Ark", + "Ratatouille", + "Reservoir Dogs", + "Rocky", + "Saving Private Ryan", + "Scarface", + "Schindler's List", + "Se7en", + "Sherlock Jr.", + "Shutter Island", + "Snatch", + "Spider-Man: No Way Home", + "Star Wars: Episode VI - Return of the Jedi", + "Taxi Driver", + "Terminator 2: Judgment Day", + "The Big Lebowski", + "The Dark Knight", + "The Departed", + "The Empire Strikes Back", + "The Godfather", + "The Green Mile", + "The Lion King", + "The Lord of the Rings: The Fellowship of the Ring", + "The Matrix", + "The Pianist", + "The Prestige", + "The Shawshank Redemption", + "The Terminator", + "The Usual Suspects", + "The Wolf of Wall Street", + "Top Gun: Maverick", + "Toy Story", + "Unforgiven", + "Up", + "V for Vendetta", + "WALL·E", + "Warrior", + "Whiplash", + }, + "genre": { + "Action", + "Adventure", + "Animation", + "Biography", + "Comedy", + "Crime", + "Drama", + "Family", + "Fantasy", + "Film-Noir", + "History", + "Horror", + "Music", + "Musical", + "Mystery", + "Romance", + "Sci-Fi", + "Sport", + "Thriller", + "War", + "Western", + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/payment.go b/vendor/github.com/brianvoe/gofakeit/v7/data/payment.go new file mode 100644 index 0000000000..77147cd87c --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/payment.go @@ -0,0 +1,211 @@ +package data + +// CreditCardInfo contains credit card info +type CreditCardInfo struct { + Display string + Patterns []uint + Gaps []uint + Lengths []uint + Code CreditCardCode +} + +// CreditCardCode contains code type and size +type CreditCardCode struct { + Name string + Size uint +} + +// CreditCardTypes is an array of credit card types +var CreditCardTypes = []string{"visa", "mastercard", "american-express", "diners-club", "discover", "jcb", "unionpay", "maestro", "elo", "hiper", "hipercard"} + +// CreditCards contains payment information +var CreditCards = map[string]CreditCardInfo{ + "visa": { + Display: "Visa", + Patterns: []uint{4}, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16}, + Code: CreditCardCode{ + Name: "CVV", + Size: 3, + }, + }, + "mastercard": { + Display: "Mastercard", + Patterns: []uint{ + 51, 55, + 2221, 2229, + 223, 229, + 23, 26, + 270, 271, + 2720, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16}, + Code: CreditCardCode{ + Name: "CVC", + Size: 3, + }, + }, + "american-express": { + Display: "American Express", + Patterns: []uint{34, 37}, + Gaps: []uint{4, 10}, + Lengths: []uint{15}, + Code: CreditCardCode{ + Name: "CID", + Size: 4, + }, + }, + "diners-club": { + Display: "Diners Club", + Patterns: []uint{ + 300, 305, + 36, 38, 39, + }, + Gaps: []uint{4, 10}, + Lengths: []uint{14, 16, 19}, + Code: CreditCardCode{ + Name: "CVV", + Size: 3, + }, + }, + "discover": { + Display: "Discover", + Patterns: []uint{ + 6011, 644, 649, 65, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16, 19}, + Code: CreditCardCode{ + Name: "CID", + Size: 3, + }, + }, + "jcb": { + Display: "JCB", + Patterns: []uint{ + 2131, 1800, 3528, 3589, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16, 17, 18, 19}, + Code: CreditCardCode{ + Name: "CVV", + Size: 3, + }, + }, + "unionpay": { + Display: "UnionPay", + Patterns: []uint{ + 620, 624, 626, + 62100, 62182, + 62184, 62187, + 62185, 62197, + 62200, 62205, + 622010, 622999, + 622018, + 622019, 622999, + 62207, 62209, + 622126, 622925, + 623, 626, + 6270, 6272, 6276, + 627700, 627779, + 627781, 627799, + 6282, 6289, + 6291, 6292, + 810, + 8110, 8131, + 8132, 8151, + 8152, 8163, + 8164, 817, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{14, 15, 16, 17, 18, 19}, + Code: CreditCardCode{ + Name: "CVN", + Size: 3, + }, + }, + "maestro": { + Display: "Maestro", + Patterns: []uint{ + 493698, + 500000, 506698, + 506779, 508999, + 56, 59, + 6, 63, 67, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{12, 13, 14, 15, 16, 17, 18, 19}, + Code: CreditCardCode{ + Name: "CVC", + Size: 3, + }, + }, + "elo": { + Display: "Elo", + Patterns: []uint{ + 401178, 401179, + 438935, 457631, + 457632, 431274, + 451416, 457393, + 504175, 506699, + 506778, 509000, + 509999, 627780, + 636297, 636368, + 650031, 650033, + 650035, 650051, + 650405, 650439, + 650485, 650538, + 650541, 650598, + 650700, 650718, + 650720, 650727, + 650901, 650978, + 651652, 651679, + 655000, 655019, + 655021, 65505, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16}, + Code: CreditCardCode{ + Name: "CVE", + Size: 3, + }, + }, + "mir": { + Display: "Mir", + Patterns: []uint{2200, 2204}, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16, 17, 18, 19}, + Code: CreditCardCode{ + Name: "CVP2", + Size: 3, + }, + }, + "hiper": { + Display: "Hiper", + Patterns: []uint{ + 637095, + 637568, + 637599, + 637609, + 637612, + }, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16}, + Code: CreditCardCode{ + Name: "CVC", + Size: 3, + }, + }, + "hipercard": { + Display: "Hipercard", + Patterns: []uint{606282}, + Gaps: []uint{4, 8, 12}, + Lengths: []uint{16}, + Code: CreditCardCode{ + Name: "CVC", + Size: 3, + }, + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/person.go b/vendor/github.com/brianvoe/gofakeit/v7/data/person.go new file mode 100644 index 0000000000..8f65a16bf1 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/person.go @@ -0,0 +1,12 @@ +package data + +// Person consists of a slice of people information +var Person = map[string][]string{ + "prefix": {"Mr.", "Mrs.", "Ms.", "Miss", "Dr."}, + "suffix": {"Jr.", "Sr.", "I", "II", "III", "IV", "V", "MD", "DDS", "PhD", "DVM"}, + "first": {"Aaliyah", "Aaron", "Abagail", "Abbey", "Abbie", "Abbigail", "Abby", "Abdiel", "Abdul", "Abdullah", "Abe", "Abel", "Abelardo", "Abigail", "Abigale", "Abigayle", "Abner", "Abraham", "Ada", "Adah", "Adalberto", "Adaline", "Adam", "Adan", "Addie", "Addison", "Adela", "Adelbert", "Adele", "Adelia", "Adeline", "Adell", "Adella", "Adelle", "Aditya", "Adolf", "Adolfo", "Adolph", "Adolphus", "Adonis", "Adrain", "Adrian", "Adriana", "Adrianna", "Adriel", "Adrien", "Adrienne", "Afton", "Aglae", "Agnes", "Agustin", "Agustina", "Ahmad", "Ahmed", "Aida", "Aidan", "Aiden", "Aileen", "Aimee", "Aisha", "Aiyana", "Akeem", "Al", "Alaina", "Alan", "Alana", "Alanis", "Alanna", "Alayna", "Alba", "Albert", "Alberta", "Albertha", "Alberto", "Albin", "Albina", "Alda", "Alden", "Alec", "Aleen", "Alejandra", "Alejandrin", "Alek", "Alena", "Alene", "Alessandra", "Alessandro", "Alessia", "Aletha", "Alex", "Alexa", "Alexander", "Alexandra", "Alexandre", "Alexandrea", "Alexandria", "Alexandrine", "Alexandro", "Alexane", "Alexanne", "Alexie", "Alexis", "Alexys", "Alexzander", "Alf", "Alfonso", "Alfonzo", "Alford", "Alfred", "Alfreda", "Alfredo", "Ali", "Alia", "Alice", "Alicia", "Alisa", "Alisha", "Alison", "Alivia", "Aliya", "Aliyah", "Aliza", "Alize", "Allan", "Allen", "Allene", "Allie", "Allison", "Ally", "Alphonso", "Alta", "Althea", "Alva", "Alvah", "Alvena", "Alvera", "Alverta", "Alvina", "Alvis", "Alyce", "Alycia", "Alysa", "Alysha", "Alyson", "Alysson", "Amalia", "Amanda", "Amani", "Amara", "Amari", "Amaya", "Amber", "Ambrose", "Amelia", "Amelie", "Amely", "America", "Americo", "Amie", "Amina", "Amir", "Amira", "Amiya", "Amos", "Amparo", "Amy", "Amya", "Ana", "Anabel", "Anabelle", "Anahi", "Anais", "Anastacio", "Anastasia", "Anderson", "Andre", "Andreane", "Andreanne", "Andres", "Andrew", "Andy", "Angel", "Angela", "Angelica", "Angelina", "Angeline", "Angelita", "Angelo", "Angie", "Angus", "Anibal", "Anika", "Anissa", "Anita", "Aniya", "Aniyah", "Anjali", "Anna", "Annabel", "Annabell", "Annabelle", "Annalise", "Annamae", "Annamarie", "Anne", "Annetta", "Annette", "Annie", "Ansel", "Ansley", "Anthony", "Antoinette", "Antone", "Antonetta", "Antonette", "Antonia", "Antonietta", "Antonina", "Antonio", "Antwan", "Antwon", "Anya", "April", "Ara", "Araceli", "Aracely", "Arch", "Archibald", "Ardella", "Arden", "Ardith", "Arely", "Ari", "Ariane", "Arianna", "Aric", "Ariel", "Arielle", "Arjun", "Arlene", "Arlie", "Arlo", "Armand", "Armando", "Armani", "Arnaldo", "Arne", "Arno", "Arnold", "Arnoldo", "Arnulfo", "Aron", "Art", "Arthur", "Arturo", "Arvel", "Arvid", "Arvilla", "Aryanna", "Asa", "Asha", "Ashlee", "Ashleigh", "Ashley", "Ashly", "Ashlynn", "Ashton", "Ashtyn", "Asia", "Assunta", "Astrid", "Athena", "Aubree", "Aubrey", "Audie", "Audra", "Audreanne", "Audrey", "August", "Augusta", "Augustine", "Augustus", "Aurelia", "Aurelie", "Aurelio", "Aurore", "Austen", "Austin", "Austyn", "Autumn", "Ava", "Avery", "Avis", "Axel", "Ayana", "Ayden", "Ayla", "Aylin", "Baby", "Bailee", "Bailey", "Barbara", "Barney", "Baron", "Barrett", "Barry", "Bart", "Bartholome", "Barton", "Baylee", "Beatrice", "Beau", "Beaulah", "Bell", "Bella", "Belle", "Ben", "Benedict", "Benjamin", "Bennett", "Bennie", "Benny", "Benton", "Berenice", "Bernadette", "Bernadine", "Bernard", "Bernardo", "Berneice", "Bernhard", "Bernice", "Bernie", "Berniece", "Bernita", "Berry", "Bert", "Berta", "Bertha", "Bertram", "Bertrand", "Beryl", "Bessie", "Beth", "Bethany", "Bethel", "Betsy", "Bette", "Bettie", "Betty", "Bettye", "Beulah", "Beverly", "Bianka", "Bill", "Billie", "Billy", "Birdie", "Blair", "Blaise", "Blake", "Blanca", "Blanche", "Blaze", "Bo", "Bobbie", "Bobby", "Bonita", "Bonnie", "Boris", "Boyd", "Brad", "Braden", "Bradford", "Bradley", "Bradly", "Brady", "Braeden", "Brain", "Brandi", "Brando", "Brandon", "Brandt", "Brandy", "Brandyn", "Brannon", "Branson", "Brant", "Braulio", "Braxton", "Brayan", "Breana", "Breanna", "Breanne", "Brenda", "Brendan", "Brenden", "Brendon", "Brenna", "Brennan", "Brennon", "Brent", "Bret", "Brett", "Bria", "Brian", "Briana", "Brianne", "Brice", "Bridget", "Bridgette", "Bridie", "Brielle", "Brigitte", "Brionna", "Brisa", "Britney", "Brittany", "Brock", "Broderick", "Brody", "Brook", "Brooke", "Brooklyn", "Brooks", "Brown", "Bruce", "Bryana", "Bryce", "Brycen", "Bryon", "Buck", "Bud", "Buddy", "Buford", "Bulah", "Burdette", "Burley", "Burnice", "Buster", "Cade", "Caden", "Caesar", "Caitlyn", "Cale", "Caleb", "Caleigh", "Cali", "Calista", "Callie", "Camden", "Cameron", "Camila", "Camilla", "Camille", "Camren", "Camron", "Camryn", "Camylle", "Candace", "Candelario", "Candice", "Candida", "Candido", "Cara", "Carey", "Carissa", "Carlee", "Carleton", "Carley", "Carli", "Carlie", "Carlo", "Carlos", "Carlotta", "Carmel", "Carmela", "Carmella", "Carmelo", "Carmen", "Carmine", "Carol", "Carolanne", "Carole", "Carolina", "Caroline", "Carolyn", "Carolyne", "Carrie", "Carroll", "Carson", "Carter", "Cary", "Casandra", "Casey", "Casimer", "Casimir", "Casper", "Cassandra", "Cassandre", "Cassidy", "Cassie", "Catalina", "Caterina", "Catharine", "Catherine", "Cathrine", "Cathryn", "Cathy", "Cayla", "Ceasar", "Cecelia", "Cecil", "Cecile", "Cecilia", "Cedrick", "Celestine", "Celestino", "Celia", "Celine", "Cesar", "Chad", "Chadd", "Chadrick", "Chaim", "Chance", "Chandler", "Chanel", "Chanelle", "Charity", "Charlene", "Charles", "Charley", "Charlie", "Charlotte", "Chase", "Chasity", "Chauncey", "Chaya", "Chaz", "Chelsea", "Chelsey", "Chelsie", "Chesley", "Chester", "Chet", "Cheyanne", "Cheyenne", "Chloe", "Chris", "Christ", "Christa", "Christelle", "Christian", "Christiana", "Christina", "Christine", "Christop", "Christophe", "Christopher", "Christy", "Chyna", "Ciara", "Cicero", "Cielo", "Cierra", "Cindy", "Citlalli", "Clair", "Claire", "Clara", "Clarabelle", "Clare", "Clarissa", "Clark", "Claud", "Claude", "Claudia", "Claudie", "Claudine", "Clay", "Clemens", "Clement", "Clementina", "Clementine", "Clemmie", "Cleo", "Cleora", "Cleta", "Cletus", "Cleve", "Cleveland", "Clifford", "Clifton", "Clint", "Clinton", "Clotilde", "Clovis", "Cloyd", "Clyde", "Coby", "Cody", "Colby", "Cole", "Coleman", "Colin", "Colleen", "Collin", "Colt", "Colten", "Colton", "Columbus", "Concepcion", "Conner", "Connie", "Connor", "Conor", "Conrad", "Constance", "Constantin", "Consuelo", "Cooper", "Cora", "Coralie", "Corbin", "Cordelia", "Cordell", "Cordia", "Cordie", "Corene", "Corine", "Cornelius", "Cornell", "Corrine", "Cortez", "Cortney", "Cory", "Coty", "Courtney", "Coy", "Craig", "Crawford", "Creola", "Cristal", "Cristian", "Cristina", "Cristobal", "Cristopher", "Cruz", "Crystal", "Crystel", "Cullen", "Curt", "Curtis", "Cydney", "Cynthia", "Cyril", "Cyrus", "Dagmar", "Dahlia", "Daija", "Daisha", "Daisy", "Dakota", "Dale", "Dallas", "Dallin", "Dalton", "Damaris", "Dameon", "Damian", "Damien", "Damion", "Damon", "Dan", "Dana", "Dandre", "Dane", "Dangelo", "Dangelo", "Danial", "Daniela", "Daniella", "Danielle", "Danika", "Dannie", "Danny", "Dante", "Danyka", "Daphne", "Daphnee", "Daphney", "Darby", "Daren", "Darian", "Dariana", "Darien", "Dario", "Darion", "Darius", "Darlene", "Daron", "Darrel", "Darrell", "Darren", "Darrick", "Darrin", "Darrion", "Darron", "Darryl", "Darwin", "Daryl", "Dashawn", "Dasia", "Dave", "David", "Davin", "Davion", "Davon", "Davonte", "Dawn", "Dawson", "Dax", "Dayana", "Dayna", "Dayne", "Dayton", "Dean", "Deangelo", "Deanna", "Deborah", "Declan", "Dedric", "Dedrick", "Dee", "Deion", "Deja", "Dejah", "Dejon", "Dejuan", "Delaney", "Delbert", "Delfina", "Delia", "Delilah", "Dell", "Della", "Delmer", "Delores", "Delpha", "Delphia", "Delphine", "Delta", "Demarco", "Demarcus", "Demario", "Demetris", "Demetrius", "Demond", "Dena", "Denis", "Dennis", "Deon", "Deondre", "Deontae", "Deonte", "Dereck", "Derek", "Derick", "Deron", "Derrick", "Deshaun", "Deshawn", "Desiree", "Desmond", "Dessie", "Destany", "Destin", "Destinee", "Destiney", "Destini", "Destiny", "Devan", "Devante", "Deven", "Devin", "Devon", "Devonte", "Devyn", "Dewayne", "Dewitt", "Dexter", "Diamond", "Diana", "Dianna", "Diego", "Dillan", "Dillon", "Dimitri", "Dina", "Dino", "Dion", "Dixie", "Dock", "Dolly", "Dolores", "Domenic", "Domenica", "Domenick", "Domenico", "Domingo", "Dominic", "Dominique", "Don", "Donald", "Donato", "Donavon", "Donna", "Donnell", "Donnie", "Donny", "Dora", "Dorcas", "Dorian", "Doris", "Dorothea", "Dorothy", "Dorris", "Dortha", "Dorthy", "Doug", "Douglas", "Dovie", "Doyle", "Drake", "Drew", "Duane", "Dudley", "Dulce", "Duncan", "Durward", "Dustin", "Dusty", "Dwight", "Dylan", "Earl", "Earlene", "Earline", "Earnest", "Earnestine", "Easter", "Easton", "Ebba", "Ebony", "Ed", "Eda", "Edd", "Eddie", "Eden", "Edgar", "Edgardo", "Edison", "Edmond", "Edmund", "Edna", "Eduardo", "Edward", "Edwardo", "Edwin", "Edwina", "Edyth", "Edythe", "Effie", "Efrain", "Efren", "Eileen", "Einar", "Eino", "Eladio", "Elaina", "Elbert", "Elda", "Eldon", "Eldora", "Eldred", "Eldridge", "Eleanora", "Eleanore", "Eleazar", "Electa", "Elena", "Elenor", "Elenora", "Eleonore", "Elfrieda", "Eli", "Elian", "Eliane", "Elias", "Eliezer", "Elijah", "Elinor", "Elinore", "Elisa", "Elisabeth", "Elise", "Eliseo", "Elisha", "Elissa", "Eliza", "Elizabeth", "Ella", "Ellen", "Ellie", "Elliot", "Elliott", "Ellis", "Ellsworth", "Elmer", "Elmira", "Elmo", "Elmore", "Elna", "Elnora", "Elody", "Eloisa", "Eloise", "Elouise", "Eloy", "Elroy", "Elsa", "Else", "Elsie", "Elta", "Elton", "Elva", "Elvera", "Elvie", "Elvis", "Elwin", "Elwyn", "Elyse", "Elyssa", "Elza", "Emanuel", "Emelia", "Emelie", "Emely", "Emerald", "Emerson", "Emery", "Emie", "Emil", "Emile", "Emilia", "Emiliano", "Emilie", "Emilio", "Emily", "Emma", "Emmalee", "Emmanuel", "Emmanuelle", "Emmet", "Emmett", "Emmie", "Emmitt", "Emmy", "Emory", "Ena", "Enid", "Enoch", "Enola", "Enos", "Enrico", "Enrique", "Ephraim", "Era", "Eriberto", "Eric", "Erica", "Erich", "Erick", "Ericka", "Erik", "Erika", "Erin", "Erling", "Erna", "Ernest", "Ernestina", "Ernestine", "Ernesto", "Ernie", "Ervin", "Erwin", "Eryn", "Esmeralda", "Esperanza", "Esta", "Esteban", "Estefania", "Estel", "Estell", "Estella", "Estelle", "Estevan", "Esther", "Estrella", "Etha", "Ethan", "Ethel", "Ethelyn", "Ethyl", "Ettie", "Eudora", "Eugene", "Eugenia", "Eula", "Eulah", "Eulalia", "Euna", "Eunice", "Eusebio", "Eva", "Evalyn", "Evan", "Evangeline", "Evans", "Eve", "Eveline", "Evelyn", "Everardo", "Everett", "Everette", "Evert", "Evie", "Ewald", "Ewell", "Ezekiel", "Ezequiel", "Ezra", "Fabian", "Fabiola", "Fae", "Fannie", "Fanny", "Fatima", "Faustino", "Fausto", "Favian", "Fay", "Faye", "Federico", "Felicia", "Felicita", "Felicity", "Felipa", "Felipe", "Felix", "Felton", "Fermin", "Fern", "Fernando", "Ferne", "Fidel", "Filiberto", "Filomena", "Finn", "Fiona", "Flavie", "Flavio", "Fleta", "Fletcher", "Flo", "Florence", "Florencio", "Florian", "Florida", "Florine", "Flossie", "Floy", "Floyd", "Ford", "Forest", "Forrest", "Foster", "Frances", "Francesca", "Francesco", "Francis", "Francisca", "Francisco", "Franco", "Frank", "Frankie", "Franz", "Fred", "Freda", "Freddie", "Freddy", "Frederic", "Frederick", "Frederik", "Frederique", "Fredrick", "Fredy", "Freeda", "Freeman", "Freida", "Frida", "Frieda", "Friedrich", "Fritz", "Furman", "Gabe", "Gabriel", "Gabriella", "Gabrielle", "Gaetano", "Gage", "Gail", "Gardner", "Garett", "Garfield", "Garland", "Garnet", "Garnett", "Garret", "Garrett", "Garrick", "Garrison", "Garry", "Garth", "Gaston", "Gavin", "Gay", "Gayle", "Gaylord", "Gene", "General", "Genesis", "Genevieve", "Gennaro", "Genoveva", "Geo", "Geoffrey", "George", "Georgette", "Georgiana", "Georgianna", "Geovanni", "Geovanny", "Geovany", "Gerald", "Geraldine", "Gerard", "Gerardo", "Gerda", "Gerhard", "Germaine", "German", "Gerry", "Gerson", "Gertrude", "Gia", "Gianni", "Gideon", "Gilbert", "Gilberto", "Gilda", "Giles", "Gillian", "Gina", "Gino", "Giovani", "Giovanna", "Giovanni", "Giovanny", "Gisselle", "Giuseppe", "Gladyce", "Gladys", "Glen", "Glenda", "Glenna", "Glennie", "Gloria", "Godfrey", "Golda", "Golden", "Gonzalo", "Gordon", "Grace", "Gracie", "Graciela", "Grady", "Graham", "Grant", "Granville", "Grayce", "Grayson", "Green", "Greg", "Gregg", "Gregoria", "Gregorio", "Gregory", "Greta", "Gretchen", "Greyson", "Griffin", "Grover", "Guadalupe", "Gudrun", "Guido", "Guillermo", "Guiseppe", "Gunnar", "Gunner", "Gus", "Gussie", "Gust", "Gustave", "Guy", "Gwen", "Gwendolyn", "Hadley", "Hailee", "Hailey", "Hailie", "Hal", "Haleigh", "Haley", "Halie", "Halle", "Hallie", "Hank", "Hanna", "Hannah", "Hans", "Hardy", "Harley", "Harmon", "Harmony", "Harold", "Harrison", "Harry", "Harvey", "Haskell", "Hassan", "Hassie", "Hattie", "Haven", "Hayden", "Haylee", "Hayley", "Haylie", "Hazel", "Hazle", "Heath", "Heather", "Heaven", "Heber", "Hector", "Heidi", "Helen", "Helena", "Helene", "Helga", "Hellen", "Helmer", "Heloise", "Henderson", "Henri", "Henriette", "Henry", "Herbert", "Herman", "Hermann", "Hermina", "Herminia", "Herminio", "Hershel", "Herta", "Hertha", "Hester", "Hettie", "Hilario", "Hilbert", "Hilda", "Hildegard", "Hillard", "Hillary", "Hilma", "Hilton", "Hipolito", "Hiram", "Hobart", "Holden", "Hollie", "Hollis", "Holly", "Hope", "Horace", "Horacio", "Hortense", "Hosea", "Houston", "Howard", "Howell", "Hoyt", "Hubert", "Hudson", "Hugh", "Hulda", "Humberto", "Hunter", "Hyman", "Ian", "Ibrahim", "Icie", "Ida", "Idell", "Idella", "Ignacio", "Ignatius", "Ike", "Ila", "Ilene", "Iliana", "Ima", "Imani", "Imelda", "Immanuel", "Imogene", "Ines", "Irma", "Irving", "Irwin", "Isaac", "Isabel", "Isabell", "Isabella", "Isabelle", "Isac", "Isadore", "Isai", "Isaiah", "Isaias", "Isidro", "Ismael", "Isobel", "Isom", "Israel", "Issac", "Itzel", "Iva", "Ivah", "Ivory", "Ivy", "Izabella", "Izaiah", "Jabari", "Jace", "Jacey", "Jacinthe", "Jacinto", "Jack", "Jackeline", "Jackie", "Jacklyn", "Jackson", "Jacky", "Jaclyn", "Jacquelyn", "Jacques", "Jacynthe", "Jada", "Jade", "Jaden", "Jadon", "Jadyn", "Jaeden", "Jaida", "Jaiden", "Jailyn", "Jaime", "Jairo", "Jakayla", "Jake", "Jakob", "Jaleel", "Jalen", "Jalon", "Jalyn", "Jamaal", "Jamal", "Jamar", "Jamarcus", "Jamel", "Jameson", "Jamey", "Jamie", "Jamil", "Jamir", "Jamison", "Jammie", "Jan", "Jana", "Janae", "Jane", "Janelle", "Janessa", "Janet", "Janice", "Janick", "Janie", "Janis", "Janiya", "Jannie", "Jany", "Jaquan", "Jaquelin", "Jaqueline", "Jared", "Jaren", "Jarod", "Jaron", "Jarred", "Jarrell", "Jarret", "Jarrett", "Jarrod", "Jarvis", "Jasen", "Jasmin", "Jason", "Jasper", "Jaunita", "Javier", "Javon", "Javonte", "Jay", "Jayce", "Jaycee", "Jayda", "Jayde", "Jayden", "Jaydon", "Jaylan", "Jaylen", "Jaylin", "Jaylon", "Jayme", "Jayne", "Jayson", "Jazlyn", "Jazmin", "Jazmyn", "Jazmyne", "Jean", "Jeanette", "Jeanie", "Jeanne", "Jed", "Jedediah", "Jedidiah", "Jeff", "Jefferey", "Jeffery", "Jeffrey", "Jeffry", "Jena", "Jenifer", "Jennie", "Jennifer", "Jennings", "Jennyfer", "Jensen", "Jerad", "Jerald", "Jeramie", "Jeramy", "Jerel", "Jeremie", "Jeremy", "Jermain", "Jermaine", "Jermey", "Jerod", "Jerome", "Jeromy", "Jerrell", "Jerrod", "Jerrold", "Jerry", "Jess", "Jesse", "Jessica", "Jessie", "Jessika", "Jessy", "Jessyca", "Jesus", "Jett", "Jettie", "Jevon", "Jewel", "Jewell", "Jillian", "Jimmie", "Jimmy", "Jo", "Joan", "Joana", "Joanie", "Joanne", "Joannie", "Joanny", "Joany", "Joaquin", "Jocelyn", "Jodie", "Jody", "Joe", "Joel", "Joelle", "Joesph", "Joey", "Johan", "Johann", "Johanna", "Johathan", "John", "Johnathan", "Johnathon", "Johnnie", "Johnny", "Johnpaul", "Johnson", "Jolie", "Jon", "Jonas", "Jonatan", "Jonathan", "Jonathon", "Jordan", "Jordane", "Jordi", "Jordon", "Jordy", "Jordyn", "Jorge", "Jose", "Josefa", "Josefina", "Joseph", "Josephine", "Josh", "Joshua", "Joshuah", "Josiah", "Josiane", "Josianne", "Josie", "Josue", "Jovan", "Jovani", "Jovanny", "Jovany", "Joy", "Joyce", "Juana", "Juanita", "Judah", "Judd", "Jude", "Judge", "Judson", "Judy", "Jules", "Julia", "Julian", "Juliana", "Julianne", "Julie", "Julien", "Juliet", "Julio", "Julius", "June", "Junior", "Junius", "Justen", "Justice", "Justina", "Justine", "Juston", "Justus", "Justyn", "Juvenal", "Juwan", "Kacey", "Kaci", "Kacie", "Kade", "Kaden", "Kadin", "Kaela", "Kaelyn", "Kaia", "Kailee", "Kailey", "Kailyn", "Kaitlin", "Kaitlyn", "Kale", "Kaleb", "Kaleigh", "Kaley", "Kali", "Kallie", "Kameron", "Kamille", "Kamren", "Kamron", "Kamryn", "Kane", "Kara", "Kareem", "Karelle", "Karen", "Kari", "Kariane", "Karianne", "Karina", "Karine", "Karl", "Karlee", "Karley", "Karli", "Karlie", "Karolann", "Karson", "Kasandra", "Kasey", "Kassandra", "Katarina", "Katelin", "Katelyn", "Katelynn", "Katharina", "Katherine", "Katheryn", "Kathleen", "Kathlyn", "Kathryn", "Kathryne", "Katlyn", "Katlynn", "Katrina", "Katrine", "Kattie", "Kavon", "Kay", "Kaya", "Kaycee", "Kayden", "Kayla", "Kaylah", "Kaylee", "Kayleigh", "Kayley", "Kayli", "Kaylie", "Kaylin", "Keagan", "Keanu", "Keara", "Keaton", "Keegan", "Keeley", "Keely", "Keenan", "Keira", "Keith", "Kellen", "Kelley", "Kelli", "Kellie", "Kelly", "Kelsi", "Kelsie", "Kelton", "Kelvin", "Ken", "Kendall", "Kendra", "Kendrick", "Kenna", "Kennedi", "Kennedy", "Kenneth", "Kennith", "Kenny", "Kenton", "Kenya", "Kenyatta", "Kenyon", "Keon", "Keshaun", "Keshawn", "Keven", "Kevin", "Kevon", "Keyon", "Keyshawn", "Khalid", "Khalil", "Kian", "Kiana", "Kianna", "Kiara", "Kiarra", "Kiel", "Kiera", "Kieran", "Kiley", "Kim", "Kimberly", "King", "Kip", "Kira", "Kirk", "Kirsten", "Kirstin", "Kitty", "Kobe", "Koby", "Kody", "Kolby", "Kole", "Korbin", "Korey", "Kory", "Kraig", "Kris", "Krista", "Kristian", "Kristin", "Kristina", "Kristofer", "Kristoffer", "Kristopher", "Kristy", "Krystal", "Krystel", "Krystina", "Kurt", "Kurtis", "Kyla", "Kyle", "Kylee", "Kyleigh", "Kyler", "Kylie", "Kyra", "Lacey", "Lacy", "Ladarius", "Lafayette", "Laila", "Laisha", "Lamar", "Lambert", "Lamont", "Lance", "Landen", "Lane", "Laney", "Larissa", "Laron", "Larry", "Larue", "Laura", "Laurel", "Lauren", "Laurence", "Lauretta", "Lauriane", "Laurianne", "Laurie", "Laurine", "Laury", "Lauryn", "Lavada", "Lavern", "Laverna", "Laverne", "Lavina", "Lavinia", "Lavon", "Lavonne", "Lawrence", "Lawson", "Layla", "Layne", "Lazaro", "Lea", "Leann", "Leanna", "Leanne", "Leatha", "Leda", "Lee", "Leif", "Leila", "Leilani", "Lela", "Lelah", "Leland", "Lelia", "Lempi", "Lemuel", "Lenna", "Lennie", "Lenny", "Lenora", "Lenore", "Leo", "Leola", "Leon", "Leonard", "Leonardo", "Leone", "Leonel", "Leonie", "Leonor", "Leonora", "Leopold", "Leopoldo", "Leora", "Lera", "Lesley", "Leslie", "Lesly", "Lessie", "Lester", "Leta", "Letha", "Letitia", "Levi", "Lew", "Lewis", "Lexi", "Lexie", "Lexus", "Lia", "Liam", "Liana", "Libbie", "Libby", "Lila", "Lilian", "Liliana", "Liliane", "Lilla", "Lillian", "Lilliana", "Lillie", "Lilly", "Lily", "Lilyan", "Lina", "Lincoln", "Linda", "Lindsay", "Lindsey", "Linnea", "Linnie", "Linwood", "Lionel", "Lisa", "Lisandro", "Lisette", "Litzy", "Liza", "Lizeth", "Lizzie", "Llewellyn", "Lloyd", "Logan", "Lois", "Lola", "Lolita", "Loma", "Lon", "London", "Lonie", "Lonnie", "Lonny", "Lonzo", "Lora", "Loraine", "Loren", "Lorena", "Lorenz", "Lorenza", "Lorenzo", "Lori", "Lorine", "Lorna", "Lottie", "Lou", "Louie", "Louisa", "Lourdes", "Louvenia", "Lowell", "Loy", "Loyal", "Loyce", "Lucas", "Luciano", "Lucie", "Lucienne", "Lucile", "Lucinda", "Lucio", "Lucious", "Lucius", "Lucy", "Ludie", "Ludwig", "Lue", "Luella", "Luigi", "Luis", "Luisa", "Lukas", "Lula", "Lulu", "Luna", "Lupe", "Lura", "Lurline", "Luther", "Luz", "Lyda", "Lydia", "Lyla", "Lynn", "Lyric", "Lysanne", "Mabel", "Mabelle", "Mable", "Mac", "Macey", "Maci", "Macie", "Mack", "Mackenzie", "Macy", "Madaline", "Madalyn", "Maddison", "Madeline", "Madelyn", "Madelynn", "Madge", "Madie", "Madilyn", "Madisen", "Madison", "Madisyn", "Madonna", "Madyson", "Mae", "Maegan", "Maeve", "Mafalda", "Magali", "Magdalen", "Magdalena", "Maggie", "Magnolia", "Magnus", "Maia", "Maida", "Maiya", "Major", "Makayla", "Makenna", "Makenzie", "Malachi", "Malcolm", "Malika", "Malinda", "Mallie", "Mallory", "Malvina", "Mandy", "Manley", "Manuel", "Manuela", "Mara", "Marc", "Marcel", "Marcelina", "Marcelino", "Marcella", "Marcelle", "Marcellus", "Marcelo", "Marcia", "Marco", "Marcos", "Marcus", "Margaret", "Margarete", "Margarett", "Margaretta", "Margarette", "Margarita", "Marge", "Margie", "Margot", "Margret", "Marguerite", "Maria", "Mariah", "Mariam", "Marian", "Mariana", "Mariane", "Marianna", "Marianne", "Mariano", "Maribel", "Marie", "Mariela", "Marielle", "Marietta", "Marilie", "Marilou", "Marilyne", "Marina", "Mario", "Marion", "Marisa", "Marisol", "Maritza", "Marjolaine", "Marjorie", "Marjory", "Mark", "Markus", "Marlee", "Marlen", "Marlene", "Marley", "Marlin", "Marlon", "Marques", "Marquis", "Marquise", "Marshall", "Marta", "Martin", "Martina", "Martine", "Marty", "Marvin", "Mary", "Maryam", "Maryjane", "Maryse", "Mason", "Mateo", "Mathew", "Mathias", "Mathilde", "Matilda", "Matilde", "Matt", "Matteo", "Mattie", "Maud", "Maude", "Maudie", "Maureen", "Maurice", "Mauricio", "Maurine", "Maverick", "Mavis", "Max", "Maxie", "Maxime", "Maximilian", "Maximillia", "Maximillian", "Maximo", "Maximus", "Maxine", "Maxwell", "May", "Maya", "Maybell", "Maybelle", "Maye", "Maymie", "Maynard", "Mayra", "Mazie", "Mckayla", "Mckenna", "Mckenzie", "Meagan", "Meaghan", "Meda", "Megane", "Meggie", "Meghan", "Mekhi", "Melany", "Melba", "Melisa", "Melissa", "Mellie", "Melody", "Melvin", "Melvina", "Melyna", "Melyssa", "Mercedes", "Meredith", "Merl", "Merle", "Merlin", "Merritt", "Mertie", "Mervin", "Meta", "Mia", "Micaela", "Micah", "Michael", "Michaela", "Michale", "Micheal", "Michel", "Michele", "Michelle", "Miguel", "Mikayla", "Mike", "Mikel", "Milan", "Miles", "Milford", "Miller", "Millie", "Milo", "Milton", "Mina", "Minerva", "Minnie", "Miracle", "Mireille", "Mireya", "Misael", "Missouri", "Misty", "Mitchel", "Mitchell", "Mittie", "Modesta", "Modesto", "Mohamed", "Mohammad", "Mohammed", "Moises", "Mollie", "Molly", "Mona", "Monica", "Monique", "Monroe", "Monserrat", "Monserrate", "Montana", "Monte", "Monty", "Morgan", "Moriah", "Morris", "Mortimer", "Morton", "Mose", "Moses", "Moshe", "Mossie", "Mozell", "Mozelle", "Muhammad", "Muriel", "Murl", "Murphy", "Murray", "Mustafa", "Mya", "Myah", "Mylene", "Myles", "Myra", "Myriam", "Myrl", "Myrna", "Myron", "Myrtice", "Myrtie", "Myrtis", "Myrtle", "Nadia", "Nakia", "Name", "Nannie", "Naomi", "Naomie", "Napoleon", "Narciso", "Nash", "Nasir", "Nat", "Natalia", "Natalie", "Natasha", "Nathan", "Nathanael", "Nathanial", "Nathaniel", "Nathen", "Nayeli", "Neal", "Ned", "Nedra", "Neha", "Neil", "Nelda", "Nella", "Nelle", "Nellie", "Nels", "Nelson", "Neoma", "Nestor", "Nettie", "Neva", "Newell", "Newton", "Nia", "Nicholas", "Nicholaus", "Nichole", "Nick", "Nicklaus", "Nickolas", "Nico", "Nicola", "Nicolas", "Nicole", "Nicolette", "Nigel", "Nikita", "Nikki", "Nikko", "Niko", "Nikolas", "Nils", "Nina", "Noah", "Noble", "Noe", "Noel", "Noelia", "Noemi", "Noemie", "Noemy", "Nola", "Nolan", "Nona", "Nora", "Norbert", "Norberto", "Norene", "Norma", "Norris", "Norval", "Norwood", "Nova", "Novella", "Nya", "Nyah", "Nyasia", "Obie", "Oceane", "Ocie", "Octavia", "Oda", "Odell", "Odessa", "Odie", "Ofelia", "Okey", "Ola", "Olaf", "Ole", "Olen", "Oleta", "Olga", "Olin", "Oliver", "Ollie", "Oma", "Omari", "Omer", "Ona", "Onie", "Opal", "Ophelia", "Ora", "Oral", "Oran", "Oren", "Orie", "Orin", "Orion", "Orland", "Orlando", "Orlo", "Orpha", "Orrin", "Orval", "Orville", "Osbaldo", "Osborne", "Oscar", "Osvaldo", "Oswald", "Oswaldo", "Otha", "Otho", "Otilia", "Otis", "Ottilie", "Ottis", "Otto", "Ova", "Owen", "Ozella", "Pablo", "Paige", "Palma", "Pamela", "Pansy", "Paolo", "Paris", "Parker", "Pascale", "Pasquale", "Pat", "Patience", "Patricia", "Patrick", "Patsy", "Pattie", "Paul", "Paula", "Pauline", "Paxton", "Payton", "Pearl", "Pearlie", "Pearline", "Pedro", "Peggie", "Penelope", "Percival", "Percy", "Perry", "Pete", "Peter", "Petra", "Peyton", "Philip", "Phoebe", "Phyllis", "Pierce", "Pierre", "Pietro", "Pink", "Pinkie", "Piper", "Polly", "Porter", "Precious", "Presley", "Preston", "Price", "Prince", "Princess", "Priscilla", "Providenci", "Prudence", "Queen", "Queenie", "Quentin", "Quincy", "Quinn", "Quinten", "Quinton", "Rachael", "Rachel", "Rachelle", "Rae", "Raegan", "Rafael", "Rafaela", "Raheem", "Rahsaan", "Rahul", "Raina", "Raleigh", "Ralph", "Ramiro", "Ramon", "Ramona", "Randal", "Randall", "Randi", "Randy", "Ransom", "Raoul", "Raphael", "Raphaelle", "Raquel", "Rashad", "Rashawn", "Rasheed", "Raul", "Raven", "Ray", "Raymond", "Raymundo", "Reagan", "Reanna", "Reba", "Rebeca", "Rebecca", "Rebeka", "Rebekah", "Reece", "Reed", "Reese", "Regan", "Reggie", "Reginald", "Reid", "Reilly", "Reina", "Reinhold", "Remington", "Rene", "Renee", "Ressie", "Reta", "Retha", "Retta", "Reuben", "Reva", "Rex", "Rey", "Reyes", "Reymundo", "Reyna", "Reynold", "Rhea", "Rhett", "Rhianna", "Rhiannon", "Rhoda", "Ricardo", "Richard", "Richie", "Richmond", "Rick", "Rickey", "Rickie", "Ricky", "Rico", "Rigoberto", "Riley", "Rita", "River", "Robb", "Robbie", "Robert", "Roberta", "Roberto", "Robin", "Robyn", "Rocio", "Rocky", "Rod", "Roderick", "Rodger", "Rodolfo", "Rodrick", "Rodrigo", "Roel", "Rogelio", "Roger", "Rogers", "Rolando", "Rollin", "Roma", "Romaine", "Roman", "Ron", "Ronaldo", "Ronny", "Roosevelt", "Rory", "Rosa", "Rosalee", "Rosalia", "Rosalind", "Rosalinda", "Rosalyn", "Rosamond", "Rosanna", "Rosario", "Roscoe", "Rose", "Rosella", "Roselyn", "Rosemarie", "Rosemary", "Rosendo", "Rosetta", "Rosie", "Rosina", "Roslyn", "Ross", "Rossie", "Rowan", "Rowena", "Rowland", "Roxane", "Roxanne", "Roy", "Royal", "Royce", "Rozella", "Ruben", "Rubie", "Ruby", "Rubye", "Rudolph", "Rudy", "Rupert", "Russ", "Russel", "Russell", "Rusty", "Ruth", "Ruthe", "Ruthie", "Ryan", "Ryann", "Ryder", "Rylan", "Rylee", "Ryleigh", "Ryley", "Sabina", "Sabrina", "Sabryna", "Sadie", "Sadye", "Sage", "Saige", "Sallie", "Sally", "Salma", "Salvador", "Salvatore", "Sam", "Samanta", "Samantha", "Samara", "Samir", "Sammie", "Sammy", "Samson", "Sandra", "Sandrine", "Sandy", "Sanford", "Santa", "Santiago", "Santina", "Santino", "Santos", "Sarah", "Sarai", "Sarina", "Sasha", "Saul", "Savanah", "Savanna", "Savannah", "Savion", "Scarlett", "Schuyler", "Scot", "Scottie", "Scotty", "Seamus", "Sean", "Sebastian", "Sedrick", "Selena", "Selina", "Selmer", "Serena", "Serenity", "Seth", "Shad", "Shaina", "Shakira", "Shana", "Shane", "Shanel", "Shanelle", "Shania", "Shanie", "Shaniya", "Shanna", "Shannon", "Shanny", "Shanon", "Shany", "Sharon", "Shaun", "Shawn", "Shawna", "Shaylee", "Shayna", "Shayne", "Shea", "Sheila", "Sheldon", "Shemar", "Sheridan", "Sherman", "Sherwood", "Shirley", "Shyann", "Shyanne", "Sibyl", "Sid", "Sidney", "Sienna", "Sierra", "Sigmund", "Sigrid", "Sigurd", "Silas", "Sim", "Simeon", "Simone", "Sincere", "Sister", "Skye", "Skyla", "Skylar", "Sofia", "Soledad", "Solon", "Sonia", "Sonny", "Sonya", "Sophia", "Sophie", "Spencer", "Stacey", "Stacy", "Stan", "Stanford", "Stanley", "Stanton", "Stefan", "Stefanie", "Stella", "Stephan", "Stephania", "Stephanie", "Stephany", "Stephen", "Stephon", "Sterling", "Steve", "Stevie", "Stewart", "Stone", "Stuart", "Summer", "Sunny", "Susan", "Susana", "Susanna", "Susie", "Suzanne", "Sven", "Syble", "Sydnee", "Sydney", "Sydni", "Sydnie", "Sylvan", "Sylvester", "Sylvia", "Tabitha", "Tad", "Talia", "Talon", "Tamara", "Tamia", "Tania", "Tanner", "Tanya", "Tara", "Taryn", "Tate", "Tatum", "Tatyana", "Taurean", "Tavares", "Taya", "Taylor", "Teagan", "Ted", "Telly", "Terence", "Teresa", "Terrance", "Terrell", "Terrence", "Terrill", "Terry", "Tess", "Tessie", "Tevin", "Thad", "Thaddeus", "Thalia", "Thea", "Thelma", "Theo", "Theodora", "Theodore", "Theresa", "Therese", "Theresia", "Theron", "Thomas", "Thora", "Thurman", "Tia", "Tiana", "Tianna", "Tiara", "Tierra", "Tiffany", "Tillman", "Timmothy", "Timmy", "Timothy", "Tina", "Tito", "Titus", "Tobin", "Toby", "Tod", "Tom", "Tomas", "Tomasa", "Tommie", "Toney", "Toni", "Tony", "Torey", "Torrance", "Torrey", "Toy", "Trace", "Tracey", "Tracy", "Travis", "Travon", "Tre", "Tremaine", "Tremayne", "Trent", "Trenton", "Tressa", "Tressie", "Treva", "Trever", "Trevion", "Trevor", "Trey", "Trinity", "Trisha", "Tristian", "Tristin", "Triston", "Troy", "Trudie", "Trycia", "Trystan", "Turner", "Twila", "Tyler", "Tyra", "Tyree", "Tyreek", "Tyrel", "Tyrell", "Tyrese", "Tyrique", "Tyshawn", "Tyson", "Ubaldo", "Ulices", "Ulises", "Una", "Unique", "Urban", "Uriah", "Uriel", "Ursula", "Vada", "Valentin", "Valentina", "Valentine", "Valerie", "Vallie", "Van", "Vance", "Vanessa", "Vaughn", "Veda", "Velda", "Vella", "Velma", "Velva", "Vena", "Verda", "Verdie", "Vergie", "Verla", "Verlie", "Vern", "Verna", "Verner", "Vernice", "Vernie", "Vernon", "Verona", "Veronica", "Vesta", "Vicenta", "Vicente", "Vickie", "Vicky", "Victor", "Victoria", "Vida", "Vidal", "Vilma", "Vince", "Vincent", "Vincenza", "Vincenzo", "Vinnie", "Viola", "Violet", "Violette", "Virgie", "Virgil", "Virginia", "Virginie", "Vita", "Vito", "Viva", "Vivian", "Viviane", "Vivianne", "Vivien", "Vivienne", "Vladimir", "Wade", "Waino", "Waldo", "Walker", "Wallace", "Walter", "Walton", "Wanda", "Ward", "Warren", "Watson", "Wava", "Waylon", "Wayne", "Webster", "Weldon", "Wellington", "Wendell", "Wendy", "Werner", "Westley", "Weston", "Whitney", "Wilber", "Wilbert", "Wilburn", "Wiley", "Wilford", "Wilfred", "Wilfredo", "Wilfrid", "Wilhelm", "Wilhelmine", "Will", "Willa", "Willard", "William", "Willie", "Willis", "Willow", "Willy", "Wilma", "Wilmer", "Wilson", "Wilton", "Winfield", "Winifred", "Winnifred", "Winona", "Winston", "Woodrow", "Wyatt", "Wyman", "Xander", "Xavier", "Xzavier", "Yadira", "Yasmeen", "Yasmin", "Yasmine", "Yazmin", "Yesenia", "Yessenia", "Yolanda", "Yoshiko", "Yvette", "Yvonne", "Zachariah", "Zachary", "Zachery", "Zack", "Zackary", "Zackery", "Zakary", "Zander", "Zane", "Zaria", "Zechariah", "Zelda", "Zella", "Zelma", "Zena", "Zetta", "Zion", "Zita", "Zoe", "Zoey", "Zoie", "Zoila", "Zola", "Zora", "Zula"}, + "middle": {"Abdul", "Abdullah", "Abigail", "Ada", "Adam", "Adelaide", "Adele", "Adelina", "Adrian", "Adriana", "Agnes", "Agnolo", "Ahmed", "Aida", "Aileen", "Aimee", "Akilesh", "Akio", "Alan", "Alana", "Alejandro", "Alex", "Ali", "Alice", "Alicia", "Alina", "Alison", "Alita", "Allegretta", "Alonzo", "Alyssa", "Aman", "Amara", "Amelda", "Amelia", "Amenra", "Amina", "Amir", "Amitabh", "Amy", "Ana", "Anastasia", "André", "Andrea", "Andrei", "Andrew", "Andy", "Angel", "Angela", "Anita", "Ann", "Anna", "Anne", "Annette", "Anthony", "Antioco", "Antonio", "Arduino", "Aria", "Ariana", "Ariel", "Aris", "Arjun", "Armando", "Asha", "Ashton", "Asong", "Athena", "Audrey", "August", "Aura", "Aurelia", "Austen", "Ava", "Avery", "Avril", "Badru", "Bailey", "Bakul", "Baldwin", "Bao", "Barack", "Bear", "Beatrice", "Beau", "Belinda", "Bella", "Belle", "Ben", "Benjamin", "Bertha", "Beverly", "Bharati", "Bhoja", "Bhuma", "Bianca", "Bird", "Birdie", "Bishvajit", "Bjorn", "Blair", "Blake", "Blanca", "Bliss", "Blue", "Bo", "Bobbie", "Bonnie", "Boris", "Bradley", "Brandt", "Braulia", "Breck", "Bree", "Brett", "Brianna", "Bridget", "Brie", "Brielle", "Brittany", "Brizio", "Brook", "Brooke", "Brooks", "Bruce", "Bryce", "Bryn", "Brynn", "Burke", "Cajetan", "Calvin", "Cameron", "Camilla", "Candice", "Carla", "Carlos", "Carmen", "Caroline", "Carson", "Casey", "Cash", "Cassandra", "Cassidy", "Catherine", "Cecelia", "Cecilia", "Cedric", "Celeste", "Celia", "Celso", "Chahna", "Chance", "Chander", "Chandler", "Chang", "Charles", "Charlie", "Charlotte", "Chen", "Chintak", "Chloe", "Chris", "Christine", "Chung", "Cimeron", "Cindy", "Ciprianna", "Ciro", "Claire", "Clara", "Clarissa", "Clark", "Clarke", "Claude", "Claudia", "Clay", "Clementine", "Clint", "Cody", "Cole", "Colette", "Cora", "Cordelia", "Corey", "Corinne", "Cory", "Cosme", "Courtney", "Cree", "Crew", "Cynthia", "Cyprienne", "Cyrus", "Daan", "Dada", "Daisy", "Dakota", "Dale", "Damodar", "Dan", "Dana", "Dane", "Daniel", "Danielle", "Danveer", "Daphne", "Darla", "David", "Davide", "Dawn", "Dax", "Dean", "Deborah", "Delilah", "Denise", "Denver", "Deshal", "Deshawn", "Dev", "Devin", "Dhavala", "Diana", "Diane", "Diego", "Dmitri", "Dolores", "Dolorita", "Donato", "Dong", "Donna", "Donte", "Donya", "Dora", "Doris", "Dorothy", "Drake", "Drew", "Dru", "Dylan", "Ean", "Edith", "Eduardo", "Edward", "Eila", "Eileen", "Elaine", "Elda", "Eleanor", "Elena", "Eliana", "Elias", "Elise", "Eliza", "Elizabeth", "Ella", "Elle", "Ellen", "Ellie", "Ellis", "Eloise", "Elsa", "Elsie", "Em", "Emerson", "Emery", "Emilie", "Emilio", "Emily", "Emma", "Emmett", "Enrico", "Enrique", "Epifania", "Erica", "Erik", "Erin", "Eroica", "Esperanza", "Estelle", "Esther", "Etta", "Ettore", "Eva", "Evan", "Eve", "Evelyn", "Everett", "Faith", "Farid", "Faye", "Federico", "Felicity", "Felipe", "Felix", "Fern", "Fernando", "Finley", "Finn", "Fiona", "Fitz", "Flint", "Flora", "Florence", "Flynn", "Folke", "Fonzo", "Fox", "Frances", "Francis", "Francisco", "Francois", "François", "Frank", "Frankie", "Freya", "Fumio", "Fynn", "Gabriel", "Gabriella", "Gael", "Gage", "Gail", "Gemma", "Genevieve", "George", "Georgia", "Geraldine", "Giannino", "Ginetta", "Gioia", "Giselle", "Giuseppe", "Giustino", "Glenn", "Gloria", "Glory", "Grace", "Grant", "Gray", "Greer", "Greta", "Guido", "Guillermo", "Gulshan", "Gus", "Gwen", "Gyula", "Hank", "Hannah", "Hans", "Harley", "Harper", "Harriet", "Harrison", "Harshad", "Haruki", "Hayden", "Hayes", "Haze", "Hazel", "Heath", "Heather", "Hector", "Helen", "Helena", "Henry", "Hideki", "Hidetoshi", "Himesh", "Hiro", "Hiroaki", "Hirofumi", "Hirokazu", "Hiroshi", "Hiroto", "Hiroyuki", "Holly", "Honor", "Hope", "Hugh", "Hugo", "Hunter", "Ida", "Ignacio", "Imogen", "Ingrid", "Irene", "Iris", "Isaac", "Isabel", "Isabella", "Isabelle", "Ivan", "Ivy", "Jace", "Jack", "Jacqueline", "Jade", "Jaden", "Jae", "Jai", "Jaime", "Jamal", "James", "Jamie", "Jan", "Janak", "Jane", "Janet", "Janice", "Jasmine", "Jasper", "Javier", "Jax", "Jay", "Jayden", "Jayne", "Jean", "Jeanne", "Jed", "Jenna", "Jennifer", "Jesse", "Jessica", "Jill", "Jin", "Joan", "Joanna", "João", "Jocelyn", "Jodi", "Jody", "Joe", "Joey", "Johanna", "Johar", "John", "Jolene", "Jordan", "Jorge", "Jose", "José", "Joseph", "Josephine", "Josie", "Joy", "Joyce", "Juan", "Juanita", "Judd", "Jude", "Judith", "Jules", "Julia", "Julian", "Juliana", "Julianne", "Julie", "June", "Justine", "Kael", "Kai", "Kane", "Karen", "Kate", "Katherine", "Kathleen", "Kathryn", "Katie", "Katrina", "Kay", "Kayla", "Kazuki", "Keira", "Kelly", "Kelsey", "Kendall", "Kendra", "Kennedy", "Kent", "Kenta", "Kerry", "Khaled", "Khloe", "Kiara", "Kim", "Kimberly", "Kit", "Kiyoshi", "Klaus", "Knight", "Knox", "Koen", "Koi", "Koichi", "Koji", "Kolt", "Kristen", "Kristina", "Kurt", "Kwame", "Kye", "Kylie", "Lacey", "Laine", "Lake", "Lakshman", "Lalika", "Lane", "Lark", "Lars", "Laurel", "Layne", "Lee", "Leif", "Lennon", "Leo", "Leon", "Leslie", "Liam", "Liberty", "Lilian", "Lillian", "Lillie", "Link", "Liz", "Locke", "Logan", "Lona", "Lorena", "Lorenzo", "Lou", "Louise", "Love", "Lucia", "Lucy", "Luis", "Luiz", "Luke", "Lupita", "Lux", "Luz", "Lydia", "Lynn", "Mabel", "Mac", "Mack", "Mackenzie", "Madeline", "Madison", "Madona", "Mae", "Mael", "Makoto", "Manuel", "Manuela", "Maple", "Marc", "Marco", "Margaret", "Margo", "Margot", "Maria", "Mariano", "Maricela", "Marilyn", "Mario", "Mark", "Marley", "Mars", "Marti", "Mary", "Mason", "Matthew", "Mavis", "Max", "May", "Mazie", "Mei", "Melody", "Mercy", "Merle", "Micah", "Michael", "Miguel", "Mina", "Ming", "Mohamed", "Mollie", "Monroe", "Morgan", "Muhammad", "Musetta", "Myra", "Nadine", "Naomi", "Nardo", "Nat", "Natalie", "Neal", "Neil", "Nellie", "Nerola", "Nevada", "Neve", "Nikolai", "Niles", "Noel", "Nola", "Nora", "Nuru", "Oakley", "Olive", "Oliver", "Opal", "Orazio", "Ortensa", "Ortensia", "Osamu", "Oscar", "Otto", "Pablo", "Paige", "Pancho", "Paris", "Parker", "Pat", "Patrick", "Paul", "Pauli", "Pax", "Peace", "Pearl", "Pedro", "Penelope", "Penn", "Penny", "Peter", "Petra", "Peyton", "Phoenix", "Pierce", "Pierre", "Pilar", "Porter", "Praise", "Pratap", "Presley", "Priscilla", "Quinn", "Rachanna", "Radames", "Rae", "Rafael", "Rain", "Raine", "Ramiro", "Ramon", "Ramona", "Raphael", "Raul", "Ravi", "Ray", "Rayne", "Reagan", "Reece", "Reed", "Reese", "Rei", "Reid", "Reilly", "Remy", "Ren", "Reyes", "Rhodes", "Ricardo", "Richard", "Riley", "Rita", "River", "Rivera", "Roan", "Robert", "Roberto", "Robin", "Robt", "Rodrigo", "Roma", "Romelia", "Rory", "Rosa", "Rosalee", "Rosalie", "Rosalynn", "Rosario", "Rose", "Ross", "Rowan", "Ruben", "Ruby", "Rue", "Rush", "Russell", "Ruth", "Ryan", "Saad", "Saariq", "Sade", "Sadie", "Sagara", "Sage", "Saige", "Saint", "Salvadora", "Sam", "Samir", "Samuel", "Sante", "Santiago", "Sara", "Sasha", "Satoshi", "Scott", "Sean", "Sebastian", "Sergei", "Sergio", "Seth", "Shae", "Shai", "Shane", "Shannon", "Shashi", "Shaun", "Shawn", "Shawnee", "Shay", "Shea", "Shelby", "Shin", "Sidney", "Simon", "Sky", "Skye", "Skyler", "Sol", "Sophie", "Spencer", "Star", "Starr", "Stella", "Steve", "Stevie", "Storm", "Susan", "Sven", "Sybil", "Sydney", "Tahj", "Takashi", "Takeshi", "Taryn", "Tatum", "Taylor", "Teagan", "Terry", "Tess", "Thea", "Theodore", "Thomas", "Tilly", "Timothy", "Tosca", "Trent", "Tripp", "Tristan", "Truth", "Tyler", "Tyrone", "Uberto", "Ursus", "Val", "Vandelia", "Vaughn", "Vera", "Vernon", "Verona", "Vianna", "Victoria", "Vida", "Vieda", "Vince", "Vincent", "Violet", "Virginia", "Vivian", "Vladimir", "Wade", "Wayne", "Wes", "Wesley", "West", "Whitney", "Will", "Willa", "William", "Willie", "Winston", "Winter", "Wolf", "Wren", "Wynn", "Xavier", "Yasuo", "Yoel", "Yolanda", "Yoshi", "Yoshiaki", "Yoshihiro", "Yoshiki", "Yoshinori", "Yoshio", "Yusuf", "Yutaka", "Zain", "Zane", "Zayd", "Zelda", "Zeus", "Zev", "Zhang", "Zhen", "Zola", "Zora", "Zuni"}, + "last": {"Abbott", "Abernathy", "Abshire", "Adams", "Altenwerth", "Anderson", "Ankunding", "Armstrong", "Auer", "Aufderhar", "Bahringer", "Bailey", "Balistreri", "Barrows", "Bartell", "Bartoletti", "Barton", "Bashirian", "Batz", "Bauch", "Baumbach", "Bayer", "Beahan", "Beatty", "Bechtelar", "Becker", "Bednar", "Beer", "Beier", "Berge", "Bergnaum", "Bergstrom", "Bernhard", "Bernier", "Bins", "Blanda", "Blick", "Block", "Bode", "Boehm", "Bogan", "Bogisich", "Borer", "Bosco", "Botsford", "Boyer", "Boyle", "Bradtke", "Brakus", "Braun", "Breitenberg", "Brekke", "Brown", "Bruen", "Buckridge", "Carroll", "Carter", "Cartwright", "Casper", "Cassin", "Champlin", "Christiansen", "Cole", "Collier", "Collins", "Conn", "Connelly", "Conroy", "Considine", "Corkery", "Cormier", "Corwin", "Cremin", "Crist", "Crona", "Cronin", "Crooks", "Cruickshank", "Cummerata", "Cummings", "Dach", "Damore", "Daniel", "Dare", "Daugherty", "Davis", "Deckow", "Denesik", "Dibbert", "Dickens", "Dicki", "Dickinson", "Dietrich", "Donnelly", "Dooley", "Douglas", "Doyle", "DuBuque", "Durgan", "Ebert", "Effertz", "Eichmann", "Emard", "Emmerich", "Erdman", "Ernser", "Fadel", "Fahey", "Farrell", "Fay", "Feeney", "Feest", "Feil", "Ferry", "Fisher", "Flatley", "Frami", "Franecki", "Friesen", "Fritsch", "Funk", "Gaylord", "Gerhold", "Gerlach", "Gibson", "Gislason", "Gleason", "Gleichner", "Glover", "Goldner", "Goodwin", "Gorczany", "Gottlieb", "Goyette", "Grady", "Graham", "Grant", "Green", "Greenfelder", "Greenholt", "Grimes", "Gulgowski", "Gusikowski", "Gutkowski", "Gutmann", "Haag", "Hackett", "Hagenes", "Hahn", "Haley", "Halvorson", "Hamill", "Hammes", "Hand", "Hane", "Hansen", "Harber", "Harris", "Hartmann", "Harvey", "Hauck", "Hayes", "Heaney", "Heathcote", "Hegmann", "Heidenreich", "Heller", "Herman", "Hermann", "Hermiston", "Herzog", "Hessel", "Hettinger", "Hickle", "Hilll", "Hills", "Hilpert", "Hintz", "Hirthe", "Hodkiewicz", "Hoeger", "Homenick", "Hoppe", "Howe", "Howell", "Hudson", "Huel", "Huels", "Hyatt", "Jacobi", "Jacobs", "Jacobson", "Jakubowski", "Jaskolski", "Jast", "Jenkins", "Jerde", "Jewess", "Johns", "Johnson", "Johnston", "Jones", "Kassulke", "Kautzer", "Keebler", "Keeling", "Kemmer", "Kerluke", "Kertzmann", "Kessler", "Kiehn", "Kihn", "Kilback", "King", "Kirlin", "Klein", "Kling", "Klocko", "Koch", "Koelpin", "Koepp", "Kohler", "Konopelski", "Koss", "Kovacek", "Kozey", "Krajcik", "Kreiger", "Kris", "Kshlerin", "Kub", "Kuhic", "Kuhlman", "Kuhn", "Kulas", "Kunde", "Kunze", "Kuphal", "Kutch", "Kuvalis", "Labadie", "Lakin", "Lang", "Langosh", "Langworth", "Larkin", "Larson", "Leannon", "Lebsack", "Ledner", "Leffler", "Legros", "Lehner", "Lemke", "Lesch", "Leuschke", "Lind", "Lindgren", "Littel", "Little", "Lockman", "Lowe", "Lubowitz", "Lueilwitz", "Luettgen", "Lynch", "Macejkovic", "Maggio", "Mann", "Mante", "Marks", "Marquardt", "Marvin", "Mayer", "Mayert", "McClure", "McCullough", "McDermott", "McGlynn", "McKenzie", "McLaughlin", "Medhurst", "Mertz", "Metz", "Miller", "Mills", "Mitchell", "Moen", "Mohr", "Monahan", "Moore", "Morar", "Morissette", "Mosciski", "Mraz", "Mueller", "Muller", "Murazik", "Murphy", "Murray", "Nader", "Nicolas", "Nienow", "Nikolaus", "Nitzsche", "Nolan", "Oberbrunner", "Okuneva", "Olson", "Ondricka", "OReilly", "Orn", "Ortiz", "Osinski", "Pacocha", "Padberg", "Pagac", "Parisian", "Parker", "Paucek", "Pfannerstill", "Pfeffer", "Pollich", "Pouros", "Powlowski", "Predovic", "Price", "Prohaska", "Prosacco", "Purdy", "Quigley", "Quitzon", "Rath", "Ratke", "Rau", "Raynor", "Reichel", "Reichert", "Reilly", "Reinger", "Rempel", "Renner", "Reynolds", "Rice", "Rippin", "Ritchie", "Robel", "Roberts", "Rodriguez", "Rogahn", "Rohan", "Rolfson", "Romaguera", "Roob", "Rosenbaum", "Rowe", "Ruecker", "Runolfsdottir", "Runolfsson", "Runte", "Russel", "Rutherford", "Ryan", "Sanford", "Satterfield", "Sauer", "Sawayn", "Schaden", "Schaefer", "Schamberger", "Schiller", "Schimmel", "Schinner", "Schmeler", "Schmidt", "Schmitt", "Schneider", "Schoen", "Schowalter", "Schroeder", "Schulist", "Schultz", "Schumm", "Schuppe", "Schuster", "Senger", "Shanahan", "Shields", "Simonis", "Sipes", "Skiles", "Smith", "Smitham", "Spencer", "Spinka", "Sporer", "Stamm", "Stanton", "Stark", "Stehr", "Steuber", "Stiedemann", "Stokes", "Stoltenberg", "Stracke", "Streich", "Stroman", "Strosin", "Swaniawski", "Swift", "Terry", "Thiel", "Thompson", "Tillman", "Torp", "Torphy", "Towne", "Toy", "Trantow", "Tremblay", "Treutel", "Tromp", "Turcotte", "Turner", "Ullrich", "Upton", "Vandervort", "Veum", "Volkman", "Von", "VonRueden", "Waelchi", "Walker", "Walsh", "Walter", "Ward", "Waters", "Watsica", "Weber", "Wehner", "Weimann", "Weissnat", "Welch", "West", "White", "Wiegand", "Wilderman", "Wilkinson", "Will", "Williamson", "Willms", "Windler", "Wintheiser", "Wisoky", "Wisozk", "Witting", "Wiza", "Wolf", "Wolff", "Wuckert", "Wunsch", "Wyman", "Yost", "Yundt", "Zboncak", "Zemlak", "Ziemann", "Zieme", "Zulauf"}, + "hobby": {"3D printing", "Acrobatics", "Acting", "Amateur radio", "Animation", "Aquascaping", "Astrology", "Astronomy", "Baking", "Baton twirling", "Blogging", "Building", "Board/tabletop games", "Book discussion clubs", "Book restoration", "Bowling", "Brazilian jiu-jitsu", "Breadmaking", "Bullet journaling", "Cabaret", "Calligraphy", "Candle making", "Candy making", "Car fixing & building", "Card games", "Cheesemaking", "Cleaning", "Clothesmaking", "Coffee roasting", "Collecting", "Coloring", "Computer programming", "Confectionery", "Cooking", "Cosplaying", "Couponing", "Craft", "Creative writing", "Crocheting", "Cross-stitch", "Crossword puzzles", "Cryptography", "Cue sports", "Dance", "Digital arts", "Distro Hopping", "DJing", "Do it yourself", "Drama", "Drawing", "Drink mixing", "Drinking", "Electronic games", "Electronics", "Embroidery", "Experimenting", "Fantasy sports", "Fashion", "Fashion design", "Fishkeeping", "Filmmaking", "Flower arranging", "Fly tying", "Foreign language learning", "Furniture building", "Gaming", "Genealogy", "Gingerbread house making", "Glassblowing", "Graphic design", "Gunsmithing", "Gymnastics", "Hacking", "Herp keeping", "Home improvement", "Homebrewing", "Houseplant care", "Hula hooping", "Humor", "Hydroponics", "Ice skating", "Jewelry making", "Jigsaw puzzles", "Journaling", "Juggling", "Karaoke", "Karate", "Kendama", "Knife making", "Knitting", "Knot tying", "Kombucha brewing", "Lace making", "Lapidary", "Leather crafting", "Lego building", "Lock picking", "Listening to music", "Listening to podcasts", "Machining", "Macrame", "Magic", "Makeup", "Mazes (indoor/outdoor)", "Metalworking", "Model building", "Model engineering", "Nail art", "Needlepoint", "Origami", "Painting", "Palmistry", "Pet adoption & fostering", "Philately", "Photography", "Practical jokes", "Pressed flower craft", "Playing musical instruments", "Poi", "Pottery", "Powerlifting", "Puzzles", "Quilling", "Quilting", "Quizzes", "Radio-controlled model", "Rail transport modeling", "Rapping", "Reading", "Refinishing", "Reiki", "Robot combat", "Rubik's Cube", "Scrapbooking", "Sculpting", "Sewing", "Shoemaking", "Singing", "Sketching", "Skipping rope", "Slot car", "Soapmaking", "Social media", "Spreadsheets", "Stand-up comedy", "Stamp collecting", "Table tennis", "Tarot", "Taxidermy", "Thrifting", "Video editing", "Video game developing", "Video gaming", "Watching movies", "Watching television", "Videography", "Virtual reality", "Waxing", "Weaving", "Weight training", "Welding", "Whittling", "Wikipedia editing", "Winemaking", "Wood carving", "Woodworking", "Worldbuilding", "Writing", "Word searches", "Yo-yoing", "Yoga", "Zumba", "Amusement park visiting", "Air sports", "Airsoft", "Amateur geology", "Archery", "Astronomy", "Backpacking", "Badminton", "BASE jumping", "Baseball", "Basketball", "Beekeeping", "Birdwatching", "Blacksmithing", "BMX", "Board sports", "Bodybuilding", "Bonsai", "Butterfly watching", "Bus riding", "Camping", "Canoeing", "Canyoning", "Car riding", "Caving", "Composting", "Cycling", "Dowsing", "Driving", "Farming", "Fishing", "Flag football", "Flower growing", "Flying", "Flying disc", "Foraging", "Fossicking", "Freestyle football", "Gardening", "Geocaching", "Ghost hunting", "Gold prospecting", "Graffiti", "Handball", "Herbalism", "Herping", "High-power rocketry", "Hiking", "Hobby horsing", "Hobby tunneling", "Hooping", "Horseback riding", "Hunting", "Inline skating", "Jogging", "Jumping rope", "Kayaking", "Kite flying", "Kitesurfing", "Lacrosse", "LARPing", "Letterboxing", "Longboarding", "Martial arts", "Metal detecting", "Meteorology", "Motor sports", "Mountain biking", "Mountaineering", "Museum visiting", "Mushroom hunting", "Netball", "Nordic skating", "Orienteering", "Paintball", "Parkour", "Photography", "Podcast hosting", "Polo", "Public transport riding", "Rafting", "Railway journeys", "Rappelling", "Road biking", "Rock climbing", "Roller skating", "Rugby", "Running", "Radio-controlled model", "Sailing", "Sand art", "Scouting", "Scuba diving", "Sculling", "Shooting", "Shopping", "Shuffleboard", "Skateboarding", "Skiing", "Skimboarding", "Skydiving", "Slacklining", "Snowboarding", "Snowmobiling", "Snowshoeing", "Soccer", "Stone skipping", "Sun bathing", "Surfing", "Survivalism", "Swimming", "Taekwondo", "Tai chi", "Tennis", "Topiary", "Tourism", "Thru-hiking", "Trade fair visiting", "Travel", "Urban exploration", "Vacation", "Vegetable farming", "Videography", "Vehicle restoration", "Walking", "Water sports", "Astronomy", "Biology", "Chemistry", "Electrochemistry", "Physics", "Psychology", "Sports science", "Geography", "History", "Mathematics", "Railway studies", "Action figure", "Antiquing", "Ant-keeping", "Art collecting", "Book collecting", "Button collecting", "Cartophily", "Coin collecting", "Comic book collecting", "Deltiology", "Die-cast toy", "Digital hoarding", "Dolls", "Element collecting", "Ephemera collecting", "Fusilately", "Knife collecting", "Lotology", "Movie and movie memorabilia collecting", "Fingerprint collecting", "Perfume", "Phillumeny", "Radio-controlled model", "Rail transport modelling", "Record collecting", "Rock tumbling", "Scutelliphily", "Shoes", "Slot car", "Sports memorabilia", "Stamp collecting", "Stuffed toy collecting", "Tea bag collecting", "Ticket collecting", "Toys", "Transit map collecting", "Video game collecting", "Vintage cars", "Vintage clothing", "Vinyl Records", "Antiquities", "Auto audiophilia", "Flower collecting and pressing", "Fossil hunting", "Insect collecting", "Magnet fishing", "Metal detecting", "Mineral collecting", "Rock balancing", "Sea glass collecting", "Seashell collecting", "Stone collecting", "Animal fancy", "Axe throwing", "Backgammon", "Badminton", "Baton twirling", "Beauty pageants", "Billiards", "Bowling", "Boxing", "Bridge", "Checkers (draughts)", "Cheerleading", "Chess", "Color guard", "Cribbage", "Curling", "Dancing", "Darts", "Debate", "Dominoes", "Eating", "Esports", "Fencing", "Go", "Gymnastics", "Ice hockey", "Ice skating", "Judo", "Jujitsu", "Kabaddi", "Knowledge/word games", "Laser tag", "Longboarding", "Mahjong", "Marbles", "Martial arts", "Model United Nations", "Poker", "Pool", "Role-playing games", "Shogi", "Slot car racing", "Speedcubing", "Sport stacking", "Table football", "Table tennis", "Volleyball", "Weightlifting", "Wrestling", "Airsoft", "Archery", "Association football", "Australian rules football", "Auto racing", "Baseball", "Beach volleyball", "Breakdancing", "Climbing", "Cricket", "Croquet", "Cycling", "Disc golf", "Dog sport", "Equestrianism", "Exhibition drill", "Field hockey", "Figure skating", "Fishing", "Footbag", "Frisbee", "Golfing", "Handball", "Horseback riding", "Horseshoes", "Iceboat racing", "Jukskei", "Kart racing", "Knife throwing", "Lacrosse", "Longboarding", "Long-distance running", "Marching band", "Model aircraft", "Orienteering", "Pickleball", "Quidditch", "Race walking", "Racquetball", "Radio-controlled car racing", "Roller derby", "Rugby league football", "Sculling", "Shooting sport", "Skateboarding", "Skiing", "Sled dog racing", "Softball", "Speed skating", "Squash", "Surfing", "Swimming", "Table tennis", "Tennis", "Tennis polo", "Tether car", "Tour skating", "Tourism", "Trapshooting", "Triathlon", "Ultimate frisbee", "Volleyball", "Water polo", "Fishkeeping", "Learning", "Meditation", "Microscopy", "Reading", "Research", "Shortwave listening", "Audiophile", "Aircraft spotting", "Amateur astronomy", "Birdwatching", "Bus spotting", "Geocaching", "Gongoozling", "Herping", "Hiking", "Meteorology", "Photography", "Satellite watching", "Trainspotting", "Whale watching"}, + "phone": {"###-###-####", "(###)###-####", "1-###-###-####", "###.###.####"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/product.go b/vendor/github.com/brianvoe/gofakeit/v7/data/product.go new file mode 100644 index 0000000000..cbe5b3a5ca --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/product.go @@ -0,0 +1,171 @@ +package data + +var Product = map[string][]string{ + "category": { + "electronics", "clothing", "home appliances", "furniture", + "automotive parts", "beauty and personal care", "books", "sports equipment", + "toys and games", "outdoor gear", "pet supplies", "kitchenware", + "health and wellness", "tools and hardware", "office supplies", + "baby products", "jewelry", "home decor", "musical instruments", + "fitness equipment", "mobile phones", "computer accessories", "cameras and photography", + "gardening supplies", "bedding and linens", "food and groceries", "party supplies", + "craft and diy supplies", "camping gear", "watches", "luggage and travel accessories", + "board games", "art supplies", "stationery", "bath and shower products", + "sunglasses", "educational toys", "headphones and earbuds", "sneakers and athletic shoes", + "coffee and tea products", "bicycles and accessories", "cookware", "cosmetics", + "home improvement", "pet food", "laptop bags and cases", "home security systems", + "musical accessories", "skincare products", "smart home devices", + }, + + "adjective": { + "bold", "swift", "pure", "smart", "fresh", + "cool", "sharp", "zen", "bright", "quick", + "robust", "sleek", "versatile", "innovative", "compact", + "luxe", "modular", "precision", "stream", + }, + + "name": { + "phone", "laptop", "tablet", "watch", "camera", + "headphones", "speaker", "drone", "car", "bike", + "appliance", "gadget", "tool", "toy", "game", + "computer", "console", "smartwatch", "fitness tracker", "smart home device", + "robot", "router", "television", "smart speaker", "vr headset", + "earbuds", "printer", "mouse", "keyboard", "monitor", + "microwave", "blender", "vacuum", "fan", "toaster", + "clock", "lamp", "shaver", "scale", "thermometer", + "fridge", "oven", "mixer", "iron", "hair dryer", + "fan", "scale", "thermostat", "router", "lightbulb", + }, + + "feature": { + "wireless", "smart", "eco-friendly", "advanced", "compact", + "high-performance", "energy-efficient", "portable", "durable", "stylish", + "touchscreen", "water-resistant", "noise-canceling", "voice-controlled", "ultra-lightweight", + "multi-functional", "user-friendly", "fast-charging", "biometric", "gps-enabled", + }, + + "material": { + "titanium", "carbon", "alloy", "bamboo", "leather", + "glass", "ceramic", "aluminum", "stainless", "wood", + "plastic", "rubber", "silicon", "fabric", "paper", + "gold", "silver", "brass", "copper", "bronze", + "chrome", "marble", "granite", "porcelain", "plexiglass", + "quartz", "felt", "suede", + }, + + "suffix": { + "tech", "pro", "x", "plus", "elite", + "spark", "nexus", "nova", "fusion", "sync", + "edge", "boost", "max", "link", "prime", + "zoom", "pulse", "dash", "connect", "blaze", + "quantum", "spark", "vertex", "core", "flux", + "turbo", "shift", "wave", "matrix", + }, + + "benefit": { + "comfort", "efficiency", "safety", "reliability", + "versatility", "ease of use", "long battery life", + "precision", "enhanced connectivity", "portability", + "durability", "energy savings", "aesthetic appeal", + "health benefits", "convenience", "time-saving", + "high performance", "noise reduction", "user satisfaction", + "customizability", "sustainability", "cost-effectiveness", + "innovative features", "improved productivity", "enhanced experience", + "robust construction", "weather resistance", "minimal maintenance", + "increased functionality", "advanced technology", "ergonomic design", + }, + + "use_case": { + "home", "office", "outdoors", "fitness", "travel", "gaming", + "cooking", "music", "learning", "entertainment", "professional work", + "healthcare", "educational purposes", "commuting", "camping", "hiking", + "sports", "art and craft", "gardening", "cleaning", "personal grooming", + "relaxation", "home security", "pet care", "smart automation", "food preparation", + "baking", "social gatherings", "productivity", "collaboration", "DIY projects", + "childcare", "remote work", "photography", "videography", "wellness routines", + }, + + "target_audience": { + "children", "adults", "seniors", "students", "professionals", "athletes", + "travelers", "families", "pet owners", "homeowners", "gamers", "cooks", "DIY enthusiasts", + "musicians", "artists", + }, + + "dimension": { + "small", "medium", "large", "extra-large", "compact", "lightweight", + "heavy", "mini", "standard", "oversized", + }, + + "description": { + "This {adjectivedescriptive} {productname} is perfect for {productusecase}, offering {productfeature} and {productbenefit}. Made from {productmaterial}, it's designed for {productaudience} who value {productbenefit}.", + "Introducing the {adjectivedescriptive} {productname} {productsuffix}, featuring {productfeature} technology and made from {productmaterial}. It ensures {productbenefit} for {productaudience}, making it ideal for {productusecase}.", + "Perfect for {productusecase}, the {productname} is crafted with {adjectivedescriptive} {productmaterial} and features {productfeature} for {productaudience}. Enjoy {productbenefit} every day.", + "Designed with {productaudience} in mind, this {adjectivedescriptive} {productname} offers {productbenefit}. It's equipped with {productfeature} and made from {productmaterial} for maximum {productbenefit}.", + "The {productname} {productsuffix} combines {adjectivedescriptive} design and {productmaterial} build to deliver {productfeature}. Its {productdimension} size makes it perfect for {productusecase} and ideal for {productaudience}.", + "With a focus on {productaudience}, the {productname} is built with {adjectivedescriptive} {productmaterial} for {productbenefit} and features {productfeature} to meet the needs of {productusecase}.", + "Experience the {productbenefit} of the {productname} {productsuffix}, made from {productmaterial} with a {adjectivedescriptive} design. It's ideal for {productusecase} and loved by {productaudience}.", + "Whether you're using it at {productusecase} or on the go, this {adjectivedescriptive} {productname} offers {productfeature} and ensures {productbenefit}. Crafted from {productmaterial}, it's perfect for {productaudience}.", + "The {productname} is a {adjectivedescriptive} solution for {productusecase}, featuring {productfeature} technology and built with {productmaterial} for {productbenefit}. Suitable for {productaudience}.", + "For {productaudience} who need {productbenefit}, the {productname} {productsuffix} delivers with {productfeature}, {adjectivedescriptive} design, and durable {productmaterial} construction. Ideal for {productusecase}.", + "Built with {adjectivedescriptive} {productmaterial}, this item is ideal for {productusecase} and provides {productaudience} with {productbenefit} through its {productfeature}.", + "Experience {productbenefit} with this {adjectivedescriptive} product, featuring {productfeature} and made from {productmaterial}, perfect for {productusecase}.", + "Designed for {productaudience}, this {adjectivedescriptive} product ensures {productbenefit} and is equipped with {productfeature} for the best {productusecase} experience.", + "For those who need {productbenefit}, this {adjectivedescriptive} product, made of {productmaterial}, offers {productfeature} and is perfect for {productusecase}.", + "Take your {productusecase} to the next level with this {adjectivedescriptive} product. Built from {productmaterial}, it features {productfeature} for {productaudience}.", + "Crafted from {productmaterial}, this product is ideal for {productaudience} seeking {productbenefit}. Its {adjectivedescriptive} design and {productfeature} make it perfect for {productusecase}.", + "This product, made with {productmaterial}, is designed for {productaudience} who value {productbenefit}. Its {adjectivedescriptive} design includes {productfeature}, making it ideal for {productusecase}.", + "Enjoy {productbenefit} with this {adjectivedescriptive} item, featuring {productfeature} technology. Made from {productmaterial}, it's perfect for {productusecase}.", + "With {productfeature} and {adjectivedescriptive} {productmaterial}, this product offers {productbenefit} for {productaudience}, ideal for {productusecase}.", + "The perfect solution for {productusecase}, this {adjectivedescriptive} product provides {productbenefit} with its {productfeature}, crafted from {productmaterial} for {productaudience}.", + "Built for {productaudience}, this product features {productfeature} and ensures {productbenefit}. Made from {productmaterial}, it's an {adjectivedescriptive} choice for {productusecase}.", + "Achieve {productbenefit} with this {adjectivedescriptive} product. Crafted from {productmaterial}, it features {productfeature}, perfect for {productaudience} during {productusecase}.", + "For {productaudience}, this {adjectivedescriptive} item offers {productfeature} and is made of {productmaterial}, providing {productbenefit} for {productusecase}.", + "This {adjectivedescriptive} product is crafted from {productmaterial} and includes {productfeature}, making it perfect for {productusecase} and delivering {productbenefit} for {productaudience}.", + "Featuring {productfeature} and made from {productmaterial}, this {adjectivedescriptive} product is ideal for {productaudience} looking for {productbenefit} in {productusecase}.", + "For {productusecase}, this {adjectivedescriptive} product provides {productbenefit} with its {productfeature}, crafted for {productaudience} from high-quality {productmaterial}.", + "This {adjectivedescriptive} product is perfect for {productaudience} who need {productbenefit}. Built from {productmaterial} and featuring {productfeature}, it's ideal for {productusecase}.", + "Delivering {productbenefit}, this product is made from {productmaterial} and designed for {productaudience}. Its {adjectivedescriptive} design includes {productfeature}, perfect for {productusecase}.", + "For those interested in {productusecase}, this {adjectivedescriptive} product offers {productfeature} and is made of {productmaterial} to provide {productbenefit} for {productaudience}.", + "This product is crafted for {productaudience}, featuring {adjectivedescriptive} {productmaterial} and equipped with {productfeature} to ensure {productbenefit} during {productusecase}.", + "Transform your {productusecase} with this {adjectivedescriptive} product, featuring {productfeature} and made from high-quality {productmaterial} to provide {productbenefit}.", + "This {adjectivedescriptive} item, built for {productaudience}, uses {productfeature} technology to deliver {productbenefit} during {productusecase}.", + "Enjoy the luxury of {productbenefit} with this product, crafted from {productmaterial}. Its {adjectivedescriptive} design and {productfeature} make it ideal for {productusecase}.", + "Made from {productmaterial} and designed with {productaudience} in mind, this product offers {productbenefit} and features {productfeature} for excellent {productusecase}.", + "Achieve seamless {productusecase} with this {adjectivedescriptive} product. Built using {productmaterial}, it delivers {productbenefit} with the help of {productfeature}.", + "This product, made for {productaudience}, offers {productbenefit} with its {adjectivedescriptive} {productmaterial} build and advanced {productfeature}, perfect for {productusecase}.", + "Built with {productmaterial}, this {adjectivedescriptive} product is designed to provide {productbenefit} for {productaudience} through its {productfeature}, ideal for {productusecase}.", + "Elevate your {productusecase} experience with this {adjectivedescriptive} product, made from {productmaterial} and offering {productfeature} to ensure {productbenefit}.", + "Perfect for {productaudience} who value {productbenefit}, this product features {productfeature} and is crafted from {adjectivedescriptive} {productmaterial}, ideal for {productusecase}.", + "With a focus on {productusecase}, this {adjectivedescriptive} product, made from {productmaterial}, ensures {productbenefit} with its {productfeature} for {productaudience}.", + "Whether for {productusecase} or everyday use, this product delivers {productbenefit} with its {adjectivedescriptive} {productmaterial} construction and {productfeature}, crafted for {productaudience}.", + "This {adjectivedescriptive} product is perfect for {productusecase}, made with {productmaterial} and offering {productfeature} to ensure {productbenefit} for {productaudience}.", + "Featuring state-of-the-art {productfeature}, this product is designed from {productmaterial} to deliver {productbenefit} for {productaudience}, ideal for {productusecase}.", + "For {productusecase}, this {adjectivedescriptive} product is crafted from {productmaterial} to provide {productfeature}, ensuring {productbenefit} for {productaudience}.", + "Built for {productaudience}, this item features {adjectivedescriptive} {productmaterial} and advanced {productfeature} to deliver {productbenefit} during {productusecase}.", + "With {productfeature} and a {adjectivedescriptive} design, this product is made from {productmaterial} to provide {productbenefit} for {productaudience}, ideal for {productusecase}.", + "This {adjectivedescriptive} item, crafted from {productmaterial}, offers {productfeature} for {productusecase}, ensuring {productbenefit} for {productaudience}.", + "For those who value {productbenefit}, this product, made from {productmaterial}, includes {productfeature} and is perfect for {productusecase}, designed for {productaudience}.", + "Achieve superior {productusecase} with this product, featuring {productfeature} and made from {adjectivedescriptive} {productmaterial}, offering {productbenefit} to {productaudience}.", + "Delivering {productbenefit}, this product is crafted from {productmaterial} and equipped with {productfeature}, making it ideal for {productaudience} during {productusecase}.", + "Revolutionize your {productusecase} with this {adjectivedescriptive} item, featuring {productfeature} and crafted from {productmaterial} for {productaudience} seeking {productbenefit}.", + "This {adjectivedescriptive} item, designed for {productaudience}, is built from {productmaterial} and includes {productfeature} to ensure {productbenefit} for {productusecase}.", + "Enjoy enhanced {productusecase} with this product, featuring {productfeature} and made with {adjectivedescriptive} {productmaterial}, delivering {productbenefit}.", + "Perfect for {productaudience}, this {adjectivedescriptive} product includes {productfeature} and is crafted from {productmaterial} to provide {productbenefit} during {productusecase}.", + "Take your {productusecase} to new heights with this product, made from {productmaterial} and featuring {productfeature} for {productaudience} who value {productbenefit}.", + "Crafted from premium {productmaterial}, this item is designed for {productaudience} to provide {productbenefit} with its {adjectivedescriptive} build and {productfeature}.", + "This {adjectivedescriptive} product, made from {productmaterial}, offers {productbenefit} through its {productfeature}, ideal for {productaudience} engaging in {productusecase}.", + "Elevate your {productusecase} with this {adjectivedescriptive} product. It features {productfeature} and is crafted from {productmaterial} for {productaudience}.", + "Designed for {productaudience}, this product includes {productfeature} and a {adjectivedescriptive} {productmaterial} construction, ensuring {productbenefit} during {productusecase}.", + "This {adjectivedescriptive} item, featuring {productfeature}, is crafted from {productmaterial} to provide {productbenefit} for {productusecase}, perfect for {productaudience}.", + "Achieve exceptional {productusecase} with this product, featuring advanced {productfeature} and made from durable {productmaterial}, delivering {productbenefit} for {productaudience}.", + "Whether it's for {productusecase} or daily use, this {adjectivedescriptive} item is crafted from {productmaterial} and offers {productfeature} to deliver {productbenefit} for {productaudience}.", + "This product, ideal for {productaudience}, features {adjectivedescriptive} {productmaterial} and incorporates {productfeature} to ensure {productbenefit} during {productusecase}.", + "Built with {productmaterial}, this {adjectivedescriptive} item is perfect for {productusecase} and features {productfeature} to provide {productbenefit} to {productaudience}.", + "With {productfeature} and made from {adjectivedescriptive} {productmaterial}, this product ensures {productbenefit} for {productaudience}, ideal for {productusecase}.", + "This {adjectivedescriptive} item is built for {productaudience}, providing {productbenefit} with its {productmaterial} construction and advanced {productfeature}, perfect for {productusecase}.", + "For {productusecase}, this product delivers {productbenefit} to {productaudience} with its {adjectivedescriptive} design and {productfeature}, made from quality {productmaterial}.", + "Experience the benefits of {productfeature} with this {adjectivedescriptive} item, crafted from {productmaterial} and ideal for {productaudience} seeking {productbenefit} during {productusecase}.", + "This {adjectivedescriptive} product is crafted from {productmaterial} and includes {productfeature}, making it perfect for {productusecase} and providing {productbenefit} for {productaudience}.", + "For those who value {productbenefit}, this product is made from {productmaterial} and features {adjectivedescriptive} {productfeature}, ideal for {productaudience} during {productusecase}.", + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/school.go b/vendor/github.com/brianvoe/gofakeit/v7/data/school.go new file mode 100644 index 0000000000..a9772d634f --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/school.go @@ -0,0 +1,56 @@ +package data + +// School type and names +var School = map[string][]string{ + "type": {"Elementary School", "Middle School", "University", "High School", "Kindergarten", "Academy", "College", "Institute"}, + "isPrivate": {"Private", "State"}, + "name": {"Maplewood", + "Pineville", + "Riverside", + "Willowbrook", + "Crestwood", + "Sunset", + "Greenfield", + "Oakwood", + "Willowbrook", + "Hawthorn", + "Brookside", + "Pleasant View", + "Crescent Valley", + "Sycamore", + "Springfield", + "Meadowbrook", + "Greenwood", + "Riverbend", + "Valley Forge", + "Ridgeview", + "Cottonwood", + "Cedarwood", + "Golden Oak", + "Stonebridge", + "Harborview", + "Windsor", + "Northbrook", + "Sunset", + "Redwood Valley", + "Liberty", + "Washington Central", + "Franklin", + "Jefferson", + "Lincoln Park", + "Madison", + "Roosevelt", + "Westwood", + "Central Lakeside", + "Fairview", + "Heritage Hills", + "Kingsbridge", + "Harrisonville", + "Valley View", + "Hillside", + "Northridge", + "Brooklyn Heights", + "Oakridge", + "Countryside", + }, +} \ No newline at end of file diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/sentence.go b/vendor/github.com/brianvoe/gofakeit/v7/data/sentence.go new file mode 100644 index 0000000000..e12319d824 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/sentence.go @@ -0,0 +1,5 @@ +package data + +var Sentence = map[string][]string{ + "phrase": {"what's yer poison", "time will tell", "I'm good", "nice to meet you", "spring forward, fall back", "what's your job", "once or twice", "you could have fooled me", "what's your name", "why not Zoidberg", "time you got a watch", "I'm Hindu", "fair play", "what's your phone number", "after the jump", "cease fire", "as ever", "I'm hot", "best of", "get well soon", "what's your poison", "when is closing time", "yes and amen", "you don't dip your pen in the company inkwell", "I'm hungry", "short of", "what's yours", "duces tecum", "after you", "yes and no", "I'm in love with you", "the pants off", "I'm Jewish", "few sandwiches short of a picnic", "shut the front door", "does a bear shit in the woods", "the party is over", "tomayto tomahto", "I'm looking for a grocery store", "does anyone here speak English", "heads I win, tails you lose", "I'm looking for a job", "stick a fork in it", "the penny drops", "I'm lost", "shut up and take my money", "mind you", "I'm married", "isn't it so", "wham-bam-thank-you-ma'am", "does not compute", "hold your fire", "pardon me", "mind your own beeswax", "I'm mute", "does someone look like", "I'm not being funny", "leave me alone", "going once, going twice, sold", "you get that", "I'm not interested", "talk about", "here be dragons", "always a bridesmaid, never a bride", "the plot thickens", "close, but no cigar", "I'm not religious", "ultra vires", "bound to", "always the bridesmaid, never the bride", "the plural of anecdote is not data", "I'm pregnant", "comedy equals tragedy plus time", "get you", "heads will roll", "all to the better", "I'm rubber, you're glue", "going to", "when push comes to shove", "you had to be there", "I'm scared", "you have beautiful eyes", "enjoy your meal", "I'm sick", "doesn't have both oars in the water", "you have the advantage of me", "here lies", "check is in the mail", "I'm single", "stick 'em up", "when the chips are down", "you just had to", "that'll be the day", "I'm sorry", "very good", "lather, rinse, repeat", "you kiss your mother with that mouth", "that'll do", "the rabbit died", "I'm straight", "in order for", "when the going gets weird, the weird turn pro", "I'm thirsty", "the rest is history", "it depends", "I'm tired", "in order to", "monkeys might fly out of my butt", "oh my life", "do want", "would it hurt", "you know what", "here you are", "all wool and a yard wide", "hit it", "pound for pound", "bottom falls out", "OK yah", "would it kill someone", "you know what I mean", "here you go", "alone in a crowd", "me neither", "chin up", "to be continued", "I'm twenty years old", "such is life", "off with someone's head", "Lord knows", "case closed", "you know what they say", "you've got to laugh", "ten points to Gryffindor", "that's a relief", "I'm worried", "kill the rabbit", "live and learn", "would not throw someone out of bed", "catch you later", "that's a wrap", "the rubber meets the road", "to be honest", "I'm your huckleberry", "off with their head", "you learn something new every day", "catch you on the flip side", "all your base are belong to us", "that's all", "horses for courses", "to be named later", "good night", "would you mind putting on your seat belt", "easy does it", "that's all she wrote", "me too", "oh noes", "that's for me to know and you to find out", "to be truthful", "still got one's communion money", "do you accept American dollars", "winner, winner, chicken dinner", "workers of the world, unite", "speak of the devil", "you must be fun at parties", "that's it", "hit me", "how about that", "ding, ding, ding, we have a winner", "do you accept credit cards", "word has it", "woulda, coulda, shoulda", "you must be new here", "how are you", "do you believe in God", "woulda, shoulda, coulda", "that's life", "safety in numbers", "how are you doing", "do you come here often", "worm has turned", "you never know", "that's my", "how are you getting along", "leave well enough alone", "do you have a boyfriend", "that's saying something", "the shoe is on the other foot", "this is someone", "do you have a girlfriend", "Lord only knows", "that's that", "check yourself before you wreck yourself", "this is the life", "how can you sleep at night", "wake up and die right", "do you have a menu in English", "that's the bunny", "the show must go on", "this is where we came in", "nod's as good as a wink to a blind bat", "wake up and smell the ashes", "on the huh", "do you have any brothers or sisters", "dogs bark", "worm turns", "that's the spirit", "this just in", "how did he die", "more like", "do you have any pets", "alright me babber", "Elvis has left the building", "this means war", "how do", "she could be his mother", "do you have children", "alright me lover", "that's the ticket", "how do I get to", "shoulda, coulda, woulda", "nome sane", "guess what", "whenever one turns around", "do you have Wi-Fi", "alright my babber", "the story goes", "how do I get to the airport", "shoulda, woulda, coulda", "do you kiss your mother with that mouth", "Lord willing and the creek don't rise", "you said it", "alright my lover", "how do I get to the bus station", "ask me one on sport", "need I say more", "sounds like a plan", "put that in your pipe and smoke it", "do you know", "take a picture, it will last longer", "the streets are paved with gold", "how do I get to the train station", "ask my arse", "stop the car", "do you know who I am", "wouldn't you know", "you shouldn't have", "how do ye do", "fans are slans", "use one's coconut", "bit by a barn mouse", "stick that in your pipe and smoke it", "do you mind", "but for the grace of God", "wouldn't you know it", "head in the sand", "the terrorists will have won", "how do you do", "please excuse my dear Aunt Sally", "much of a muchness", "bless someone's cotton socks", "do you need help", "or else", "dress for the slide, not the ride", "that's wassup", "the thick plottens", "much to be said", "bless someone's heart", "a blessing and a curse", "do you speak English", "you think", "that's what I'm talking about", "how do you like that", "art imitates life", "please help me", "five will get you ten", "do you think you can walk", "or so", "that's what she said", "the thing is", "how do you like them apples", "please pass the salt", "I've been robbed", "nature calls", "a boon and a bane", "but me no buts", "or something", "you welcome", "that's what's up", "how do you pronounce this word", "fare thee well", "please repeat after me", "I've been shot", "pot, meet kettle", "a boon or a bane", "where are the snows of yesteryear", "or what", "rolling in it", "the toilet is clogged", "how do you say...in English", "circle gets the square", "more than someone has had hot dinners", "please say that again", "I've burned myself", "different strokes", "where are the toilets", "or words to that effect", "you win", "how do you spell this word", "to hell with", "in virtue of which", "please sit down", "where are we", "out to", "am I right", "please speak more slowly", "I've lost my keys", "where are we going", "but who's counting", "you wish", "am I right or am I right", "how goes it", "methinks the lady doth protest too much", "please turn left", "could be written on the back of a postage stamp", "I've never heard it called that before", "where are you", "you wish, jellyfish", "am I under arrest", "methinks thou dost protest too much", "please turn right", "bang to rights", "gimme a break", "where are you from", "revenge is sweet", "'tis the season", "pull the other one", "where are your parents", "out with it", "have a good one", "how long is a piece of string", "ay up me duck", "before you can say Jack Robinson", "pull the other one, it's got bells on", "where away", "only time will tell", "could fit on the back of a postage stamp", "before you can say knife", "pull the other one, it's got brass bells on", "where can I find a hotel", "the wheels came off", "angel passes", "how many languages do you speak", "could go all day", "sleep tight", "nature vs nurture", "practice, practice, practice", "where do I sign up", "help is on the way", "many thanks", "the wheels came off the bus", "mercy bucket", "how many siblings do you have", "pleased to meet you", "could have fooled me", "where do you live", "the wheels came off the wagon", "mercy buckets", "where do you live at", "you'd better believe it", "than a bygod", "the wheels fell off", "could have, would have, should have", "where does it hurt", "hell if I know", "you'd complain if you were hung with a new rope", "the wheels fell off the bus", "every good boy deserves fudge", "could I see the menu, please", "where does this bus go", "help wanted", "the wheels fell off the wagon", "how much do I owe you", "where does this train go", "how much do you charge", "steady as she goes", "put the same shoe on every foot", "where have you been", "temper temper", "how much does it cost", "coulda, shoulda, woulda", "give credit where credit is due", "boom goes the dynamite", "where is the toilet", "how much is it", "in your dreams", "coulda, woulda, shoulda", "what a lovely day", "to save one's life", "exsqueeze me", "like a martin to his gourd", "what a pity", "you'll be late for your own funeral", "every man for himself", "size matters"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/song.go b/vendor/github.com/brianvoe/gofakeit/v7/data/song.go new file mode 100644 index 0000000000..0e275c8ee3 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/song.go @@ -0,0 +1,246 @@ +package data + +// Songs: Year-end Charts Hot 100 Songs from Billboard +// Source: https://www.billboard.com/charts/year-end/hot-100-songs/ + +// Artists: Greatest of All Time Artists based on Billboard rate +// Source: https://www.billboard.com/charts/greatest-of-all-time-artists/ + +var Songs = map[string][]string{ + "name": { + "A Bar Song (Tipsy)", + "A Holly Jolly Christmas", + "Act II: Date @ 8", + "Agora Hills", + "Ain't No Love In Oklahoma", + "All I Want For Christmas Is You", + "Austin", + "Beautiful Things", + "Birds Of A Feather", + "Bulletproof", + "Burn It Down", + "Carnival", + "Cowgirls", + "Cruel Summer", + "Dance The Night", + "Die With A Smile", + "Down Bad", + "End Of Beginning", + "Espresso", + "Euphoria", + "Everybody", + "Exes", + "FE!N", + "FTCU", + "Fast Car", + "Feather", + "First Person Shooter", + "Flowers", + "Fortnight", + "Fukumean", + "Gata Only", + "Get It Sexyy", + "Good Good", + "Good Luck, Babe!", + "Greedy", + "High Road", + "Hot To Go!", + "Houdini", + "Houdini", + "I Am Not Okay", + "I Can Do It With A Broken Heart", + "I Had Some Help", + "I Like The Way You Kiss Me", + "I Remember Everything", + "IDGAF", + "Is It Over Now?", + "Jingle Bell Rock", + "La Diabla", + "Last Christmas", + "Last Night", + "Lies Lies Lies", + "Like That", + "Lil Boo Thang", + "Lose Control", + "Lovin On Me", + "Lunch", + "Made For Me", + "Miles On It", + "Million Dollar Baby", + "Monaco", + "Need A Favor", + "Never Lose Me", + "Not Like Us", + "On My Mama", + "Paint The Town Red", + "Pink Skies", + "Please Please Please", + "Pour Me A Drink", + "Pretty Little Poison", + "Redrum", + "Rich Baby Daddy", + "Rockin' Around The Christmas Tree", + "Saturn", + "Save Me", + "Slow It Down", + "Snooze", + "Stargazing", + "Stick Season", + "Taste", + "Texas Hold 'Em", + "The Painter", + "Thinkin' Bout Me", + "Too Sweet", + "Truck Bed", + "Type Shit", + "Vampire", + "Wanna Be", + "Water", + "We Can't Be Friends (Wait For Your Love)", + "What Was I Made For?", + "Whatever She Wants", + "Where It Ends", + "Where The Wild Things Are", + "White Horse", + "Wild Ones", + "Wildflower", + "Wind Up Missin' You", + "World On Fire", + "Yeah Glo!", + "Yes, And?", + }, + "artist": { + "Adele", + "Aerosmith", + "Alicia Keys", + "Aretha Franklin", + "Barbra Streisand", + "Barry Manilow", + "Bee Gees", + "Beyonce", + "Billy Joel", + "Bob Dylan", + "Bob Seger", + "Bon Jovi", + "Boyz II Men", + "Britney Spears", + "Bruce Springsteen & The E Street Band", + "Bruno Mars", + "Bryan Adams", + "Carole King", + "Carpenters", + "Celine Dion", + "Chicago", + "Chris Brown", + "Commodores", + "Creedence Clearwater Revival", + "Daryl Hall John Oates", + "Def Leppard", + "Diana Ross", + "Donna Summer", + "Drake", + "Eagles", + "Earth, Wind & Fire", + "Ed Sheeran", + "Elton John", + "Elvis Presley", + "Eminem", + "Eric Clapton", + "Fleetwood Mac", + "Foreigner", + "Garth Brooks", + "Guns N' Roses", + "Heart", + "Herb Alpert", + "Huey Lewis & The News", + "JAY-Z", + "James Taylor", + "Janet Jackson", + "John Denver", + "John Mellencamp", + "Journey", + "Justin Bieber", + "Justin Timberlake", + "Kanye West", + "Katy Perry", + "Kelly Clarkson", + "Kenny Rogers", + "Lady Gaga", + "Led Zeppelin", + "Linda Ronstadt", + "Linkin Park", + "Lionel Richie", + "Madonna", + "Mariah Carey", + "Maroon 5", + "Marvin Gaye", + "Mary J. Blige", + "Michael Bolton", + "Michael Jackson", + "Miley Cyrus", + "Neil Diamond", + "Nelly", + "Nickelback", + "Olivia Newton-John", + "P!nk", + "Paul McCartney", + "Paula Abdul", + "Phil Collins", + "Pink Floyd", + "Prince", + "Queen", + "R. Kelly", + "Rihanna", + "Rod Stewart", + "Santana", + "Simon & Garfunkel", + "Stevie Wonder", + "Taylor Swift", + "The Beach Boys", + "The Beatles", + "The Black Eyed Peas", + "The Jacksons", + "The Monkees", + "The Rolling Stones", + "The Supremes", + "The Temptations", + "Three Dog Night", + "Tim McGraw", + "U2", + "Usher", + "Van Halen", + "Whitney Houston", + }, + "genre": { + "Acoustic Pop", + "Alternative Hip-Hop", + "Alternative Pop", + "Chillwave", + "Contemporary R&B", + "Country", + "Dancehall", + "Electro-pop", + "Electronic Dance Music (EDM)", + "Emo Rap", + "Funk", + "Gospel-inspired Pop", + "Hip-Hop", + "Indie Pop", + "Latin Pop", + "Lo-fi Hip-Hop", + "Melodic Rap", + "Pop", + "Pop Punk", + "Pop Rock", + "R&B", + "Rap", + "Reggaeton", + "Rock", + "Singer-Songwriter", + "Soul", + "Synthwave", + "Trap", + "Trap Soul", + "Urban Contemporary", + }, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/data/word.go b/vendor/github.com/brianvoe/gofakeit/v7/data/word.go new file mode 100644 index 0000000000..87b48dc887 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/data/word.go @@ -0,0 +1,83 @@ +package data + +import ( + "sort" +) + +var WordKeys []string + +func init() { + // Loop through Word and put togther a list of keys + for key := range Word { + WordKeys = append(WordKeys, key) + } + + // Sort the keys + sort.Strings(WordKeys) +} + +// Word consists of common english words +var Word = map[string][]string{ + // Nouns + "noun_common": {"time", "person", "year", "way", "day", "thing", "man", "world", "life", "hand", "part", "child", "eye", "woman", "place", "work", "week", "case", "point", "government", "company", "number", "group", "problem", "fact"}, + "noun_concrete": {"apple", "air", "conditioner", "airport", "ambulance", "aircraft", "apartment", "arrow", "antlers", "apro", "alligator", "architect", "ankle", "armchair", "aunt", "ball", "bermudas", "beans", "balloon", "bear", "blouse", "bed", "bow", "bread", "black", "board", "bones", "bill", "bitterness", "boxers", "belt", "brain", "buffalo", "bird", "baby", "book", "back", "butter", "bulb", "buckles", "bat", "bank", "bag", "bra", "boots", "blazer", "bikini", "bookcase", "bookstore", "bus stop", "brass", "brother", "boy", "blender", "bucket", "bakery", "bow", "bridge", "boat", "car", "cow", "cap", "cooker", "cheeks", "cheese", "credenza", "carpet", "crow", "crest", "chest", "chair", "candy", "cabinet", "cat", "coffee", "children", "cookware", "chaise longue", "chicken", "casino", "cabin", "castle", "church", "cafe", "cinema", "choker", "cravat", "cane", "costume", "cardigan", "chocolate", "crib", "couch", "cello", "cashier", "composer", "cave", "country", "computer", "canoe", "clock", "dog", "deer", "donkey", "desk", "desktop", "dress", "dolphin", "doctor", "dentist", "drum", "dresser", "designer", "detective", "daughter", "egg", "elephant", "earrings", "ears", "eyes", "estate", "finger", "fox", "frock", "frog", "fan", "freezer", "fish", "film", "foot", "flag", "factory", "father", "farm", "forest", "flower", "fruit", "fork", "grapes", "goat", "gown", "garlic", "ginger", "giraffe", "gauva", "grains", "gas station", "garage", "gloves", "glasses", "gift", "galaxy", "guitar", "grandmother", "grandfather", "governor", "girl", "guest", "hamburger", "hand", "head", "hair", "heart", "house", "horse", "hen", "horn", "hat", "hammer", "hostel", "hospital", "hotel", "heels", "herbs", "host", "jacket", "jersey", "jewelry", "jaw", "jumper", "judge", "juicer", "keyboard", "kid", "kangaroo", "koala", "knife", "lemon", "lion", "leggings", "leg", "laptop", "library", "lamb", "london", "lips", "lung", "lighter", "luggage", "lamp", "lawyer", "mouse", "monkey", "mouth", "mango", "mobile", "milk", "music", "mirror", "musician", "mother", "man", "model", "mall", "museum", "market", "moonlight", "medicine", "microscope", "newspaper", "nose", "notebook", "neck", "noodles", "nurse", "necklace", "noise", "ocean", "ostrich", "oil", "orange", "onion", "oven", "owl", "paper", "panda", "pants", "palm", "pasta", "pumpkin", "pharmacist", "potato", "parfume", "panther", "pad", "pencil", "pipe", "police", "pen", "pharmacy", "police station", "parrot", "plane", "pigeon", "phone", "peacock", "pencil", "pig", "pouch", "pagoda", "pyramid", "purse", "pancake", "popcorn", "piano", "physician", "photographer", "professor", "painter", "park", "plant", "parfume", "radio", "razor", "ribs", "rainbow", "ring", "rabbit", "rice", "refrigerator", "remote", "restaurant", "road", "surgeon", "scale", "shampoo", "sink", "salt", "shark", "sandals", "shoulder", "spoon", "soap", "sand", "sheep", "sari", "stomach", "stairs", "soup", "shoes", "scissors", "sparrow", "shirt", "suitcase", "stove", "stairs", "snowman", "shower", "swan", "suit", "sweater", "smoke", "skirt", "sofa", "socks", "stadium", "skyscraper", "school", "sunglasses", "sandals", "slippers", "shorts", "sandwich", "strawberry", "spaghetti", "shrimp", "saxophone", "sister", "son", "singer", "senator", "street", "supermarket", "swimming pool", "star", "sky", "sun", "spoon", "ship", "smile", "table", "turkey", "tie", "toes", "truck", "train", "taxi", "tiger", "trousers", "tongue", "television", "teacher", "turtle", "tablet", "train station", "toothpaste", "tail", "theater", "trench coat", "tea", "tomato", "teen", "tunnel", "temple", "town", "toothbrush", "tree", "toy", "tissue", "telephone", "underwear", "uncle", "umbrella", "vest", "voice", "veterinarian", "villa", "violin", "village", "vehicle", "vase", "wallet", "wolf", "waist", "wrist", "water melon", "whale", "water", "wings", "whisker", "watch", "woman", "washing machine", "wheelchair", "waiter", "wound", "xylophone", "zebra", "zoo"}, + "noun_abstract": {"fiction", "horror", "dream", "luck", "movement", "right", "clarity", "joy", "care", "trend", "belief", "sorrow", "joy", "failure", "slavery", "riches", "fashion", "envy", "success", "fear", "union", "luxury", "freedom", "generosity", "wit", "peace", "hatred", "thrill", "brilliance", "care", "wealth", "religion", "divorce", "goal", "stupidity", "friendship", "goodness", "rhythm", "timing", "infancy", "disregard", "riches", "appetite", "loneliness", "pleasure", "love", "beauty", "annoyance", "kindness", "nap", "gain", "talent", "religion", "lie", "truth", "solitude", "justice", "bravery", "calm", "childhood", "confusion", "ability", "loss", "thought", "growth", "cleverness", "anger", "horror", "marriage", "delay", "philosophy", "generation", "wisdom", "dishonesty", "happiness", "coldness", "poverty", "brilliance", "luxuty", "sleep", "awareness", "idea", "disregard", "slavery", "growth", "company", "irritation", "advantage", "mercy", "speed", "pain", "gossip", "crime", "comfort", "frailty", "life", "patience", "omen", "deceit", "elegance"}, + "noun_collective_people": {"band", "troupe", "dynasty", "group", "bevy", "staff", "crowd", "party", "board", "regiment", "crew", "tribe", "body", "patrol", "congregation", "pack", "bunch", "company", "team", "mob", "caravan", "line", "troop", "choir", "host", "posse", "class", "gang", "horde"}, + "noun_collective_animal": {"cackle", "mustering", "mob", "wisp", "pod", "bale", "murder", "muster", "brace", "exaltation", "party", "flock", "cast", "sedge", "stand", "scold", "team", "covey", "trip", "army", "school", "nest", "leap", "host", "troop"}, + "noun_collective_thing": {"wad", "pair", "album", "string", "anthology", "reel", "outfit", "fleet", "comb", "archipelago", "quiver", "bale", "packet", "hedge", "basket", "orchard", "batch", "library", "battery", "set", "harvest", "block", "forest", "book", "group", "bouquet", "collection", "bowl", "stack", "bunch", "hand", "bundle", "catalog", "shower", "ream", "chest", "heap", "range", "cluster", "pack", "hail", "cloud", "galaxy", "sheaf", "clump"}, + "noun_countable": {"camp", "hospital", "shirt", "sock", "plant", "cup", "fork", "spoon", "plate", "straw", "town", "box", "bird", "father", "answer", "egg", "purse", "mirror", "mistake", "toilet", "toothbrush", "shower", "towel", "pool", "corner", "card", "lawn", "city", "egg", "yard", "burger", "kilometer", "mile", "father", "film", "actor", "issue", "machine", "liter", "room", "station", "journey", "castle", "hour", "finger", "boy", "book", "year", "second", "son", "month", "group", "hall", "cat", "week", "picture", "day", "village", "effect", "baby", "weekend", "class", "meal", "river", "grade", "bush", "desk", "stream", "method", "brother", "sister", "factory", "aunt", "bush", "program", "uncle", "ball", "cousin", "wall", "grandmother", "cup", "grandfather", "week", "school", "shirt", "child", "king", "road", "judge", "bridge", "car", "line", "book", "eye", "teacher", "foot", "party", "face", "day", "chest", "handle", "week", "hotel", "eye", "animal", "doctor", "adult", "village", "key", "bird", "bank", "program", "idea", "gun", "card", "brother", "dress", "room", "door", "mouth", "club", "game", "ring", "project", "sister", "road", "coat", "account", "group", "cigarette", "farm", "river", "college", "computer", "walk", "corner", "cat", "head", "street", "election", "country", "chair", "crowd", "cup", "plant", "farm", "handle", "model", "book", "message", "battle", "pen", "pencil", "elephant", "carrot", "onion", "garden", "country", "engine", "bill", "apple", "noun", "club", "crowd", "window", "field", "friend", "verb", "class", "flower", "seed", "lake", "plant", "animal", "ocean", "whale", "fish", "stream", "cloud", "couch", "steak", "problem", "light", "door", "room", "painting", "shop", "apartment", "candle", "adult", "building", "plan", "page", "ball", "game", "animal", "apartment", "box", "thought", "walk", "lady", "bottle", "article", "game", "kettle", "car", "house", "hoses", "orange", "phone", "app", "window", "door", "dollar", "foot", "cent", "library", "cat", "bed", "pound", "gate", "tomatoes", "gun", "holiday", "woman", "job", "shock", "salary", "tax", "coat", "scooter", "dog", "problem", "field", "answer", "ear", "camp", "case", "road", "woman", "product", "bridge", "man", "dream", "idea", "scheme", "invention", "cigarette", "mother", "friend", "chapter", "computer", "dream", "father", "child", "motor", "deskpath", "factory", "park", "newspaper", "hat", "dream", "table", "kitchen", "student", "captain", "doctor", "bus", "neck", "class", "list", "member", "chest", "valley", "product", "horse", "captain", "star", "hour", "page", "bus", "girl", "month", "child", "house", "boy", "bill", "kitchen", "chapter", "boat", "hand", "dress", "table", "wall", "chair", "train", "minute", "magazine", "bus", "party", "bird", "lake", "job", "nation", "bike", "election", "hand", "box", "beach", "address", "project", "task", "park", "face", "college", "bell", "plane", "store", "hall", "accident", "daughter", "ship", "candy", "smile", "city", "island", "case", "spot", "film", "husband", "artist", "tour", "bag", "boat", "driver", "office", "chair", "path", "dog", "bag", "finger", "apartment", "garden", "heart", "year", "engine", "girl", "day", "castle", "plane", "ring", "brother", "edge", "picture", "meeting", "tent", "dog", "hat", "head", "bottle", "hill"}, + "noun_uncountable": {"accommodation", "advertising", "air", "aid", "advice", "anger", "art", "assistance", "bread", "business", "butter", "calm", "cash", "chaos", "cheese", "childhood", "clothing", "coffee", "content", "corruption", "courage", "currency", "damage", "danger", "darkness", "data", "determination", "economics", "education", "electricity", "employment", "energy", "entertainment", "enthusiasm", "equipment", "evidence", "failure", "fame", "fire", "flour", "food", "freedom", "friendship", "fuel", "furniture", "fun", "genetics", "gold", "grammar", "guilt", "hair", "happiness", "harm", "health", "heat", "help", "homework", "honesty", "hospitality", "housework", "humour", "imagination", "importance", "information", "innocence", "intelligence", "jealousy", "juice", "justice", "kindness", "knowledge", "labour", "lack", "laughter", "leisure", "literature", "litter", "logic", "love", "luck", "magic", "management", "metal", "milk", "money", "motherhood", "motivation", "music", "nature", "news", "nutrition", "obesity", "oil", "old age", "oxygen", "paper", "patience", "permission", "pollution", "poverty", "power", "pride", "production", "progress", "pronunciation", "publicity", "punctuation", "quality", "quantity", "racism", "rain", "relaxation", "research", "respect", "rice", "room (space)", "rubbish", "safety", "salt", "sand", "seafood", "shopping", "silence", "smoke", "snow", "software", "soup", "speed", "spelling", "stress", "sugar", "sunshine", "tea", "tennis", "time", "tolerance", "trade", "traffic", "transportation", "travel", "trust", "understanding", "unemployment", "usage", "violence", "vision", "warmth", "water", "wealth", "weather", "weight", "welfare", "wheat", "width", "wildlife", "wisdom", "wood", "work", "yoga", "youth"}, + "noun_determiner": {"the", "a", "an", "this", "that", "these", "those", "my", "your", "his", "her", "its", "our", "their", "some", "any", "each", "every", "certain"}, + //"noun_proper": {}, // This refers to an actual person(John Doe), place(Chipotle, Tennessee) + + // Verbs + "verb_action": {"ride", "sit", "stand", "fight", "laugh", "read", "play", "listen", "cry", "think", "sing", "watch", "dance", "turn", "win", "fly", "cut", "throw", "sleep", "close", "open", "write", "give", "jump", "eat", "drink", "cook", "wash", "wait", "climb", "talk", "crawl", "dream", "dig", "clap", "knit", "sew", "smell", "kiss", "hug", "snore", "bathe", "bow", "paint", "dive", "ski", "stack", "buy", "shake"}, + "verb_transitive": {"accept", "acknowledge", "admit", "aggravate", "answer", "ask", "avoid", "beat", "bend", "bless", "bother", "break", "brush", "build", "cancel", "capture", "carry", "catch", "change", "chase", "chastise", "clean", "collect", "comfort", "contradict", "convert", "crack", "dazzle", "deceive", "define", "describe", "destroy", "discover", "distinguish", "drag", "dress", "dunk", "edify", "embarrass", "embrace", "enable", "encourage", "enlist", "entertain", "execute", "fascinate", "finish", "flick", "follow", "forget", "forgive", "freeze", "frighten", "furnish", "gather", "grab", "grasp", "grease", "grip", "handle", "hang", "head", "help", "highlight", "honour", "hurry", "hurt", "imitate", "impress", "indulge", "insert", "inspect", "interest", "interrupt", "intimidate", "involve", "irritate", "join", "judge", "keep", "key", "kill", "kiss", "knock", "lag", "lay", "lead", "lean", "leave", "lighten", "limit", "link", "load", "love", "lower", "maintain", "marry", "massage", "melt", "mock", "munch", "murder", "notice", "number", "offend", "order", "page", "paralyze", "persuade", "petrify", "pierce", "place", "please", "poison", "possess", "prepare", "promise", "protect", "punch", "purchase", "puzzle", "question", "quit", "raise", "reassure", "recognise", "refill", "remind", "remove", "repel", "research", "retard", "ring", "run", "satisfy", "scold", "select", "slap", "smell", "soften", "specify", "spell", "spit", "spread", "strike", "surprise", "swallow", "switch", "taste", "teach", "tickle", "tighten", "toast", "toss", "transform", "try", "turn", "tweak", "twist", "understand", "understimate", "unload", "unlock", "untie", "upgrade", "use", "vacate", "videotape", "vilify", "viplate", "wake", "want", "warm", "warn", "wash", "watch", "wear", "weep", "widen", "win", "wipe", "wrack", "wrap", "wreck"}, + "verb_intransitive": {"agree", "appear", "arrive", "become", "belong", "collapse", "consist", "cost", "cough", "cry", "depend", "die", "disappear", "emerge", "exist", "explode", "fade", "fall", "fast", "float", "fly", "gallop", "go", "grow", "happen", "have", "hiccup", "inquire", "jump", "kneel", "knock", "last", "laugh", "lead", "lean", "leap", "learn", "left", "lie", "limp", "listen", "live", "look", "march", "mourn", "move", "occur", "panic", "party", "pause", "peep", "pose", "pounce", "pout", "pray", "preen", "read", "recline", "relax", "relent", "remain", "respond", "result", "revolt", "rise", "roll", "run", "rush", "sail", "scream", "shake", "shout", "sigh", "sit", "skip", "sleep", "slide", "smell", "smile", "snarl", "sneeze", "soak", "spin", "spit", "sprint", "squeak", "stagger", "stand", "stay", "swim", "swing", "twist", "vanish", "vomit", "wade", "wait", "wake", "walk", "wander", "wave", "whirl", "wiggle", "work", "yell"}, + "verb_linking": {"am", "is", "was", "are", "were", "being", "been", "be", "have", "has", "had", "do", "does", "did", "shall", "will", "should", "would", "may", "might", "must", "can", "could"}, + "verb_helping": {"is", "can", "be", "do", "may", "had", "should", "was", "has", "could", "are", "will", "been", "did", "might", "were", "does", "must", "have", "would", "am", "shall", "being"}, + + // Adverbs + "adverb_manner": {"accidentally", "angrily", "anxiously", "awkwardly", "badly", "beautifully", "blindly", "boldly", "bravely", "brightly", "busily", "calmly", "carefully", "carelessly", "cautiously", "cheerfully", "clearly", "closely", "correctly", "courageously", "cruelly", "daringly", "deliberately", "doubtfully", "eagerly", "easily", "elegantly", "enormously", "enthusiastically", "equally", "eventually", "exactly", "faithfully", "fast", "fatally", "fiercely", "fondly", "foolishly", "fortunately", "frankly", "frantically", "generously", "gently", "gladly", "gracefully", "greedily", "happily", "hard", "hastily", "healthily", "honestly", "hungrily", "hurriedly", "inadequately", "ingeniously", "innocently", "inquisitively", "irritably", "joyously", "justly", "kindly", "lazily", "loosely", "loudly", "madly", "mortally", "mysteriously", "neatly", "nervously", "noisily", "obediently", "openly", "painfully", "patiently", "perfectly", "politely", "poorly", "powerfully", "promptly", "punctually", "quickly", "quietly", "rapidly", "rarely", "really", "recklessly", "regularly", "reluctantly", "repeatedly", "rightfully", "roughly", "rudely", "sadly", "safely", "selfishly", "sensibly", "seriously", "sharply", "shyly", "silently", "sleepily", "slowly", "smoothly", "so", "softly", "solemnly", "speedily", "stealthily", "sternly", "straight", "stupidly", "successfully", "suddenly", "suspiciously", "swiftly", "tenderly", "tensely", "thoughtfully", "tightly", "truthfully", "unexpectedly", "victoriously", "violently", "vivaciously", "warmly", "weakly", "wearily", "well", "wildly", "wisely"}, + "adverb_degree": {"almost", "absolutely", "awfully", "badly", "barely", "completely", "decidedly", "deeply", "enough", "enormously", "entirely", "extremely", "fairly", "far", "fully", "greatly", "hardly", "highly", "how", "incredibly", "indeed", "intensely", "just", "least", "less", "little", "lots", "most", "much", "nearly", "perfectly", "positively", "practically", "pretty", "purely", "quite", "rather", "really", "scarcely", "simply", "so", "somewhat", "strongly", "terribly", "thoroughly", "too", "totally", "utterly", "very", "virtually", "well"}, + "adverb_place": {"about", "above", "abroad", "anywhere", "away", "back", "backwards", "behind", "below", "down", "downstairs", "east", "elsewhere", "far", "here", "in", "indoors", "inside", "near", "nearby", "off", "on", "out", "outside", "over", "there", "towards", "under", "up", "upstairs", "where"}, + "adverb_time_definite": {"now", "then", "today", "tomorrow", "tonight", "yesterday"}, + "adverb_time_indefinite": {"already", "before", "early", "earlier", "eventually", "finally", "first", "formerly", "just", "last", "late", "later", "lately", "next", "previously", "recently", "since", "soon", "still", "yet"}, + "adverb_frequency_definite": {"annually", "daily", "fortnightly", "hourly", "monthly", "nightly", "quarterly", "weekly", "yearly"}, + "adverb_frequency_indefinite": {"always", "constantly", "ever", "frequently", "generally", "infrequently", "never", "normally", "occasionally", "often", "rarely", "regularly", "seldom", "sometimes", "regularly", "usually"}, + + // Prepositions + "preposition_simple": {"at", "by", "as", "but", "from", "for", "into", "in", "than", "of", "off", "on", "out", "over", "till", "to", "up", "upon", "with", "under", "down"}, + "preposition_double": {"outside of", "out of", "upon", "within", "inside", "without", "onto", "from behind", "because of", "out of", "throughout", "up to", "before", "due to", "according to", "from beneath", "next to", "from above"}, + "preposition_compound": {"according to", "as to", "onto", "across", "after", "beyond", "without", "opposite to", "away from", "aside from", "in favor of", "in front of", "because of", "as for", "near to", "behind", "along", "outside", "on account of", "on behalf of", "but for", "ahead of", "close to", "despite", "depending on", "due to", "in addition to", "next to", "in between", "in case of", "owing to", "along with", "around", "between", "apart from", "in return for", "out of", "instead of", "outside of", "other than", "together with", "up to", "above", "about"}, + + // Adjectives + "adjective_descriptive": {"adorable", "adventurous", "agreeable", "alive", "aloof", "amused", "angry", "annoying", "anxious", "arrogant", "ashamed", "attractive", "auspicious", "awful", "bad", "beautiful", "black", "blue", "blushing", "bored", "brave", "bright", "brown", "busy", "calm", "careful", "cautious", "charming", "cheerful", "clean", "clear", "clever", "clumsy", "colorful", "comfortable", "concerning", "condemned", "confusing", "cooperative", "courageous", "creepy", "crowded", "cruel", "curios", "cute", "dangerous", "dark", "defiant", "delightful", "difficult", "disgusting", "distinct", "disturbed", "dizzying", "drab", "dull", "eager", "easy", "elated", "elegant", "embarrassed", "enchanted", "encouraging", "energetic", "enthusiastic", "envious", "evil", "exciting", "expensive", "exuberant", "faithful", "famous", "fancy", "fantastic", "fierce", "filthy", "fine", "foolish", "fragile", "frail", "frantic", "friendly", "frightening", "funny", "gentle", "gifted", "glamorous", "gleaming", "glorious", "good", "gorgeous", "graceful", "green", "grieving", "grumpy", "handsome", "happy", "healthy", "helpful", "helpless", "hilarious", "homeless", "horrible", "hungry", "hurt", "ill", "important", "impossible", "impromptu", "improvised", "inexpensive", "innocent", "inquiring", "itchy", "jealous", "jittery", "joyous", "kind", "knightly", "lazy", "lemony", "light", "lingering", "lively", "lonely", "long", "lovely", "lucky", "magnificent", "modern", "motionless", "muddy", "mushy", "mysterious", "naughty", "niche", "nervous", "nice", "nutty", "obedient", "obnoxious", "odd", "open", "orange", "outrageous", "outstanding", "panicked", "perfect", "pink", "plain", "pleasant", "poised", "poor", "powerless", "precious", "prickling", "proud", "purple", "puzzled", "quaint", "queer", "quizzical", "realistic", "red", "relieved", "repelling", "repulsive", "rich", "scary", "scenic", "selfish", "shiny", "shy", "silly", "sleepy", "smiling", "smoggy", "sore", "sparkly", "splendid", "spotted", "stormy", "strange", "stupid", "successful", "super", "talented", "tame", "tasty", "tender", "tense", "terse", "terrible", "thankful", "thoughtful", "tired", "tough", "troubling", "ugly", "uninterested", "unusual", "upset", "uptight", "varied", "vast", "victorious", "wandering", "weary", "white", "wicked", "wide", "wild", "witty", "worrisome", "wrong", "yellow", "young", "zealous"}, + "adjective_quantitative": {"a little", "a little bit", "a lot", "abundant", "all", "any", "couple", "double", "each", "either", "empty", "enough", "enough of", "every", "few", "full", "great", "half", "heavily", "heavy", "huge", "hundred", "hundreds", "insufficient", "light", "little", "lots of", "many", "most", "much", "neither", "no", "numerous", "plenty of", "several", "significant", "single", "so few", "some", "sparse", "substantial", "sufficient", "too", "whole"}, + "adjective_proper": {"Afghan", "African", "Alaskan", "Alpine", "Amazonian", "American", "Antarctic", "Aristotelian", "Asian", "Atlantean", "Atlantic", "Bahamian", "Bahrainean", "Balinese", "Bangladeshi", "Barbadian", "Barcelonian", "Beethovenian", "Belgian", "Beninese", "Bismarckian", "Brazilian", "British", "Buddhist", "Burkinese", "Burmese", "Caesarian", "Californian", "Cambodian", "Canadian", "Chinese", "Christian", "Colombian", "Confucian", "Congolese", "Cormoran", "Costa Rican", "Cypriot", "Danish", "Darwinian", "Diabolical", "Dutch", "Ecuadorian", "Egyptian", "Einsteinian", "Elizabethan", "English", "Finnish", "French", "Freudian", "Gabonese", "Gaussian", "German", "Greek", "Guyanese", "Himalayan", "Hindu", "Hitlerian", "Honduran", "Icelandic", "Indian", "Indonesian", "Intelligent", "Iranian", "Iraqi", "Italian", "Japanese", "Jungian", "Kazakh", "Korean", "kuban", "Kyrgyz", "Laotian", "Lebanese", "Lilliputian", "Lincolnian", "Machiavellian", "Madagascan", "Malagasy", "Marxist", "Mayan", "Mexican", "Middle Eastern", "Monacan", "Mozartian", "Muscovite", "Nepalese", "Newtonian", "Norwegian", "Orwellian", "Pacific", "Parisian", "Peruvian", "Philippine", "Plutonian", "Polish", "Polynesian", "Portuguese", "Putinist", "Roman", "Romanian", "Rooseveltian", "Russian", "Salvadorean", "Sammarinese", "Senegalese", "Shakespearean", "Slovak", "Somali", "South American", "Spanish", "Spanish", "Sri-Lankan", "Sudanese", "Swazi", "Swiss", "Taiwanese", "Thai", "Thatcherite", "Tibetan", "Torontonian", "Turkish", "Turkishish", "Turkmen", "Uzbek", "Victorian", "Viennese", "Vietnamese", "Welsh"}, + "adjective_demonstrative": {"this", "that", "these", "those", "it", "here", "there", "over there"}, + "adjective_possessive": {"my", "your", "his", "her", "its", "our", "their"}, + "adjective_interrogative": {"what", "whose", "where", "why", "how", "which"}, + "adjective_indefinite": {"all", "any", "anything", "everyone", "few", "nobody", "one", "some", "someone", "everybody", "anyone", "each", "everything", "many", "none", "several", "somebody"}, + + // Pronouns + "pronoun_personal": {"I", "we", "you", "he", "she", "it", "they"}, + "pronoun_object": {"me", "us", "you", "her", "him", "it", "them"}, + "pronoun_possessive": {"mine", "ours", "yours", "hers", "his", "theirs"}, + "pronoun_reflective": {"myself", "yourself", "herself", "himself", "itself", "ourselves", "yourselves", "themselves"}, + "pronoun_indefinite": {"all", "another", "any", "anybody", "anyone", "anything", "both", "each", "either", "everybody", "everyone", "everything", "few", "many", "most", "neither", "nobody", "none", "no one", "nothing", "one", "other", "others", "several", "some", "somebody", "someone", "something", "such"}, + "pronoun_demonstrative": {"this", "that", "these", "those"}, + "pronoun_interrogative": {"who", "whom", "which", "what", "whose", "where", "when", "why", "how"}, + "pronoun_relative": {"as", "that", "what", "whatever", "which", "whichever", "who", "whoever", "whom", "whomever", "whose"}, + + // Connectives + "connective_time": {"after a while", "afterwards", "at once", "at this moment", "at this point", "before that", "finally", "first", "here", "in the end", "lastly", "later on", "meanwhile", "next", "next time", "now", "on another occasion", "previously", "since", "soon", "straightaway", "then", "until then", "when", "whenever", "while"}, + "connective_comparative": {"additionally", "also", "as well", "even", "furthermore", "in addition", "indeed", "let alone", "moreover", "not only", "alternatively", "anyway", "but", "by contrast", "differs from", "elsewhere", "even so", "however", "in contrast", "in fact", "in other respects", "in spite of this", "in that respect", "instead", "nevertheless", "on the contrary", "on the other hand", "rather", "though", "whereas", "yet", "after all", "anyway", "besides", "moreover"}, + "connective_complaint": {"besides", "e.g.", "for example", "for instance", "i.e.", "in other words", "in that", "that is to say"}, + "connective_listing": {"firstly", "secondly", "first of all", "finally", "lastly", "for one thing", "for another", "in the first place", "to begin with", "next", "in summation", "to conclude"}, + "connective_casual": {"accordingly", "all the same", "an effect of", "an outcome of", "an upshot of", "as a consequence of", "as a result of", "because", "caused by", "consequently", "despite this", "even though", "hence", "however", "in that case", "moreover", "nevertheless", "otherwise", "so", "so as", "stemmed from", "still", "then", "therefore", "though", "under the circumstances", "yet"}, + "connective_examplify": {"accordingly", "as a result", "as exemplified by", "consequently", "for example", "for instance", "for one thing", "including", "provided that", "since", "so", "such as", "then", "therefore", "these include", "through", "unless", "without"}, + + // Misc + "interjection": {"wow", "hey", "oops", "ouch", "yay", "aha", "eek", "huh", "hmm", "whoa", "yikes", "phew", "gee", "alas", "bravo"}, +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/doc.go b/vendor/github.com/brianvoe/gofakeit/v7/doc.go new file mode 100644 index 0000000000..dc06a1bfe7 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/doc.go @@ -0,0 +1,4 @@ +/* +Package gofakeit provides a set of functions that generate random data +*/ +package gofakeit diff --git a/vendor/github.com/brianvoe/gofakeit/v7/emoji.go b/vendor/github.com/brianvoe/gofakeit/v7/emoji.go new file mode 100644 index 0000000000..c9e9785e99 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/emoji.go @@ -0,0 +1,98 @@ +package gofakeit + +// Emoji will return a random fun emoji +func Emoji() string { return emoji(GlobalFaker) } + +// Emoji will return a random fun emoji +func (f *Faker) Emoji() string { return emoji(f) } + +func emoji(f *Faker) string { return getRandValue(f, []string{"emoji", "emoji"}) } + +// EmojiDescription will return a random fun emoji description +func EmojiDescription() string { return emojiDescription(GlobalFaker) } + +// EmojiDescription will return a random fun emoji description +func (f *Faker) EmojiDescription() string { return emojiDescription(f) } + +func emojiDescription(f *Faker) string { return getRandValue(f, []string{"emoji", "description"}) } + +// EmojiCategory will return a random fun emoji category +func EmojiCategory() string { return emojiCategory(GlobalFaker) } + +// EmojiCategory will return a random fun emoji category +func (f *Faker) EmojiCategory() string { return emojiCategory(f) } + +func emojiCategory(f *Faker) string { return getRandValue(f, []string{"emoji", "category"}) } + +// EmojiAlias will return a random fun emoji alias +func EmojiAlias() string { return emojiAlias(GlobalFaker) } + +// EmojiAlias will return a random fun emoji alias +func (f *Faker) EmojiAlias() string { return emojiAlias(f) } + +func emojiAlias(f *Faker) string { return getRandValue(f, []string{"emoji", "alias"}) } + +// EmojiTag will return a random fun emoji tag +func EmojiTag() string { return emojiTag(GlobalFaker) } + +// EmojiTag will return a random fun emoji tag +func (f *Faker) EmojiTag() string { return emojiTag(f) } + +func emojiTag(f *Faker) string { return getRandValue(f, []string{"emoji", "tag"}) } + +func addEmojiLookup() { + AddFuncLookup("emoji", Info{ + Display: "Emoji", + Category: "emoji", + Description: "Digital symbol expressing feelings or ideas in text messages and online chats", + Example: "🤣", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return emoji(f), nil + }, + }) + + AddFuncLookup("emojidescription", Info{ + Display: "Emoji Description", + Category: "emoji", + Description: "Brief explanation of the meaning or emotion conveyed by an emoji", + Example: "face vomiting", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return emojiDescription(f), nil + }, + }) + + AddFuncLookup("emojicategory", Info{ + Display: "Emoji Category", + Category: "emoji", + Description: "Group or classification of emojis based on their common theme or use, like 'smileys' or 'animals'", + Example: "Smileys & Emotion", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return emojiCategory(f), nil + }, + }) + + AddFuncLookup("emojialias", Info{ + Display: "Emoji Alias", + Category: "emoji", + Description: "Alternative name or keyword used to represent a specific emoji in text or code", + Example: "smile", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return emojiAlias(f), nil + }, + }) + + AddFuncLookup("emojitag", Info{ + Display: "Emoji Tag", + Category: "emoji", + Description: "Label or keyword associated with an emoji to categorize or search for it easily", + Example: "happy", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return emojiTag(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/error.go b/vendor/github.com/brianvoe/gofakeit/v7/error.go new file mode 100644 index 0000000000..e3726e7e55 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/error.go @@ -0,0 +1,241 @@ +package gofakeit + +import ( + "errors" +) + +// Error will return a random generic error +func Error() error { + return err(GlobalFaker) +} + +// Error will return a random generic error +func (f *Faker) Error() error { + return err(f) +} + +func err(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "generic"})) + return errors.New(genStr) +} + +// ErrorObject will return a random error object word +func ErrorObject() error { + return errorObject(GlobalFaker) +} + +// ErrorObject will return a random error object word +func (f *Faker) ErrorObject() error { + return errorObject(f) +} + +func errorObject(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "object"})) + return errors.New(genStr) +} + +// ErrorDatabase will return a random database error +func ErrorDatabase() error { + return errorDatabase(GlobalFaker) +} + +// ErrorDatabase will return a random database error +func (f *Faker) ErrorDatabase() error { + return errorDatabase(f) +} + +func errorDatabase(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "database"})) + return errors.New(genStr) +} + +// ErrorGRPC will return a random gRPC error +func ErrorGRPC() error { + return errorGRPC(GlobalFaker) +} + +// ErrorGRPC will return a random gRPC error +func (f *Faker) ErrorGRPC() error { + return errorGRPC(f) +} + +func errorGRPC(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "grpc"})) + return errors.New(genStr) +} + +// ErrorHTTP will return a random HTTP error +func ErrorHTTP() error { + return errorHTTP(GlobalFaker) +} + +// ErrorHTTP will return a random HTTP error +func (f *Faker) ErrorHTTP() error { + return errorHTTP(f) +} + +func errorHTTP(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "http"})) + return errors.New(genStr) +} + +// ErrorHTTPClient will return a random HTTP client error response (400-418) +func ErrorHTTPClient() error { + return errorHTTPClient(GlobalFaker) +} + +// ErrorHTTPClient will return a random HTTP client error response (400-418) +func (f *Faker) ErrorHTTPClient() error { + return errorHTTPClient(f) +} + +func errorHTTPClient(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "http_client"})) + return errors.New(genStr) +} + +// ErrorHTTPServer will return a random HTTP server error response (500-511) +func ErrorHTTPServer() error { + return errorHTTPServer(GlobalFaker) +} + +// ErrorHTTPServer will return a random HTTP server error response (500-511) +func (f *Faker) ErrorHTTPServer() error { + return errorHTTPServer(f) +} + +func errorHTTPServer(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "http_server"})) + return errors.New(genStr) +} + +// ErrorRuntime will return a random runtime error +func ErrorRuntime() error { + return errorRuntime(GlobalFaker) +} + +// ErrorRuntime will return a random runtime error +func (f *Faker) ErrorRuntime() error { + return errorRuntime(f) +} + +func errorRuntime(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "runtime"})) + return errors.New(genStr) +} + +// ErrorValidation will return a random validation error +func ErrorValidation() error { + return errorValidation(GlobalFaker) +} + +// ErrorValidation will return a random validation error +func (f *Faker) ErrorValidation() error { + return errorValidation(f) +} + +func errorValidation(f *Faker) error { + genStr, _ := generate(f, getRandValue(f, []string{"error", "validation"})) + return errors.New(genStr) +} + +func addErrorLookup() { + AddFuncLookup("error", Info{ + Display: "Error", + Category: "error", + Description: "Message displayed by a computer or software when a problem or mistake is encountered", + Example: "syntax error", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return err(f), nil + }, + }) + + AddFuncLookup("errorobject", Info{ + Display: "Error object word", + Category: "error", + Description: "Various categories conveying details about encountered errors", + Example: "protocol", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorObject(f), nil + }, + }) + + AddFuncLookup("errordatabase", Info{ + Display: "Database error", + Category: "error", + Description: "A problem or issue encountered while accessing or managing a database", + Example: "sql error", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorDatabase(f), nil + }, + }) + + AddFuncLookup("errorgrpc", Info{ + Display: "gRPC error", + Category: "error", + Description: "Communication failure in the high-performance, open-source universal RPC framework", + Example: "client protocol error", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorGRPC(f), nil + }, + }) + + AddFuncLookup("errorhttp", Info{ + Display: "HTTP error", + Category: "error", + Description: "A problem with a web http request", + Example: "invalid method", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorHTTP(f), nil + }, + }) + + AddFuncLookup("errorhttpclient", Info{ + Display: "HTTP client error", + Category: "error", + Description: "Failure or issue occurring within a client software that sends requests to web servers", + Example: "request timeout", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorHTTPClient(f), nil + }, + }) + + AddFuncLookup("errorhttpserver", Info{ + Display: "HTTP server error", + Category: "error", + Description: "Failure or issue occurring within a server software that recieves requests from clients", + Example: "internal server error", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorHTTPServer(f), nil + }, + }) + + AddFuncLookup("errorruntime", Info{ + Display: "Runtime error", + Category: "error", + Description: "Malfunction occuring during program execution, often causing abrupt termination or unexpected behavior", + Example: "address out of bounds", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorRuntime(f), nil + }, + }) + + AddFuncLookup("errorvalidation", Info{ + Display: "Validation error", + Category: "error", + Description: "Occurs when input data fails to meet required criteria or format specifications", + Example: "missing required field", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return errorValidation(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/fakeable.go b/vendor/github.com/brianvoe/gofakeit/v7/fakeable.go new file mode 100644 index 0000000000..01932ec27c --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/fakeable.go @@ -0,0 +1,84 @@ +package gofakeit + +import ( + "errors" + "fmt" + "reflect" +) + +// Fakeable is an interface that can be implemented by a type to provide a custom fake value. +type Fakeable interface { + // Fake returns a fake value for the type. + Fake(faker *Faker) (any, error) +} + +func isFakeable(t reflect.Type) bool { + fakeableTyp := reflect.TypeOf((*Fakeable)(nil)).Elem() + + return t.Implements(fakeableTyp) || reflect.PointerTo(t).Implements(fakeableTyp) +} + +func callFake(faker *Faker, v reflect.Value, possibleKinds ...reflect.Kind) (any, error) { + f, ok := v.Addr().Interface().(Fakeable) + if !ok { + return nil, errors.New("not a Fakeable type") + } + + fakedValue, err := f.Fake(faker) + if err != nil { + return nil, fmt.Errorf("error calling Fake: %w", err) + } + k := reflect.TypeOf(fakedValue).Kind() + if !containsKind(possibleKinds, k) { + return nil, fmt.Errorf("returned value kind %q is not amongst the valid ones: %v", k, possibleKinds) + } + + switch k { + case reflect.String: + return reflect.ValueOf(fakedValue).String(), nil + case reflect.Bool: + return reflect.ValueOf(fakedValue).Bool(), nil + case reflect.Int: + return int(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int8: + return int8(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int16: + return int16(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int32: + return int32(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int64: + return int64(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Uint: + return uint(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint8: + return uint8(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint16: + return uint16(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint32: + return uint32(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint64: + return uint64(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Float32: + return float32(reflect.ValueOf(fakedValue).Float()), nil + case reflect.Float64: + return float64(reflect.ValueOf(fakedValue).Float()), nil + case reflect.Slice, reflect.Array: + return reflect.ValueOf(fakedValue).Interface(), nil + case reflect.Map: + return reflect.ValueOf(fakedValue).Interface(), nil + case reflect.Struct: + return reflect.ValueOf(fakedValue).Interface(), nil + + default: + return nil, fmt.Errorf("unsupported type %q", k) + } +} + +func containsKind(possibleKinds []reflect.Kind, kind reflect.Kind) bool { + for _, k := range possibleKinds { + if k == kind { + return true + } + } + return false +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/faker.go b/vendor/github.com/brianvoe/gofakeit/v7/faker.go new file mode 100644 index 0000000000..2271eac4ec --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/faker.go @@ -0,0 +1,112 @@ +package gofakeit + +import ( + "errors" + "math/rand/v2" + "reflect" + "sync" + + "github.com/brianvoe/gofakeit/v7/source" +) + +// Create global variable to deal with global function call +var GlobalFaker *Faker = New(0) + +// Faker struct is the primary struct for using localized +type Faker struct { + Rand rand.Source + + // Lock to make thread safe + Locked bool + mu sync.Mutex +} + +// New creates and returns a new Faker struct seeded with a given seed +// using the PCG algorithm in lock mode for thread safety +func New(seed uint64) *Faker { + // If seed is 0, use a random crypto seed + if seed == 0 { + faker := NewFaker(source.NewCrypto(), false) + seed = faker.Uint64() + } + + return &Faker{ + Rand: rand.NewPCG(seed, seed), + Locked: true, + } +} + +// NewFaker takes in a rand.Source and thread lock state and returns a new Faker struct +func NewFaker(src rand.Source, lock bool) *Faker { + return &Faker{ + Rand: src, + Locked: lock, + } +} + +// Seed attempts to seed the Faker with the given seed +func (f *Faker) Seed(args ...any) error { + // Lock if locked + if f.Locked { + f.mu.Lock() + defer f.mu.Unlock() + } + + // Ensure GlobalFaker is not nil and Rand is initialized + if GlobalFaker == nil || GlobalFaker.Rand == nil { + return errors.New("GlobalFaker or GlobalFaker.Rand is nil") + } + + // If args is empty or 0, seed with a random crypto seed + if len(args) == 0 { + faker := NewFaker(source.NewCrypto(), false) + args = append(args, faker.Uint64()) + } + + if args[0] == 0 { + faker := NewFaker(source.NewCrypto(), false) + args[0] = faker.Uint64() + } + + // Retrieve the Seed method + method := reflect.ValueOf(GlobalFaker.Rand).MethodByName("Seed") + if !method.IsValid() { + return errors.New("Seed method not found") + } + + // Adjust args if method requires exactly 2 args but only 1 was provided + if method.Type().NumIn() == 2 && len(args) == 1 { + args = append(args, args[0]) // Duplicate the first value if only one is provided + } + + // Get array of function argument types and prepare converted arguments + argTypes := make([]reflect.Type, method.Type().NumIn()) + convertedArgs := make([]reflect.Value, len(args)) + for i := 0; i < method.Type().NumIn(); i++ { + argTypes[i] = method.Type().In(i) + } + + // Convert args to the expected type by the Seed method + for i, arg := range args { + if i < len(argTypes) { // Ensure arg index is within argTypes bounds + argValue := reflect.ValueOf(arg) + // Check if conversion is necessary + if argValue.Type().ConvertibleTo(argTypes[i]) { + convertedArgs[i] = argValue.Convert(argTypes[i]) + } else { + // If not convertible, use the argument as is (reflectively) + convertedArgs[i] = argValue + } + } + } + + // Dynamically call the Seed method with converted arguments + method.Call(convertedArgs) + + return nil +} + +// Seed attempts to seed the GlobalFaker with the given seed +func Seed(args ...any) error { + return GlobalFaker.Seed(args...) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/file.go b/vendor/github.com/brianvoe/gofakeit/v7/file.go new file mode 100644 index 0000000000..ffefe8630e --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/file.go @@ -0,0 +1,41 @@ +package gofakeit + +// FileExtension will generate a random file extension +func FileExtension() string { return fileExtension(GlobalFaker) } + +// FileExtension will generate a random file extension +func (f *Faker) FileExtension() string { return fileExtension(f) } + +func fileExtension(f *Faker) string { return getRandValue(f, []string{"file", "extension"}) } + +// FileMimeType will generate a random mime file type +func FileMimeType() string { return fileMimeType(GlobalFaker) } + +// FileMimeType will generate a random mime file type +func (f *Faker) FileMimeType() string { return fileMimeType(f) } + +func fileMimeType(f *Faker) string { return getRandValue(f, []string{"file", "mime_type"}) } + +func addFileLookup() { + AddFuncLookup("fileextension", Info{ + Display: "File Extension", + Category: "file", + Description: "Suffix appended to a filename indicating its format or type", + Example: "nes", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return fileExtension(f), nil + }, + }) + + AddFuncLookup("filemimetype", Info{ + Display: "File Mime Type", + Category: "file", + Description: "Defines file format and nature for browsers and email clients using standardized identifiers", + Example: "application/json", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return fileMimeType(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/finance.go b/vendor/github.com/brianvoe/gofakeit/v7/finance.go new file mode 100644 index 0000000000..4e363326b8 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/finance.go @@ -0,0 +1,127 @@ +package gofakeit + +import ( + "strconv" + "unicode" +) + +const cusipStr = upperStr + numericStr + +// CUSIP +func Cusip() string { + return cusip(GlobalFaker) +} + +func (f *Faker) Cusip() string { + return cusip(f) +} + +func cusip(f *Faker) string { + cusipBytes := make([]byte, 8) + for i := 0; i < len(cusipBytes); i++ { + cusipBytes[i] = byte(cusipStr[f.IntN(len(cusipStr))]) + } + + baseCusip := string(cusipBytes) + + chkDigit := cusipChecksumDigit(baseCusip) + return baseCusip + chkDigit +} + +// ISIN +func Isin() string { + return isin(GlobalFaker) +} + +func (f *Faker) Isin() string { + return isin(f) +} + +func isin(f *Faker) string { + countryCode := countryAbr(f) + nsin := cusip(f) + isinChkDig := isinChecksumDigit(countryCode + nsin) + return countryCode + nsin + isinChkDig +} + +// cusipChecksumDigit returns the checksum digit for a CUSIP +func cusipChecksumDigit(cusip string) string { + sum := 0 + for i, c := range cusip { + v := 0 + if unicode.IsDigit(c) { + v = int(c - '0') + } + if unicode.IsLetter(c) { + //0-indexed ordinal position of Letter + 10 + v = int(c-'A') + 10 + } + if i%2 != 0 { + // Multiply odd digits by two + v = v * 2 + } + + sum = sum + int(v/10) + v%10 + } + + return strconv.Itoa((10 - (sum % 10)) % 10) +} + +// isinChecksumDigit returns the checksum digit for an ISIN +func isinChecksumDigit(isin string) string { + isinDigits := make([]int, 0) + for _, c := range isin { + if unicode.IsLetter(c) { + letterVal := int(c) - 55 + // Each digit is added as a separate value + isinDigits = append(isinDigits, letterVal/10) + isinDigits = append(isinDigits, letterVal%10) + } + if unicode.IsDigit(c) { + isinDigits = append(isinDigits, int(c-'0')) + } + } + + oddSum := 0 + evenSum := 0 + + // Take the per digit sum of the digitized ISIN, doubling even indexed digits + for i, d := range isinDigits { + if i%2 == 0 { + elem := 2 * d + if elem > 9 { + // If the element now has two digits, sum those digits + elem = (elem % 10) + (elem / 10) + } + evenSum += elem + } else { + oddSum += d + } + } + + return strconv.Itoa((10 - (oddSum+evenSum)%10) % 10) +} + +// Lookup Adds +func addFinanceLookup() { + AddFuncLookup("cusip", Info{ + Display: "CUSIP", + Category: "finance", + Description: "Unique identifier for securities, especially bonds, in the United States and Canada", + Example: "38259P508", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return cusip(f), nil + }, + }) + AddFuncLookup("isin", Info{ + Display: "ISIN", + Category: "finance", + Description: "International standard code for uniquely identifying securities worldwide", + Example: "CVLRQCZBXQ97", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return isin(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/food.go b/vendor/github.com/brianvoe/gofakeit/v7/food.go new file mode 100644 index 0000000000..111dbc25aa --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/food.go @@ -0,0 +1,177 @@ +package gofakeit + +import ( + "strings" +) + +// Fruit will return a random fruit name +func Fruit() string { return fruit(GlobalFaker) } + +// Fruit will return a random fruit name +func (f *Faker) Fruit() string { return fruit(f) } + +func fruit(f *Faker) string { return getRandValue(f, []string{"food", "fruit"}) } + +// Vegetable will return a random vegetable name +func Vegetable() string { return vegetable(GlobalFaker) } + +// Vegetable will return a random vegetable name +func (f *Faker) Vegetable() string { return vegetable(f) } + +func vegetable(f *Faker) string { return getRandValue(f, []string{"food", "vegetable"}) } + +// Breakfast will return a random breakfast name +func Breakfast() string { return breakfast(GlobalFaker) } + +// Breakfast will return a random breakfast name +func (f *Faker) Breakfast() string { return breakfast(f) } + +func breakfast(f *Faker) string { + v := getRandValue(f, []string{"food", "breakfast"}) + return strings.ToUpper(v[:1]) + v[1:] +} + +// Lunch will return a random lunch name +func Lunch() string { return lunch(GlobalFaker) } + +// Lunch will return a random lunch name +func (f *Faker) Lunch() string { return lunch(f) } + +func lunch(f *Faker) string { + v := getRandValue(f, []string{"food", "lunch"}) + return strings.ToUpper(v[:1]) + v[1:] +} + +// Dinner will return a random dinner name +func Dinner() string { return dinner(GlobalFaker) } + +// Dinner will return a random dinner name +func (f *Faker) Dinner() string { return dinner(f) } + +func dinner(f *Faker) string { + v := getRandValue(f, []string{"food", "dinner"}) + return strings.ToUpper(v[:1]) + v[1:] +} + +// Drink will return a random drink name +func Drink() string { return drink(GlobalFaker) } + +// Drink will return a random drink name +func (f *Faker) Drink() string { return drink(f) } + +func drink(f *Faker) string { + v := getRandValue(f, []string{"food", "drink"}) + return strings.ToUpper(v[:1]) + v[1:] +} + +// Snack will return a random snack name +func Snack() string { return snack(GlobalFaker) } + +// Snack will return a random snack name +func (f *Faker) Snack() string { return snack(f) } + +func snack(f *Faker) string { + v := getRandValue(f, []string{"food", "snack"}) + return strings.ToUpper(v[:1]) + v[1:] +} + +// Dessert will return a random dessert name +func Dessert() string { return dessert(GlobalFaker) } + +// Dessert will return a random dessert name +func (f *Faker) Dessert() string { return dessert(f) } + +func dessert(f *Faker) string { + v := getRandValue(f, []string{"food", "dessert"}) + return strings.ToUpper(v[:1]) + v[1:] +} + +func addFoodLookup() { + AddFuncLookup("fruit", Info{ + Display: "Fruit", + Category: "food", + Description: "Edible plant part, typically sweet, enjoyed as a natural snack or dessert", + Example: "Peach", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return fruit(f), nil + }, + }) + + AddFuncLookup("vegetable", Info{ + Display: "Vegetable", + Category: "food", + Description: "Edible plant or part of a plant, often used in savory cooking or salads", + Example: "Amaranth Leaves", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return vegetable(f), nil + }, + }) + + AddFuncLookup("breakfast", Info{ + Display: "Breakfast", + Category: "food", + Description: "First meal of the day, typically eaten in the morning", + Example: "Blueberry banana happy face pancakes", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return breakfast(f), nil + }, + }) + + AddFuncLookup("lunch", Info{ + Display: "Lunch", + Category: "food", + Description: "Midday meal, often lighter than dinner, eaten around noon", + Example: "No bake hersheys bar pie", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return lunch(f), nil + }, + }) + + AddFuncLookup("dinner", Info{ + Display: "Dinner", + Category: "food", + Description: "Evening meal, typically the day's main and most substantial meal", + Example: "Wild addicting dip", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return dinner(f), nil + }, + }) + + AddFuncLookup("drink", Info{ + Display: "Drink", + Category: "food", + Description: "Liquid consumed for hydration, pleasure, or nutritional benefits", + Example: "Soda", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return drink(f), nil + }, + }) + + AddFuncLookup("snack", Info{ + Display: "Snack", + Category: "food", + Description: "Random snack", + Example: "Small, quick food item eaten between meals", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return snack(f), nil + }, + }) + + AddFuncLookup("dessert", Info{ + Display: "Dessert", + Category: "food", + Description: "Sweet treat often enjoyed after a meal", + Example: "French napoleons", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return dessert(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/game.go b/vendor/github.com/brianvoe/gofakeit/v7/game.go new file mode 100644 index 0000000000..0e13700019 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/game.go @@ -0,0 +1,101 @@ +package gofakeit + +import ( + "fmt" + "strings" +) + +// Gamertag will generate a random video game username +func Gamertag() string { return gamertag(GlobalFaker) } + +// Gamertag will generate a random video game username +func (f *Faker) Gamertag() string { return gamertag(f) } + +func gamertag(f *Faker) string { + str := "" + num := number(f, 1, 4) + switch num { + case 1: + str = fmt.Sprintf("%s%ser", title(nounConcrete(f)), title(verbAction(f))) + case 2: + str = fmt.Sprintf("%s%s", title(adjectiveDescriptive(f)), title(animal(f))) + case 3: + str = fmt.Sprintf("%s%s", title(adjectiveDescriptive(f)), title(nounConcrete(f))) + case 4: + str = fmt.Sprintf("%s%s", title(fruit(f)), title(adjectiveDescriptive(f))) + } + + // Randomly determine if we should add a number + if f.IntN(3) == 1 { + str += digitN(f, uint(number(f, 1, 3))) + } + + // Remove any spaces + str = strings.Replace(str, " ", "", -1) + + return str +} + +// Dice will generate a random set of dice +func Dice(numDice uint, sides []uint) []uint { return dice(GlobalFaker, numDice, sides) } + +// Dice will generate a random set of dice +func (f *Faker) Dice(numDice uint, sides []uint) []uint { return dice(f, numDice, sides) } + +func dice(f *Faker, numDice uint, sides []uint) []uint { + dice := make([]uint, numDice) + + // If we dont have any sides well set the sides to 6 + if len(sides) == 0 { + sides = []uint{6} + } + + for i := range dice { + // If sides[i] doesnt exist use the first side + if len(sides)-1 < i { + dice[i] = uint(number(f, 1, int(sides[0]))) + } else { + dice[i] = uint(number(f, 1, int(sides[i]))) + } + } + + return dice +} + +func addGameLookup() { + AddFuncLookup("gamertag", Info{ + Display: "Gamertag", + Category: "game", + Description: "User-selected online username or alias used for identification in games", + Example: "footinterpret63", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return gamertag(f), nil + }, + }) + + AddFuncLookup("dice", Info{ + Display: "Dice", + Category: "game", + Description: "Small, cube-shaped objects used in games of chance for random outcomes", + Example: "[5, 2, 3]", + Output: "[]uint", + Params: []Param{ + {Field: "numdice", Display: "Number of Dice", Type: "uint", Default: "1", Description: "Number of dice to roll"}, + {Field: "sides", Display: "Number of Sides", Type: "[]uint", Default: "[6]", Description: "Number of sides on each dice"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + numDice, err := info.GetUint(m, "numdice") + if err != nil { + return nil, err + } + + sides, err := info.GetUintArray(m, "sides") + if err != nil { + return nil, err + } + + return dice(f, numDice, sides), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/generate.go b/vendor/github.com/brianvoe/gofakeit/v7/generate.go new file mode 100644 index 0000000000..9ca091e733 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/generate.go @@ -0,0 +1,600 @@ +package gofakeit + +import ( + "encoding/json" + "errors" + "fmt" + "math" + "regexp/syntax" + "strings" +) + +// Generate fake information from given string. +// Replaceable values should be within {} +// +// Functions +// Ex: {firstname} - billy +// Ex: {sentence:3} - Record river mind. +// Ex: {number:1,10} - 4 +// Ex: {uuid} - 590c1440-9888-45b0-bd51-a817ee07c3f2 +// +// Letters/Numbers +// Ex: ### - 481 - random numbers +// Ex: ??? - fda - random letters +// +// For a complete list of runnable functions use FuncsLookup +func Generate(dataVal string) (string, error) { return generate(GlobalFaker, dataVal) } + +// Generate fake information from given string. +// Replaceable values should be within {} +// +// Functions +// Ex: {firstname} - billy +// Ex: {sentence:3} - Record river mind. +// Ex: {number:1,10} - 4 +// Ex: {uuid} - 590c1440-9888-45b0-bd51-a817ee07c3f2 +// +// Letters/Numbers +// Ex: ### - 481 - random numbers +// Ex: ??? - fda - random letters +// +// For a complete list of runnable functions use FuncsLookup +func (f *Faker) Generate(dataVal string) (string, error) { return generate(f, dataVal) } + +func generate(f *Faker, dataVal string) (string, error) { + // Replace # with numbers and ? with letters + dataVal = replaceWithNumbers(f, dataVal) + dataVal = replaceWithLetters(f, dataVal) + + // Check if string has any replaceable values + // Even if it doesnt its ok we will just return the string + if !strings.Contains(dataVal, "{") && !strings.Contains(dataVal, "}") { + return dataVal, nil + } + + // Variables to identify the index in which it exists + startCurly := -1 + startCurlyIgnore := []int{} + endCurly := -1 + endCurlyIgnore := []int{} + + // Loop through string characters + for i := 0; i < len(dataVal); i++ { + // Check for ignores if equal skip + shouldSkip := false + for _, igs := range startCurlyIgnore { + if i == igs { + shouldSkip = true + } + } + for _, ige := range endCurlyIgnore { + if i == ige { + shouldSkip = true + } + } + if shouldSkip { + continue + } + + // Identify items between brackets. Ex: {firstname} + if string(dataVal[i]) == "{" { + startCurly = i + continue + } + if startCurly != -1 && string(dataVal[i]) == "}" { + endCurly = i + } + if startCurly == -1 || endCurly == -1 { + continue + } + + // Get the value between brackets + fParts := dataVal[startCurly+1 : endCurly] + + // Check if has params separated by : + fNameSplit := strings.SplitN(fParts, ":", 2) + fName := "" + fParams := "" + if len(fNameSplit) >= 1 { + fName = fNameSplit[0] + } + if len(fNameSplit) >= 2 { + fParams = fNameSplit[1] + } + + // Check to see if its a replaceable lookup function + if info := GetFuncLookup(fName); info != nil { + // Get parameters, make sure params and the split both have values + mapParams := NewMapParams() + paramsLen := len(info.Params) + + // If just one param and its a string simply just pass it + if paramsLen == 1 && info.Params[0].Type == "string" { + mapParams.Add(info.Params[0].Field, fParams) + } else if paramsLen > 0 && fParams != "" { + var err error + splitVals, err := funcLookupSplit(fParams) + if err != nil { + return "", err + } + mapParams, err = addSplitValsToMapParams(splitVals, info, mapParams) + if err != nil { + return "", err + } + } + if mapParams.Size() == 0 { + mapParams = nil + } + + // Call function + fValue, err := info.Generate(f, mapParams, info) + if err != nil { + return "", err + } + + // Successfully found, run replace with new value + dataVal = strings.Replace(dataVal, "{"+fParts+"}", fmt.Sprintf("%v", fValue), 1) + + // Reset the curly index back to -1 and reset ignores + startCurly = -1 + startCurlyIgnore = []int{} + endCurly = -1 + endCurlyIgnore = []int{} + i = -1 // Reset back to the start of the string + continue + } + + // Couldnt find anything - mark curly brackets to skip and rerun + startCurlyIgnore = append(startCurlyIgnore, startCurly) + endCurlyIgnore = append(endCurlyIgnore, endCurly) + + // Reset the curly index back to -1 + startCurly = -1 + endCurly = -1 + i = -1 // Reset back to the start of the string + continue + } + + return dataVal, nil +} + +// FixedWidthOptions defines values needed for csv generation +type FixedWidthOptions struct { + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` + Fields []Field `json:"fields" xml:"fields" fake:"{fields}"` +} + +// FixedWidth generates an table of random data in fixed width format +// A nil FixedWidthOptions returns a randomly structured FixedWidth. +func FixedWidth(co *FixedWidthOptions) (string, error) { return fixeWidthFunc(GlobalFaker, co) } + +// FixedWidth generates an table of random data in fixed width format +// A nil FixedWidthOptions returns a randomly structured FixedWidth. +func (f *Faker) FixedWidth(co *FixedWidthOptions) (string, error) { return fixeWidthFunc(f, co) } + +// Function to generate a fixed width document +func fixeWidthFunc(f *Faker, co *FixedWidthOptions) (string, error) { + // If we didn't get FixedWidthOptions, create a new random one + if co == nil { + co = &FixedWidthOptions{} + } + + // Make sure you set a row count + if co.RowCount <= 0 { + co.RowCount = f.IntN(10) + 1 + } + + // Check fields + if len(co.Fields) <= 0 { + // Create random fields + co.Fields = []Field{ + {Name: "Name", Function: "{firstname} {lastname}"}, + {Name: "Email", Function: "email"}, + {Name: "Password", Function: "password", Params: MapParams{"special": {"false"}, "space": {"false"}}}, + } + } + + data := [][]string{} + hasHeader := false + + // Loop through fields, generate data and add to data array + for _, field := range co.Fields { + // Start new row + row := []string{} + + // Add name to first value + if field.Name != "" { + hasHeader = true + } + row = append(row, field.Name) + + // Get function + funcInfo := GetFuncLookup(field.Function) + var value any + if funcInfo == nil { + // Try to run the function through generate + for i := 0; i < co.RowCount; i++ { + genStr, err := generate(f, field.Function) + if err != nil { + return "", err + } + + row = append(row, genStr) + } + } else { + // Generate function value + var err error + for i := 0; i < co.RowCount; i++ { + value, err = funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return "", err + } + + // Add value to row + row = append(row, anyToString(value)) + } + } + + // Add row to data + data = append(data, row) + } + + var result strings.Builder + + // Calculate column widths + colWidths := make([]int, len(data)) + for i, row := range data { + for _, value := range row { + width := len(value) + 5 + if width > colWidths[i] { + colWidths[i] = width + } + } + } + + // Append table rows to the string, excluding the entire row if the first value is empty + for i := 0; i < len(data[0]); i++ { + if !hasHeader && i == 0 { + continue // Skip the entire column if the first value is empty + } + + var resultRow strings.Builder + for j, row := range data { + resultRow.WriteString(fmt.Sprintf("%-*s", colWidths[j], row[i])) + } + + // Trim trailing spaces + result.WriteString(strings.TrimRight(resultRow.String(), " ")) + + // Only add new line if not the last row + if i != len(data[0])-1 { + result.WriteString("\n") + } + } + + return result.String(), nil +} + +// Regex will generate a string based upon a RE2 syntax +func Regex(regexStr string) string { return regex(GlobalFaker, regexStr) } + +// Regex will generate a string based upon a RE2 syntax +func (f *Faker) Regex(regexStr string) string { return regex(f, regexStr) } + +func regex(f *Faker, regexStr string) (gen string) { + re, err := syntax.Parse(regexStr, syntax.Perl) + if err != nil { + return "Could not parse regex string" + } + + // Panic catch + defer func() { + if r := recover(); r != nil { + gen = fmt.Sprint(f) + return + + } + }() + + return regexGenerate(f, re, len(regexStr)*100) +} + +func regexGenerate(f *Faker, re *syntax.Regexp, limit int) string { + if limit <= 0 { + panic("Length limit reached when generating output") + } + + op := re.Op + switch op { + case syntax.OpNoMatch: // matches no strings + // Do Nothing + case syntax.OpEmptyMatch: // matches empty string + return "" + case syntax.OpLiteral: // matches Runes sequence + var b strings.Builder + for _, ru := range re.Rune { + b.WriteRune(ru) + } + return b.String() + case syntax.OpCharClass: // matches Runes interpreted as range pair list + // number of possible chars + sum := 0 + for i := 0; i < len(re.Rune); i += 2 { + sum += int(re.Rune[i+1]-re.Rune[i]) + 1 + if re.Rune[i+1] == 0x10ffff { // rune range end + sum = -1 + break + } + } + + // pick random char in range (inverse match group) + if sum == -1 { + chars := []uint8{} + for j := 0; j < len(allStr); j++ { + c := allStr[j] + + // Check c in range + for i := 0; i < len(re.Rune); i += 2 { + if rune(c) >= re.Rune[i] && rune(c) <= re.Rune[i+1] { + chars = append(chars, c) + break + } + } + } + if len(chars) > 0 { + return string([]byte{chars[f.IntN(len(chars))]}) + } + } + + r := f.IntN(int(sum)) + var ru rune + sum = 0 + for i := 0; i < len(re.Rune); i += 2 { + gap := int(re.Rune[i+1]-re.Rune[i]) + 1 + if sum+gap > r { + ru = re.Rune[i] + rune(r-sum) + break + } + sum += gap + } + + return string(ru) + case syntax.OpAnyCharNotNL, syntax.OpAnyChar: // matches any character(and except newline) + return randCharacter(f, allStr) + case syntax.OpBeginLine: // matches empty string at beginning of line + case syntax.OpEndLine: // matches empty string at end of line + case syntax.OpBeginText: // matches empty string at beginning of text + case syntax.OpEndText: // matches empty string at end of text + case syntax.OpWordBoundary: // matches word boundary `\b` + case syntax.OpNoWordBoundary: // matches word non-boundary `\B` + case syntax.OpCapture: // capturing subexpression with index Cap, optional name Name + return regexGenerate(f, re.Sub0[0], limit) + case syntax.OpStar: // matches Sub[0] zero or more times + var b strings.Builder + for i := 0; i < number(f, 0, 10); i++ { + for _, rs := range re.Sub { + b.WriteString(regexGenerate(f, rs, limit-b.Len())) + } + } + return b.String() + case syntax.OpPlus: // matches Sub[0] one or more times + var b strings.Builder + for i := 0; i < number(f, 1, 10); i++ { + for _, rs := range re.Sub { + b.WriteString(regexGenerate(f, rs, limit-b.Len())) + } + } + return b.String() + case syntax.OpQuest: // matches Sub[0] zero or one times + var b strings.Builder + for i := 0; i < number(f, 0, 1); i++ { + for _, rs := range re.Sub { + b.WriteString(regexGenerate(f, rs, limit-b.Len())) + } + } + return b.String() + case syntax.OpRepeat: // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit) + var b strings.Builder + count := 0 + re.Max = int(math.Min(float64(re.Max), float64(10))) + if re.Max > re.Min { + count = f.IntN(re.Max - re.Min + 1) + } + for i := 0; i < re.Min || i < (re.Min+count); i++ { + for _, rs := range re.Sub { + b.WriteString(regexGenerate(f, rs, limit-b.Len())) + } + } + return b.String() + case syntax.OpConcat: // matches concatenation of Subs + var b strings.Builder + for _, rs := range re.Sub { + b.WriteString(regexGenerate(f, rs, limit-b.Len())) + } + return b.String() + case syntax.OpAlternate: // matches alternation of Subs + return regexGenerate(f, re.Sub[number(f, 0, len(re.Sub)-1)], limit) + } + + return "" +} + +// Map will generate a random set of map data +func Map() map[string]any { return mapFunc(GlobalFaker) } + +// Map will generate a random set of map data +func (f *Faker) Map() map[string]any { return mapFunc(f) } + +func mapFunc(f *Faker) map[string]any { + m := map[string]any{} + + randWordType := func() string { + s := randomString(f, []string{"lorem", "bs", "job", "name", "address"}) + switch s { + case "bs": + return bs(f) + case "job": + return jobTitle(f) + case "name": + return name(f) + case "address": + return street(f) + ", " + city(f) + ", " + state(f) + " " + zip(f) + } + return word(f) + } + + randSlice := func() []string { + var sl []string + for ii := 0; ii < number(f, 3, 10); ii++ { + sl = append(sl, word(f)) + } + return sl + } + + for i := 0; i < number(f, 3, 10); i++ { + t := randomString(f, []string{"string", "int", "float", "slice", "map"}) + switch t { + case "string": + m[word(f)] = randWordType() + case "int": + m[word(f)] = number(f, 1, 10000000) + case "float": + m[word(f)] = float32Range(f, 1, 1000000) + case "slice": + m[word(f)] = randSlice() + case "map": + mm := map[string]any{} + tt := randomString(f, []string{"string", "int", "float", "slice"}) + switch tt { + case "string": + mm[word(f)] = randWordType() + case "int": + mm[word(f)] = number(f, 1, 10000000) + case "float": + mm[word(f)] = float32Range(f, 1, 1000000) + case "slice": + mm[word(f)] = randSlice() + } + m[word(f)] = mm + } + } + + return m +} + +func addGenerateLookup() { + AddFuncLookup("generate", Info{ + Display: "Generate", + Category: "generate", + Description: "Random string generated from string value based upon available data sets", + Example: "{firstname} {lastname} {email} - Markus Moen markusmoen@pagac.net", + Output: "string", + Params: []Param{ + {Field: "str", Display: "String", Type: "string", Description: "String value to generate from"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + str, err := info.GetString(m, "str") + if err != nil { + return nil, err + } + + // Limit the length of the string passed + if len(str) > 1000 { + return nil, errors.New("string length is too large. limit to 1000 characters") + } + + return generate(f, str) + }, + }) + + AddFuncLookup("fixed_width", Info{ + Display: "Fixed Width", + Category: "generate", + Description: "Fixed width rows of output data based on input fields", + Example: `Name Email Password Age +Markus Moen sylvanmraz@murphy.net 6VlvH6qqXc7g 13 +Alayna Wuckert santinostanton@carroll.biz g7sLrS0gEwLO 46 +Lura Lockman zacherykuhic@feil.name S8gV7Z64KlHG 12`, + Output: "[]byte", + ContentType: "text/plain", + Params: []Param{ + {Field: "rowcount", Display: "Row Count", Type: "int", Default: "10", Description: "Number of rows"}, + {Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields name, function and params"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + co := FixedWidthOptions{} + + rowCount, err := info.GetInt(m, "rowcount") + if err != nil { + return nil, err + } + + co.RowCount = rowCount + + fields, _ := info.GetStringArray(m, "fields") + + // Check to make sure fields has length + if len(fields) > 0 { + co.Fields = make([]Field, len(fields)) + for i, f := range fields { + // Unmarshal fields string into fields array + err = json.Unmarshal([]byte(f), &co.Fields[i]) + if err != nil { + return nil, err + } + } + } else { + return nil, errors.New("missing fields") + } + + out, err := fixeWidthFunc(f, &co) + if err != nil { + return nil, err + } + + return out, nil + }, + }) + + AddFuncLookup("regex", Info{ + Display: "Regex", + Category: "generate", + Description: "Pattern-matching tool used in text processing to search and manipulate strings", + Example: "[abcdef]{5} - affec", + Output: "string", + Params: []Param{ + {Field: "str", Display: "String", Type: "string", Description: "Regex RE2 syntax string"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + str, err := info.GetString(m, "str") + if err != nil { + return nil, err + } + + // Limit the length of the string passed + if len(str) > 500 { + return nil, errors.New("string length is too large. limit to 500 characters") + } + + return regex(f, str), nil + }, + }) + + AddFuncLookup("map", Info{ + Display: "Map", + Category: "generate", + Description: "Data structure that stores key-value pairs", + Example: `{ + "software": 7518355, + "that": ["despite", "pack", "whereas", "recently", "there", "anyone", "time", "read"], + "use": 683598, + "whom": "innovate", + "yourselves": 1987784 +}`, + Output: "map[string]any", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return mapFunc(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/hacker.go b/vendor/github.com/brianvoe/gofakeit/v7/hacker.go new file mode 100644 index 0000000000..22a78eb8e5 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/hacker.go @@ -0,0 +1,137 @@ +package gofakeit + +import ( + "strings" +) + +// HackerPhrase will return a random hacker sentence +func HackerPhrase() string { return hackerPhrase(GlobalFaker) } + +// HackerPhrase will return a random hacker sentence +func (f *Faker) HackerPhrase() string { return hackerPhrase(f) } + +func hackerPhrase(f *Faker) string { + genStr, _ := generate(f, getRandValue(f, []string{"hacker", "phrase"})) + + words := strings.Split(genStr, " ") + words[0] = strings.ToUpper(words[0][0:1]) + words[0][1:] + return strings.Join(words, " ") +} + +// HackerAbbreviation will return a random hacker abbreviation +func HackerAbbreviation() string { return hackerAbbreviation(GlobalFaker) } + +// HackerAbbreviation will return a random hacker abbreviation +func (f *Faker) HackerAbbreviation() string { return hackerAbbreviation(f) } + +func hackerAbbreviation(f *Faker) string { + return getRandValue(f, []string{"hacker", "abbreviation"}) +} + +// HackerAdjective will return a random hacker adjective +func HackerAdjective() string { return hackerAdjective(GlobalFaker) } + +// HackerAdjective will return a random hacker adjective +func (f *Faker) HackerAdjective() string { return hackerAdjective(f) } + +func hackerAdjective(f *Faker) string { + return getRandValue(f, []string{"hacker", "adjective"}) +} + +// HackerNoun will return a random hacker noun +func HackerNoun() string { return hackerNoun(GlobalFaker) } + +// HackerNoun will return a random hacker noun +func (f *Faker) HackerNoun() string { return hackerNoun(f) } + +func hackerNoun(f *Faker) string { + return getRandValue(f, []string{"hacker", "noun"}) +} + +// HackerVerb will return a random hacker verb +func HackerVerb() string { return hackerVerb(GlobalFaker) } + +// HackerVerb will return a random hacker verb +func (f *Faker) HackerVerb() string { return hackerVerb(f) } + +func hackerVerb(f *Faker) string { + return getRandValue(f, []string{"hacker", "verb"}) +} + +// HackeringVerb will return a random hacker ingverb +func HackeringVerb() string { return hackeringVerb(GlobalFaker) } + +// HackeringVerb will return a random hacker ingverb +func (f *Faker) HackeringVerb() string { return hackeringVerb(f) } + +func hackeringVerb(f *Faker) string { + return getRandValue(f, []string{"hacker", "ingverb"}) +} + +func addHackerLookup() { + AddFuncLookup("hackerphrase", Info{ + Display: "Hacker Phrase", + Category: "hacker", + Description: "Informal jargon and slang used in the hacking and cybersecurity community", + Example: "If we calculate the program, we can get to the AI pixel through the redundant XSS matrix!", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hackerPhrase(f), nil + }, + }) + + AddFuncLookup("hackerabbreviation", Info{ + Display: "Hacker Abbreviation", + Category: "hacker", + Description: "Abbreviations and acronyms commonly used in the hacking and cybersecurity community", + Example: "ADP", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hackerAbbreviation(f), nil + }, + }) + + AddFuncLookup("hackeradjective", Info{ + Display: "Hacker Adjective", + Category: "hacker", + Description: "Adjectives describing terms often associated with hackers and cybersecurity experts", + Example: "wireless", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hackerAdjective(f), nil + }, + }) + + AddFuncLookup("hackernoun", Info{ + Display: "Hacker Noun", + Category: "hacker", + Description: "Noun representing an element, tool, or concept within the realm of hacking and cybersecurity", + Example: "driver", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hackerNoun(f), nil + }, + }) + + AddFuncLookup("hackerverb", Info{ + Display: "Hacker Verb", + Category: "hacker", + Description: "Verbs associated with actions and activities in the field of hacking and cybersecurity", + Example: "synthesize", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hackerVerb(f), nil + }, + }) + + AddFuncLookup("hackeringverb", Info{ + Display: "Hackering Verb", + Category: "hacker", + Description: "Verb describing actions and activities related to hacking, often involving computer systems and security", + Example: "connecting", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hackeringVerb(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/helpers.go b/vendor/github.com/brianvoe/gofakeit/v7/helpers.go new file mode 100644 index 0000000000..6773e39f26 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/helpers.go @@ -0,0 +1,374 @@ +package gofakeit + +import ( + "encoding/json" + "fmt" + "math" + "reflect" + "strings" + "unicode" + + "github.com/brianvoe/gofakeit/v7/data" +) + +const lowerStr = "abcdefghijklmnopqrstuvwxyz" +const upperStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +const numericStr = "0123456789" +const specialStr = "@#$%&?|!(){}<>=*+-_:;,." +const specialSafeStr = "!@.-_*" // https://github.com/1Password/spg/pull/22 +const spaceStr = " " +const allStr = lowerStr + upperStr + numericStr + specialStr + spaceStr +const vowels = "aeiou" +const hashtag = '#' +const questionmark = '?' +const dash = '-' +const base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" +const minUint = 0 +const maxUint = ^uint(0) +const minInt = -maxInt - 1 +const maxInt = int(^uint(0) >> 1) +const is32bit = ^uint(0)>>32 == 0 + +// Check if in lib +func dataCheck(dataVal []string) bool { + var checkOk bool + + if len(dataVal) == 2 { + _, checkOk = data.Data[dataVal[0]] + if checkOk { + _, checkOk = data.Data[dataVal[0]][dataVal[1]] + } + } + + return checkOk +} + +// Get Random Value +func getRandValue(f *Faker, dataVal []string) string { + if !dataCheck(dataVal) { + return "" + } + return data.Data[dataVal[0]][dataVal[1]][f.IntN(len(data.Data[dataVal[0]][dataVal[1]]))] +} + +// Replace # with numbers +func replaceWithNumbers(f *Faker, str string) string { + if str == "" { + return str + } + bytestr := []byte(str) + for i := 0; i < len(bytestr); i++ { + if bytestr[i] == hashtag { + bytestr[i] = byte(randDigit(f)) + } + } + if bytestr[0] == '0' { + bytestr[0] = byte(f.IntN(8)+1) + '0' + } + + return string(bytestr) +} + +// Replace ? with ASCII lowercase letters +func replaceWithLetters(f *Faker, str string) string { + if str == "" { + return str + } + bytestr := []byte(str) + for i := 0; i < len(bytestr); i++ { + if bytestr[i] == questionmark { + bytestr[i] = byte(randLetter(f)) + } + } + + return string(bytestr) +} + +// Replace ? with ASCII lowercase letters between a and f +func replaceWithHexLetters(f *Faker, str string) string { + if str == "" { + return str + } + bytestr := []byte(str) + for i := 0; i < len(bytestr); i++ { + if bytestr[i] == questionmark { + bytestr[i] = byte(randHexLetter(f)) + } + } + + return string(bytestr) +} + +// Generate random lowercase ASCII letter +func randLetter(f *Faker) rune { + allLetters := upperStr + lowerStr + return rune(allLetters[f.IntN(len(allLetters))]) +} + +func randCharacter(f *Faker, s string) string { + return string(s[f.Int64()%int64(len(s))]) +} + +// Generate random lowercase ASCII letter between a and f +func randHexLetter(f *Faker) rune { + return rune(byte(f.IntN(6)) + 'a') +} + +// Generate random ASCII digit +func randDigit(f *Faker) rune { + return rune(byte(f.IntN(10)) + '0') +} + +// Generate random integer between min and max +func randIntRange(f *Faker, min, max int) int { + if min == max { + return min + } + + if min > max { + min, max = max, min // Swap if min is greater than max + } + + // Use f.IntN to generate a random number in [0, rangeSize) and shift it into [min, max]. + return f.IntN(max-min+1) + min +} + +// Generate random uint between min and max +func randUintRange(f *Faker, min, max uint) uint { + if min == max { + return min // Immediate return if range is zero + } + + if min > max { + min, max = max, min // Swap if min is greater than max + } + + // Use f.UintN to generate a random number in [0, rangeSize) and shift it into [min, max]. + return f.UintN(max-min+1) + min +} + +func toFixed(num float64, precision int) float64 { + output := math.Pow(10, float64(precision)) + return float64(math.Floor(num*output)) / output +} + +func equalSliceString(a, b []string) bool { + sizeA, sizeB := len(a), len(b) + if sizeA != sizeB { + return false + } + + for i, va := range a { + vb := b[i] + + if va != vb { + return false + } + } + return true +} + +func equalSliceInt(a, b []int) bool { + sizeA, sizeB := len(a), len(b) + if sizeA != sizeB { + return false + } + + for i, va := range a { + vb := b[i] + + if va != vb { + return false + } + } + return true +} + +func equalSliceInterface(a, b []any) bool { + sizeA, sizeB := len(a), len(b) + if sizeA != sizeB { + return false + } + + for i, va := range a { + if !reflect.DeepEqual(va, b[i]) { + return false + } + } + return true +} + +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} + +func anyToString(a any) string { + if a == nil { + return "" + } + + // If it's a slice of bytes or struct, unmarshal it into an interface + if bytes, ok := a.([]byte); ok { + return string(bytes) + } + + // If it's a struct, map, or slice, convert to JSON + switch reflect.TypeOf(a).Kind() { + case reflect.Struct, reflect.Map, reflect.Slice: + b, err := json.Marshal(a) + if err == nil { + return string(b) + } + } + + return fmt.Sprintf("%v", a) +} + +// Title returns a copy of the string s with all Unicode letters that begin words +// mapped to their Unicode title case +func title(s string) string { + // isSeparator reports whether the rune could mark a word boundary + isSeparator := func(r rune) bool { + // ASCII alphanumerics and underscore are not separators + if r <= 0x7F { + switch { + case '0' <= r && r <= '9': + return false + case 'a' <= r && r <= 'z': + return false + case 'A' <= r && r <= 'Z': + return false + case r == '_': + return false + } + return true + } + + // Letters and digits are not separators + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return false + } + + // Otherwise, all we can do for now is treat spaces as separators. + return unicode.IsSpace(r) + } + + prev := ' ' + return strings.Map( + func(r rune) rune { + if isSeparator(prev) { + prev = r + return unicode.ToTitle(r) + } + prev = r + return r + }, + s) +} + +func funcLookupSplit(str string) ([]string, error) { + out := []string{} + for str != "" { + if strings.HasPrefix(str, "[") { + startIndex := strings.Index(str, "[") + endIndex := strings.Index(str, "]") + if endIndex == -1 { + return nil, fmt.Errorf("invalid lookup split missing ending ] bracket") + } + + val := str[(startIndex) : endIndex+1] + out = append(out, strings.TrimSpace(val)) + str = strings.Replace(str, val, "", 1) + + // Trim off comma if it has it + if strings.HasPrefix(str, ",") { + str = strings.Replace(str, ",", "", 1) + } + } else { + strSplit := strings.SplitN(str, ",", 2) + strSplitLen := len(strSplit) + if strSplitLen >= 1 { + out = append(out, strings.TrimSpace(strSplit[0])) + } + if strSplitLen >= 2 { + str = strSplit[1] + } else { + str = "" + } + } + } + + return out, nil +} + +// Used for parsing the tag in a struct +func parseNameAndParamsFromTag(tag string) (string, string) { + // Trim the curly on the beginning and end + tag = strings.TrimLeft(tag, "{") + tag = strings.TrimRight(tag, "}") + // Check if has params separated by : + fNameSplit := strings.SplitN(tag, ":", 2) + fName := "" + fParams := "" + if len(fNameSplit) >= 1 { + fName = fNameSplit[0] + } + if len(fNameSplit) >= 2 { + fParams = fNameSplit[1] + } + return fName, fParams +} + +// Used for parsing map params +func parseMapParams(info *Info, fParams string) (*MapParams, error) { + // Get parameters, make sure params and the split both have values + mapParams := NewMapParams() + paramsLen := len(info.Params) + + // If just one param and its a string simply just pass it + if paramsLen == 1 && info.Params[0].Type == "string" { + mapParams.Add(info.Params[0].Field, fParams) + } else if paramsLen > 0 && fParams != "" { + splitVals, err := funcLookupSplit(fParams) + if err != nil { + return nil, err + } + mapParams, err = addSplitValsToMapParams(splitVals, info, mapParams) + if err != nil { + return nil, err + } + } + + // If mapParams doesnt have a size then return nil + if mapParams.Size() == 0 { + return nil, nil + } + + return mapParams, nil +} + +// Used for splitting the values +func addSplitValsToMapParams(splitVals []string, info *Info, mapParams *MapParams) (*MapParams, error) { + for ii := 0; ii < len(splitVals); ii++ { + if len(info.Params)-1 >= ii { + if strings.HasPrefix(splitVals[ii], "[") { + lookupSplits, err := funcLookupSplit(strings.TrimRight(strings.TrimLeft(splitVals[ii], "["), "]")) + if err != nil { + return nil, err + } + + for _, v := range lookupSplits { + mapParams.Add(info.Params[ii].Field, v) + } + } else { + mapParams.Add(info.Params[ii].Field, splitVals[ii]) + } + } + } + return mapParams, nil +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/hipster.go b/vendor/github.com/brianvoe/gofakeit/v7/hipster.go new file mode 100644 index 0000000000..8cf7cba9d8 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/hipster.go @@ -0,0 +1,130 @@ +package gofakeit + +import ( + "errors" +) + +// HipsterWord will return a single hipster word +func HipsterWord() string { return hipsterWord(GlobalFaker) } + +// HipsterWord will return a single hipster word +func (f *Faker) HipsterWord() string { return hipsterWord(f) } + +func hipsterWord(f *Faker) string { return getRandValue(f, []string{"hipster", "word"}) } + +// HipsterSentence will generate a random sentence +func HipsterSentence(wordCount int) string { return hipsterSentence(GlobalFaker, wordCount) } + +// HipsterSentence will generate a random sentence +func (f *Faker) HipsterSentence(wordCount int) string { return hipsterSentence(f, wordCount) } + +func hipsterSentence(f *Faker, wordCount int) string { + return sentenceGen(f, wordCount, hipsterWord) +} + +// HipsterParagraph will generate a random paragraphGenerator +// Set Paragraph Count +// Set Sentence Count +// Set Word Count +// Set Paragraph Separator +func HipsterParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return hipsterParagraph(GlobalFaker, paragraphCount, sentenceCount, wordCount, separator) +} + +// HipsterParagraph will generate a random paragraphGenerator +// Set Paragraph Count +// Set Sentence Count +// Set Word Count +// Set Paragraph Separator +func (f *Faker) HipsterParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return hipsterParagraph(f, paragraphCount, sentenceCount, wordCount, separator) +} + +func hipsterParagraph(f *Faker, paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return paragraphGen(f, paragrapOptions{paragraphCount, sentenceCount, wordCount, separator}, hipsterSentence) +} + +func addHipsterLookup() { + AddFuncLookup("hipsterword", Info{ + Display: "Hipster Word", + Category: "hipster", + Description: "Trendy and unconventional vocabulary used by hipsters to express unique cultural preferences", + Example: "microdosing", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hipsterWord(f), nil + }, + }) + + AddFuncLookup("hipstersentence", Info{ + Display: "Hipster Sentence", + Category: "hipster", + Description: "Sentence showcasing the use of trendy and unconventional vocabulary associated with hipster culture", + Example: "Microdosing roof chia echo pickled.", + Output: "string", + Params: []Param{ + {Field: "wordcount", Display: "Word Count", Type: "int", Default: "5", Description: "Number of words in a sentence"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + wordCount, err := info.GetInt(m, "wordcount") + if err != nil { + return nil, err + } + if wordCount <= 0 || wordCount > 50 { + return nil, errors.New("invalid word count, must be greater than 0, less than 50") + } + + return hipsterSentence(f, wordCount), nil + }, + }) + + AddFuncLookup("hipsterparagraph", Info{ + Display: "Hipster Paragraph", + Category: "hipster", + Description: "Paragraph showcasing the use of trendy and unconventional vocabulary associated with hipster culture", + Example: `Microdosing roof chia echo pickled meditation cold-pressed raw denim fingerstache normcore sriracha pork belly. Wolf try-hard pop-up blog tilde hashtag health butcher waistcoat paleo portland vinegar. Microdosing sartorial blue bottle slow-carb freegan five dollar toast you probably haven't heard of them asymmetrical chia farm-to-table narwhal banjo. Gluten-free blog authentic literally synth vinyl meh ethical health fixie banh mi Yuccie. Try-hard drinking squid seitan cray VHS echo chillwave hammock kombucha food truck sustainable. + +Pug bushwick hella tote bag cliche direct trade waistcoat yr waistcoat knausgaard pour-over master. Pitchfork jean shorts franzen flexitarian distillery hella meggings austin knausgaard crucifix wolf heirloom. Crucifix food truck you probably haven't heard of them trust fund fixie gentrify pitchfork stumptown mlkshk umami chambray blue bottle. 3 wolf moon swag +1 biodiesel knausgaard semiotics taxidermy meh artisan hoodie +1 blue bottle. Fashion axe forage mixtape Thundercats pork belly whatever 90's beard selfies chambray cred mlkshk. + +Shabby chic typewriter VHS readymade lo-fi bitters PBR&B gentrify lomo raw denim freegan put a bird on it. Raw denim cliche dreamcatcher pug fixie park trust fund migas fingerstache sriracha +1 mustache. Tilde shoreditch kickstarter franzen dreamcatcher green juice mustache neutra polaroid stumptown organic schlitz. Flexitarian ramps chicharrones kogi lo-fi mustache tilde forage street church-key williamsburg taxidermy. Chia mustache plaid mumblecore squid slow-carb disrupt Thundercats goth shoreditch master direct trade.`, + Output: "string", + Params: []Param{ + {Field: "paragraphcount", Display: "Paragraph Count", Type: "int", Default: "2", Description: "Number of paragraphs"}, + {Field: "sentencecount", Display: "Sentence Count", Type: "int", Default: "2", Description: "Number of sentences in a paragraph"}, + {Field: "wordcount", Display: "Word Count", Type: "int", Default: "5", Description: "Number of words in a sentence"}, + {Field: "paragraphseparator", Display: "Paragraph Separator", Type: "string", Default: "
", Description: "String value to add between paragraphs"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + paragraphCount, err := info.GetInt(m, "paragraphcount") + if err != nil { + return nil, err + } + if paragraphCount <= 0 || paragraphCount > 20 { + return nil, errors.New("invalid paragraph count, must be greater than 0, less than 20") + } + + sentenceCount, err := info.GetInt(m, "sentencecount") + if err != nil { + return nil, err + } + if sentenceCount <= 0 || sentenceCount > 20 { + return nil, errors.New("invalid sentence count, must be greater than 0, less than 20") + } + + wordCount, err := info.GetInt(m, "wordcount") + if err != nil { + return nil, err + } + if wordCount <= 0 || wordCount > 50 { + return nil, errors.New("invalid word count, must be greater than 0, less than 50") + } + + paragraphSeparator, err := info.GetString(m, "paragraphseparator") + if err != nil { + return nil, err + } + + return hipsterParagraph(f, paragraphCount, sentenceCount, wordCount, paragraphSeparator), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/html.go b/vendor/github.com/brianvoe/gofakeit/v7/html.go new file mode 100644 index 0000000000..27385ecddf --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/html.go @@ -0,0 +1,174 @@ +package gofakeit + +import ( + "errors" + "strconv" + "strings" + + "github.com/brianvoe/gofakeit/v7/data" +) + +// InputName will return a random input field name +func InputName() string { + return inputName(GlobalFaker) +} + +// InputName will return a random input field name +func (f *Faker) InputName() string { + return inputName(f) +} + +func inputName(f *Faker) string { + return getRandValue(f, []string{"html", "input_name"}) +} + +type SVGOptions struct { + Height int + Width int + Type string + Colors []string +} + +// Generate a random svg generator +func Svg(options *SVGOptions) string { return svg(GlobalFaker, options) } + +// Generate a random svg generator +func (f *Faker) Svg(options *SVGOptions) string { return svg(f, options) } + +func svg(f *Faker, options *SVGOptions) string { + // If options is nil, set it to empty struct + if options == nil { + options = &SVGOptions{} + } + + // If options height and weight is not set, set it to random number between 100 and 500 + if options.Width == 0 { + options.Width = number(f, 100, 500) + } + widthStr := strconv.Itoa(options.Width) + if options.Height == 0 { + options.Height = number(f, 100, 500) + } + heightStr := strconv.Itoa(options.Height) + + // Check if type is set, if not set to random type + if options.Type == "" { + options.Type = randomString(f, data.GetSubData("html", "svg")) + } + + // If the colors are not set, set it to a set of nice colors + if len(options.Colors) == 0 { + options.Colors = niceColors(f) + } + + // Start svg string + svgStr := `` + + // Add a rect for the background + svgStr += `` + + // Add a random number of shapes + for i := 0; i < number(f, 10, 20); i++ { + // Add a random shape + switch options.Type { + case "rect": + svgStr += `` + case "circle": + svgStr += `` + case "ellipse": + svgStr += `` + case "line": + svgStr += `` + case "polyline": + svgStr += `` + case "polygon": + svgStr += `` + } + } + + // End svg string + svgStr += `` + + return svgStr +} + +func addHtmlLookup() { + AddFuncLookup("inputname", Info{ + Display: "Input Name", + Category: "html", + Description: "Attribute used to define the name of an input element in web forms", + Example: "first_name", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return inputName(f), nil + }, + }) + + AddFuncLookup("svg", Info{ + Display: "Image SVG", + Category: "html", + Description: "Scalable Vector Graphics used to display vector images in web content", + Example: ` + + +`, + Output: "string", + ContentType: "image/svg+xml", + Params: []Param{ + {Field: "width", Display: "Width", Type: "int", Default: "500", Description: "Width in px"}, + {Field: "height", Display: "Height", Type: "int", Default: "500", Description: "Height in px"}, + {Field: "type", Display: "Type", Type: "string", Optional: true, Options: data.GetSubData("html", "svg"), Description: "Sub child element type"}, + {Field: "colors", Display: "Colors", Type: "[]string", Optional: true, Description: "Hex or RGB array of colors to use"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + // Setup new options + options := SVGOptions{} + var err error + + options.Width, err = info.GetInt(m, "width") + if err != nil { + return nil, err + } + if options.Width < 10 || options.Width >= 1000 { + return nil, errors.New("invalid image width, must be greater than 10, less than 1000") + } + + options.Height, err = info.GetInt(m, "height") + if err != nil { + return nil, err + } + if options.Height < 10 || options.Height >= 1000 { + return nil, errors.New("invalid image height, must be greater than 10, less than 1000") + } + + options.Type, err = info.GetString(m, "type") + svgData := data.GetSubData("html", "svg") + if err != nil { + return nil, err + } + + // If type is empty, set with random type + if options.Type == "" { + options.Type = randomString(f, svgData) + } + + // If not in date html svg type array, return error + if !stringInSlice(options.Type, svgData) { + return nil, errors.New("invalid svg type, must be one of " + strings.Join(svgData, ",")) + } + + // Get colors + options.Colors, err = info.GetStringArray(m, "colors") + if err != nil { + return nil, err + } + + // If colors is empty, set with random colors + if len(options.Colors) == 0 { + options.Colors = niceColors(f) + } + + return svg(f, &options), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/image.go b/vendor/github.com/brianvoe/gofakeit/v7/image.go new file mode 100644 index 0000000000..9a04bcd669 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/image.go @@ -0,0 +1,122 @@ +package gofakeit + +import ( + "bytes" + "errors" + img "image" + imgCol "image/color" + "image/jpeg" + "image/png" +) + +// Image generates a random rgba image +func Image(width int, height int) *img.RGBA { return image(GlobalFaker, width, height) } + +// Image generates a random rgba image +func (f *Faker) Image(width int, height int) *img.RGBA { return image(f, width, height) } + +func image(f *Faker, width int, height int) *img.RGBA { + upLeft := img.Point{0, 0} + lowRight := img.Point{width, height} + + img := img.NewRGBA(img.Rectangle{upLeft, lowRight}) + + // Set color for each pixel + for x := 0; x < width; x++ { + for y := 0; y < height; y++ { + img.Set(x, y, imgCol.RGBA{uint8(number(f, 0, 255)), uint8(number(f, 0, 255)), uint8(number(f, 0, 255)), 0xff}) + } + } + + return img +} + +// ImageJpeg generates a random rgba jpeg image +func ImageJpeg(width int, height int) []byte { return imageJpeg(GlobalFaker, width, height) } + +// ImageJpeg generates a random rgba jpeg image +func (f *Faker) ImageJpeg(width int, height int) []byte { return imageJpeg(f, width, height) } + +func imageJpeg(f *Faker, width int, height int) []byte { + buf := new(bytes.Buffer) + jpeg.Encode(buf, image(f, width, height), nil) + return buf.Bytes() +} + +// ImagePng generates a random rgba png image +func ImagePng(width int, height int) []byte { return imagePng(GlobalFaker, width, height) } + +// ImagePng generates a random rgba png image +func (f *Faker) ImagePng(width int, height int) []byte { return imagePng(f, width, height) } + +func imagePng(f *Faker, width int, height int) []byte { + buf := new(bytes.Buffer) + png.Encode(buf, image(f, width, height)) + return buf.Bytes() +} + +func addImageLookup() { + AddFuncLookup("imagejpeg", Info{ + Display: "Image JPEG", + Category: "image", + Description: "Image file format known for its efficient compression and compatibility", + Example: "file.jpeg - bytes", + Output: "[]byte", + ContentType: "image/jpeg", + Params: []Param{ + {Field: "width", Display: "Width", Type: "int", Default: "500", Description: "Image width in px"}, + {Field: "height", Display: "Height", Type: "int", Default: "500", Description: "Image height in px"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + width, err := info.GetInt(m, "width") + if err != nil { + return nil, err + } + if width < 10 || width >= 1000 { + return nil, errors.New("invalid image width, must be greater than 10, less than 1000") + } + + height, err := info.GetInt(m, "height") + if err != nil { + return nil, err + } + if height < 10 || height >= 1000 { + return nil, errors.New("invalid image height, must be greater than 10, less than 1000") + } + + return imageJpeg(f, width, height), nil + }, + }) + + AddFuncLookup("imagepng", Info{ + Display: "Image PNG", + Category: "image", + Description: "Image file format known for its lossless compression and support for transparency", + Example: "file.png - bytes", + Output: "[]byte", + ContentType: "image/png", + Params: []Param{ + {Field: "width", Display: "Width", Type: "int", Default: "500", Description: "Image width in px"}, + {Field: "height", Display: "Height", Type: "int", Default: "500", Description: "Image height in px"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + width, err := info.GetInt(m, "width") + if err != nil { + return nil, err + } + if width < 10 || width >= 1000 { + return nil, errors.New("invalid image width, must be greater than 10, less than 1000") + } + + height, err := info.GetInt(m, "height") + if err != nil { + return nil, err + } + if height < 10 || height >= 1000 { + return nil, errors.New("invalid image height, must be greater than 10, less than 1000") + } + + return imagePng(f, width, height), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/internet.go b/vendor/github.com/brianvoe/gofakeit/v7/internet.go new file mode 100644 index 0000000000..68cf858005 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/internet.go @@ -0,0 +1,440 @@ +package gofakeit + +import ( + "fmt" + "strconv" + "strings" + + "github.com/brianvoe/gofakeit/v7/data" +) + +// DomainName will generate a random url domain name +func DomainName() string { return domainName(GlobalFaker) } + +// DomainName will generate a random url domain name +func (f *Faker) DomainName() string { return domainName(f) } + +func domainName(f *Faker) string { + name := strings.Replace(strings.ToLower(jobDescriptor(f)+bs(f)), " ", "", -1) + + return fmt.Sprintf("%s.%s", name, domainSuffix(f)) +} + +// DomainSuffix will generate a random domain suffix +func DomainSuffix() string { return domainSuffix(GlobalFaker) } + +// DomainSuffix will generate a random domain suffix +func (f *Faker) DomainSuffix() string { return domainSuffix(f) } + +func domainSuffix(f *Faker) string { + return getRandValue(f, []string{"internet", "domain_suffix"}) +} + +// URL will generate a random url string +func URL() string { return url(GlobalFaker) } + +// URL will generate a random url string +func (f *Faker) URL() string { return url(f) } + +func url(f *Faker) string { + // Slugs + num := number(f, 1, 4) + slug := make([]string, num) + for i := 0; i < num; i++ { + slug[i] = bs(f) + } + + scheme := randomString(f, []string{"https", "http"}) + path := strings.ToLower(strings.Join(slug, "/")) + + url := fmt.Sprintf("%s://www.%s/%s", scheme, domainName(f), path) + url = strings.Replace(url, " ", "", -1) + + return url +} + +// HTTPMethod will generate a random http method +func HTTPMethod() string { return httpMethod(GlobalFaker) } + +// HTTPMethod will generate a random http method +func (f *Faker) HTTPMethod() string { return httpMethod(f) } + +func httpMethod(f *Faker) string { + return getRandValue(f, []string{"internet", "http_method"}) +} + +// IPv4Address will generate a random version 4 ip address +func IPv4Address() string { return ipv4Address(GlobalFaker) } + +// IPv4Address will generate a random version 4 ip address +func (f *Faker) IPv4Address() string { return ipv4Address(f) } + +func ipv4Address(f *Faker) string { + num := func() int { return f.IntN(256) } + + return fmt.Sprintf("%d.%d.%d.%d", num(), num(), num(), num()) +} + +// IPv6Address will generate a random version 6 ip address +func IPv6Address() string { return ipv6Address(GlobalFaker) } + +// IPv6Address will generate a random version 6 ip address +func (f *Faker) IPv6Address() string { return ipv6Address(f) } + +func ipv6Address(f *Faker) string { + num := func() int { return f.IntN(65536) } + + return fmt.Sprintf("%x:%x:%x:%x:%x:%x:%x:%x", num(), num(), num(), num(), num(), num(), num(), num()) +} + +// MacAddress will generate a random mac address +func MacAddress() string { return macAddress(GlobalFaker) } + +// MacAddress will generate a random mac address +func (f *Faker) MacAddress() string { return macAddress(f) } + +func macAddress(f *Faker) string { + num := 255 + + return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", f.IntN(num), f.IntN(num), f.IntN(num), f.IntN(num), f.IntN(num), f.IntN(num)) +} + +// HTTPStatusCode will generate a random status code +func HTTPStatusCode() int { return httpStatusCode(GlobalFaker) } + +// HTTPStatusCode will generate a random status code +func (f *Faker) HTTPStatusCode() int { return httpStatusCode(f) } + +func httpStatusCode(f *Faker) int { + randInt, _ := strconv.Atoi(getRandValue(f, []string{"internet", "http_status_general"})) + return randInt +} + +// HTTPStatusCodeSimple will generate a random simple status code +func HTTPStatusCodeSimple() int { return httpStatusCodeSimple(GlobalFaker) } + +// HTTPStatusCodeSimple will generate a random simple status code +func (f *Faker) HTTPStatusCodeSimple() int { return httpStatusCodeSimple(f) } + +func httpStatusCodeSimple(f *Faker) int { + randInt, _ := strconv.Atoi(getRandValue(f, []string{"internet", "http_status_simple"})) + return randInt +} + +// LogLevel will generate a random log level +// See data/LogLevels for list of available levels +func LogLevel(logType string) string { return logLevel(GlobalFaker, logType) } + +// LogLevel will generate a random log level +// See data/LogLevels for list of available levels +func (f *Faker) LogLevel(logType string) string { return logLevel(f, logType) } + +func logLevel(f *Faker, logType string) string { + if _, ok := data.LogLevels[logType]; ok { + return getRandValue(f, []string{"log_level", logType}) + } + + return getRandValue(f, []string{"log_level", "general"}) +} + +// UserAgent will generate a random broswer user agent +func UserAgent() string { return userAgent(GlobalFaker) } + +// UserAgent will generate a random broswer user agent +func (f *Faker) UserAgent() string { return userAgent(f) } + +func userAgent(f *Faker) string { + randNum := randIntRange(f, 0, 4) + switch randNum { + case 0: + return chromeUserAgent(f) + case 1: + return firefoxUserAgent(f) + case 2: + return safariUserAgent(f) + case 3: + return operaUserAgent(f) + default: + return chromeUserAgent(f) + } +} + +// ChromeUserAgent will generate a random chrome browser user agent string +func ChromeUserAgent() string { return chromeUserAgent(GlobalFaker) } + +// ChromeUserAgent will generate a random chrome browser user agent string +func (f *Faker) ChromeUserAgent() string { return chromeUserAgent(f) } + +func chromeUserAgent(f *Faker) string { + randNum1 := strconv.Itoa(randIntRange(f, 531, 536)) + strconv.Itoa(randIntRange(f, 0, 2)) + randNum2 := strconv.Itoa(randIntRange(f, 36, 40)) + randNum3 := strconv.Itoa(randIntRange(f, 800, 899)) + return "Mozilla/5.0 " + "(" + randomPlatform(f) + ") AppleWebKit/" + randNum1 + " (KHTML, like Gecko) Chrome/" + randNum2 + ".0." + randNum3 + ".0 Mobile Safari/" + randNum1 +} + +// FirefoxUserAgent will generate a random firefox broswer user agent string +func FirefoxUserAgent() string { return firefoxUserAgent(GlobalFaker) } + +// FirefoxUserAgent will generate a random firefox broswer user agent string +func (f *Faker) FirefoxUserAgent() string { return firefoxUserAgent(f) } + +func firefoxUserAgent(f *Faker) string { + ver := "Gecko/" + date(f).Format("2006-01-02") + " Firefox/" + strconv.Itoa(randIntRange(f, 35, 37)) + ".0" + platforms := []string{ + "(" + windowsPlatformToken(f) + "; " + "en-US" + "; rv:1.9." + strconv.Itoa(randIntRange(f, 0, 3)) + ".20) " + ver, + "(" + linuxPlatformToken(f) + "; rv:" + strconv.Itoa(randIntRange(f, 5, 8)) + ".0) " + ver, + "(" + macPlatformToken(f) + " rv:" + strconv.Itoa(randIntRange(f, 2, 7)) + ".0) " + ver, + } + + return "Mozilla/5.0 " + randomString(f, platforms) +} + +// SafariUserAgent will generate a random safari browser user agent string +func SafariUserAgent() string { return safariUserAgent(GlobalFaker) } + +// SafariUserAgent will generate a random safari browser user agent string +func (f *Faker) SafariUserAgent() string { return safariUserAgent(f) } + +func safariUserAgent(f *Faker) string { + randNum := strconv.Itoa(randIntRange(f, 531, 536)) + "." + strconv.Itoa(randIntRange(f, 1, 51)) + "." + strconv.Itoa(randIntRange(f, 1, 8)) + ver := strconv.Itoa(randIntRange(f, 4, 6)) + "." + strconv.Itoa(randIntRange(f, 0, 2)) + + mobileDevices := []string{ + "iPhone; CPU iPhone OS", + "iPad; CPU OS", + } + + platforms := []string{ + "(Windows; U; " + windowsPlatformToken(f) + ") AppleWebKit/" + randNum + " (KHTML, like Gecko) Version/" + ver + " Safari/" + randNum, + "(" + macPlatformToken(f) + " rv:" + strconv.Itoa(randIntRange(f, 4, 7)) + ".0; en-US) AppleWebKit/" + randNum + " (KHTML, like Gecko) Version/" + ver + " Safari/" + randNum, + "(" + randomString(f, mobileDevices) + " " + strconv.Itoa(randIntRange(f, 7, 9)) + "_" + strconv.Itoa(randIntRange(f, 0, 3)) + "_" + strconv.Itoa(randIntRange(f, 1, 3)) + " like Mac OS X; " + "en-US" + ") AppleWebKit/" + randNum + " (KHTML, like Gecko) Version/" + strconv.Itoa(randIntRange(f, 3, 5)) + ".0.5 Mobile/8B" + strconv.Itoa(randIntRange(f, 111, 120)) + " Safari/6" + randNum, + } + + return "Mozilla/5.0 " + randomString(f, platforms) +} + +// OperaUserAgent will generate a random opera browser user agent string +func OperaUserAgent() string { return operaUserAgent(GlobalFaker) } + +// OperaUserAgent will generate a random opera browser user agent string +func (f *Faker) OperaUserAgent() string { return operaUserAgent(f) } + +func operaUserAgent(f *Faker) string { + platform := "(" + randomPlatform(f) + "; en-US) Presto/2." + strconv.Itoa(randIntRange(f, 8, 13)) + "." + strconv.Itoa(randIntRange(f, 160, 355)) + " Version/" + strconv.Itoa(randIntRange(f, 10, 13)) + ".00" + + return "Opera/" + strconv.Itoa(randIntRange(f, 8, 10)) + "." + strconv.Itoa(randIntRange(f, 10, 99)) + " " + platform +} + +// linuxPlatformToken will generate a random linux platform +func linuxPlatformToken(f *Faker) string { + return "X11; Linux " + getRandValue(f, []string{"computer", "linux_processor"}) +} + +// macPlatformToken will generate a random mac platform +func macPlatformToken(f *Faker) string { + return "Macintosh; " + getRandValue(f, []string{"computer", "mac_processor"}) + " Mac OS X 10_" + strconv.Itoa(randIntRange(f, 5, 9)) + "_" + strconv.Itoa(randIntRange(f, 0, 10)) +} + +// windowsPlatformToken will generate a random windows platform +func windowsPlatformToken(f *Faker) string { + return getRandValue(f, []string{"computer", "windows_platform"}) +} + +// randomPlatform will generate a random platform +func randomPlatform(f *Faker) string { + platforms := []string{ + linuxPlatformToken(f), + macPlatformToken(f), + windowsPlatformToken(f), + } + + return randomString(f, platforms) +} + +// HTTPVersion will generate a random http version +func HTTPVersion() string { return httpVersion(GlobalFaker) } + +// HTTPVersion will generate a random http version +func (f *Faker) HTTPVersion() string { return httpVersion(f) } + +func httpVersion(f *Faker) string { + return getRandValue(f, []string{"internet", "http_version"}) +} + +func addInternetLookup() { + AddFuncLookup("url", Info{ + Display: "URL", + Category: "internet", + Description: "Web address that specifies the location of a resource on the internet", + Example: "http://www.principalproductize.biz/target", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return url(f), nil + }, + }) + + AddFuncLookup("domainname", Info{ + Display: "Domain Name", + Category: "internet", + Description: "Human-readable web address used to identify websites on the internet", + Example: "centraltarget.biz", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return domainName(f), nil + }, + }) + + AddFuncLookup("domainsuffix", Info{ + Display: "Domain Suffix", + Category: "internet", + Description: "The part of a domain name that comes after the last dot, indicating its type or purpose", + Example: "org", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return domainSuffix(f), nil + }, + }) + + AddFuncLookup("ipv4address", Info{ + Display: "IPv4 Address", + Category: "internet", + Description: "Numerical label assigned to devices on a network for identification and communication", + Example: "222.83.191.222", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return ipv4Address(f), nil + }, + }) + + AddFuncLookup("ipv6address", Info{ + Display: "IPv6 Address", + Category: "internet", + Description: "Numerical label assigned to devices on a network, providing a larger address space than IPv4 for internet communication", + Example: "2001:cafe:8898:ee17:bc35:9064:5866:d019", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return ipv6Address(f), nil + }, + }) + + AddFuncLookup("httpmethod", Info{ + Display: "HTTP Method", + Category: "internet", + Description: "Verb used in HTTP requests to specify the desired action to be performed on a resource", + Example: "HEAD", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return httpMethod(f), nil + }, + }) + + AddFuncLookup("loglevel", Info{ + Display: "Log Level", + Category: "internet", + Description: "Classification used in logging to indicate the severity or priority of a log entry", + Example: "error", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return logLevel(f, ""), nil + }, + }) + + AddFuncLookup("useragent", Info{ + Display: "User Agent", + Category: "internet", + Description: "String sent by a web browser to identify itself when requesting web content", + Example: "Mozilla/5.0 (Windows NT 5.0) AppleWebKit/5362 (KHTML, like Gecko) Chrome/37.0.834.0 Mobile Safari/5362", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return userAgent(f), nil + }, + }) + + AddFuncLookup("chromeuseragent", Info{ + Display: "Chrome User Agent", + Category: "internet", + Description: "The specific identification string sent by the Google Chrome web browser when making requests on the internet", + Example: "Mozilla/5.0 (X11; Linux i686) AppleWebKit/5312 (KHTML, like Gecko) Chrome/39.0.836.0 Mobile Safari/5312", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return chromeUserAgent(f), nil + }, + }) + + AddFuncLookup("firefoxuseragent", Info{ + Display: "Firefox User Agent", + Category: "internet", + Description: "The specific identification string sent by the Firefox web browser when making requests on the internet", + Example: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_8_3 rv:7.0) Gecko/1900-07-01 Firefox/37.0", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return firefoxUserAgent(f), nil + }, + }) + + AddFuncLookup("operauseragent", Info{ + Display: "Opera User Agent", + Category: "internet", + Description: "The specific identification string sent by the Opera web browser when making requests on the internet", + Example: "Opera/8.39 (Macintosh; U; PPC Mac OS X 10_8_7; en-US) Presto/2.9.335 Version/10.00", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return operaUserAgent(f), nil + }, + }) + + AddFuncLookup("safariuseragent", Info{ + Display: "Safari User Agent", + Category: "internet", + Description: "The specific identification string sent by the Safari web browser when making requests on the internet", + Example: "Mozilla/5.0 (iPad; CPU OS 8_3_2 like Mac OS X; en-US) AppleWebKit/531.15.6 (KHTML, like Gecko) Version/4.0.5 Mobile/8B120 Safari/6531.15.6", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return safariUserAgent(f), nil + }, + }) + + AddFuncLookup("httpstatuscode", Info{ + Display: "HTTP Status Code", + Category: "internet", + Description: "Random http status code", + Example: "200", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return httpStatusCode(f), nil + }, + }) + + AddFuncLookup("httpstatuscodesimple", Info{ + Display: "HTTP Status Code Simple", + Category: "internet", + Description: "Three-digit number returned by a web server to indicate the outcome of an HTTP request", + Example: "404", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return httpStatusCodeSimple(f), nil + }, + }) + + AddFuncLookup("httpversion", Info{ + Display: "HTTP Version", + Category: "internet", + Description: "Number indicating the version of the HTTP protocol used for communication between a client and a server", + Example: "HTTP/1.1", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return httpVersion(f), nil + }, + }) + + AddFuncLookup("macaddress", Info{ + Display: "MAC Address", + Category: "internet", + Description: "Unique identifier assigned to network interfaces, often used in Ethernet networks", + Example: "cb:ce:06:94:22:e9", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return macAddress(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/json.go b/vendor/github.com/brianvoe/gofakeit/v7/json.go new file mode 100644 index 0000000000..858e5233ec --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/json.go @@ -0,0 +1,348 @@ +package gofakeit + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "strconv" +) + +// JSONOptions defines values needed for json generation +type JSONOptions struct { + Type string `json:"type" xml:"type" fake:"{randomstring:[array,object]}"` // array or object + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` + Indent bool `json:"indent" xml:"indent"` + Fields []Field `json:"fields" xml:"fields" fake:"{fields}"` +} + +type jsonKeyVal struct { + Key string + Value any +} + +type jsonOrderedKeyVal []*jsonKeyVal + +func (okv jsonOrderedKeyVal) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + + buf.WriteString("{") + for i, kv := range okv { + // Add comma to all except last one + if i != 0 { + buf.WriteString(",") + } + + // Marshal key and write + key, err := json.Marshal(kv.Key) + if err != nil { + return nil, err + } + buf.Write(key) + + // Write colon separator + buf.WriteString(":") + + // Marshal value and write + val, err := json.Marshal(kv.Value) + if err != nil { + return nil, err + } + buf.Write(val) + } + buf.WriteString("}") + + return buf.Bytes(), nil +} + +// JSON generates an object or an array of objects in json format. +// A nil JSONOptions returns a randomly structured JSON. +func JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(GlobalFaker, jo) } + +// JSON generates an object or an array of objects in json format. +// A nil JSONOptions returns a randomly structured JSON. +func (f *Faker) JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(f, jo) } + +// JSON generates an object or an array of objects in json format +func jsonFunc(f *Faker, jo *JSONOptions) ([]byte, error) { + if jo == nil { + // We didn't get a JSONOptions, so create a new random one + err := f.Struct(&jo) + if err != nil { + return nil, err + } + } + + // Check to make sure they passed in a type + if jo.Type != "array" && jo.Type != "object" { + return nil, errors.New("invalid type, must be array or object") + } + + if jo.Fields == nil || len(jo.Fields) <= 0 { + return nil, errors.New("must pass fields in order to build json object(s)") + } + + if jo.Type == "object" { + v := make(jsonOrderedKeyVal, len(jo.Fields)) + + // Loop through fields and add to them to map[string]any + for i, field := range jo.Fields { + if field.Function == "autoincrement" { + // Object only has one + v[i] = &jsonKeyVal{Key: field.Name, Value: 1} + continue + } + + // Get function info + funcInfo := GetFuncLookup(field.Function) + if funcInfo == nil { + return nil, errors.New("invalid function, " + field.Function + " does not exist") + } + + // Call function value + value, err := funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return nil, err + } + + if _, ok := value.([]byte); ok { + // If it's a slice, unmarshal it into an interface + var val any + err := json.Unmarshal(value.([]byte), &val) + if err != nil { + return nil, err + } + value = val + } + + v[i] = &jsonKeyVal{Key: field.Name, Value: value} + + } + + // Marshal into bytes + if jo.Indent { + j, _ := json.MarshalIndent(v, "", " ") + return j, nil + } + + j, _ := json.Marshal(v) + return j, nil + } + + if jo.Type == "array" { + // Make sure you set a row count + if jo.RowCount <= 0 { + return nil, errors.New("must have row count") + } + + v := make([]jsonOrderedKeyVal, jo.RowCount) + + for i := 0; i < int(jo.RowCount); i++ { + vr := make(jsonOrderedKeyVal, len(jo.Fields)) + + // Loop through fields and add to them to map[string]any + for ii, field := range jo.Fields { + if field.Function == "autoincrement" { + vr[ii] = &jsonKeyVal{Key: field.Name, Value: i + 1} // +1 because index starts with 0 + continue + } + + // Get function info + funcInfo := GetFuncLookup(field.Function) + if funcInfo == nil { + return nil, errors.New("invalid function, " + field.Function + " does not exist") + } + + // Call function value + value, err := funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return nil, err + } + + if _, ok := value.([]byte); ok { + // If it's a slice, unmarshal it into an interface + var val any + err := json.Unmarshal(value.([]byte), &val) + if err != nil { + return nil, err + } + value = val + } + + vr[ii] = &jsonKeyVal{Key: field.Name, Value: value} + } + + v[i] = vr + } + + // Marshal into bytes + if jo.Indent { + j, _ := json.MarshalIndent(v, "", " ") + return j, nil + } + + j, _ := json.Marshal(v) + return j, nil + } + + return nil, errors.New("invalid type, must be array or object") +} + +func addFileJSONLookup() { + AddFuncLookup("json", Info{ + Display: "JSON", + Category: "file", + Description: "Format for structured data interchange used in programming, returns an object or an array of objects", + Example: `[ + { "first_name": "Markus", "last_name": "Moen", "password": "Dc0VYXjkWABx" }, + { "first_name": "Osborne", "last_name": "Hilll", "password": "XPJ9OVNbs5lm" }, + { "first_name": "Mertie", "last_name": "Halvorson", "password": "eyl3bhwfV8wA" } + ]`, + Output: "[]byte", + ContentType: "application/json", + Params: []Param{ + {Field: "type", Display: "Type", Type: "string", Default: "object", Options: []string{"object", "array"}, Description: "Type of JSON, object or array"}, + {Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows in JSON array"}, + {Field: "indent", Display: "Indent", Type: "bool", Default: "false", Description: "Whether or not to add indents and newlines"}, + {Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + jo := JSONOptions{} + + typ, err := info.GetString(m, "type") + if err != nil { + return nil, err + } + jo.Type = typ + + rowcount, err := info.GetInt(m, "rowcount") + if err != nil { + return nil, err + } + jo.RowCount = rowcount + + indent, err := info.GetBool(m, "indent") + if err != nil { + return nil, err + } + jo.Indent = indent + + fieldsStr, err := info.GetStringArray(m, "fields") + if err != nil { + return nil, err + } + + // Check to make sure fields has length + if len(fieldsStr) > 0 { + jo.Fields = make([]Field, len(fieldsStr)) + + for i, f := range fieldsStr { + // Unmarshal fields string into fields array + err = json.Unmarshal([]byte(f), &jo.Fields[i]) + if err != nil { + return nil, err + } + } + } + + return jsonFunc(f, &jo) + }, + }) +} + +// encoding/json.RawMessage is a special case of []byte +// it cannot be handled as a reflect.Array/reflect.Slice +// because it needs additional structure in the output +func rJsonRawMessage(f *Faker, v reflect.Value, tag string) error { + if tag != "" { + err := rCustom(f, v, tag) + if err == nil { + jsonData := v.Bytes() + if !json.Valid(jsonData) { + fName, _ := parseNameAndParamsFromTag(tag) + return errors.New("custom function " + fName + " returned invalid json data: " + string(jsonData)) + } + } + return err + } + + b, err := f.JSON(nil) + if err != nil { + return err + } + + v.SetBytes(b) + return nil +} + +// encoding/json.Number is a special case of string +// that represents a JSON number literal. +// It cannot be handled as a string because it needs to +// represent an integer or a floating-point number. +func rJsonNumber(f *Faker, v reflect.Value, tag string) error { + var ret json.Number + + var numberType string + + if tag == "" { + numberType = f.RandomString([]string{"int", "float"}) + + switch numberType { + case "int": + retInt := f.Int16() + ret = json.Number(strconv.Itoa(int(retInt))) + case "float": + retFloat := f.Float64() + ret = json.Number(strconv.FormatFloat(retFloat, 'f', -1, 64)) + } + } else { + fName, fParams := parseNameAndParamsFromTag(tag) + info := GetFuncLookup(fName) + if info == nil { + return fmt.Errorf("invalid function, %s does not exist", fName) + } + + // Parse map params + mapParams, err := parseMapParams(info, fParams) + if err != nil { + return err + } + + valueIface, err := info.Generate(f, mapParams, info) + if err != nil { + return err + } + + switch value := valueIface.(type) { + case int: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int8: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int16: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int32: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int64: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case uint: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint8: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint16: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint32: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint64: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case float32: + ret = json.Number(strconv.FormatFloat(float64(value), 'f', -1, 64)) + case float64: + ret = json.Number(strconv.FormatFloat(float64(value), 'f', -1, 64)) + default: + return fmt.Errorf("invalid type, %s is not a valid type for json.Number", reflect.TypeOf(value)) + } + } + v.Set(reflect.ValueOf(ret)) + return nil +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/languages.go b/vendor/github.com/brianvoe/gofakeit/v7/languages.go new file mode 100644 index 0000000000..5ac0db80c6 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/languages.go @@ -0,0 +1,81 @@ +package gofakeit + +// Language will return a random language +func Language() string { return language(GlobalFaker) } + +// Language will return a random language +func (f *Faker) Language() string { return language(f) } + +func language(f *Faker) string { return getRandValue(f, []string{"language", "long"}) } + +// LanguageAbbreviation will return a random language abbreviation +func LanguageAbbreviation() string { return languageAbbreviation(GlobalFaker) } + +// LanguageAbbreviation will return a random language abbreviation +func (f *Faker) LanguageAbbreviation() string { return languageAbbreviation(f) } + +func languageAbbreviation(f *Faker) string { return getRandValue(f, []string{"language", "short"}) } + +// LanguageBCP will return a random language BCP (Best Current Practices) +func LanguageBCP() string { return languageBCP(GlobalFaker) } + +// LanguageBCP will return a random language BCP (Best Current Practices) +func (f *Faker) LanguageBCP() string { return languageBCP(f) } + +func languageBCP(f *Faker) string { return getRandValue(f, []string{"language", "bcp"}) } + +// ProgrammingLanguage will return a random programming language +func ProgrammingLanguage() string { return programmingLanguage(GlobalFaker) } + +// ProgrammingLanguage will return a random programming language +func (f *Faker) ProgrammingLanguage() string { return programmingLanguage(f) } + +func programmingLanguage(f *Faker) string { + return getRandValue(f, []string{"language", "programming"}) +} + +func addLanguagesLookup() { + AddFuncLookup("language", Info{ + Display: "Language", + Category: "language", + Description: "System of communication using symbols, words, and grammar to convey meaning between individuals", + Example: "Kazakh", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return language(f), nil + }, + }) + + AddFuncLookup("languageabbreviation", Info{ + Display: "Language Abbreviation", + Category: "language", + Description: "Shortened form of a language's name", + Example: "kk", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return languageAbbreviation(f), nil + }, + }) + + AddFuncLookup("languagebcp", Info{ + Display: "Language BCP", + Category: "language", + Description: "Set of guidelines and standards for identifying and representing languages in computing and internet protocols", + Example: "en-US", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return languageBCP(f), nil + }, + }) + + AddFuncLookup("programminglanguage", Info{ + Display: "Programming Language", + Category: "language", + Description: "Formal system of instructions used to create software and perform computational tasks", + Example: "Go", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return programmingLanguage(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/logo.png b/vendor/github.com/brianvoe/gofakeit/v7/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1f40f061a2088845dc717be2a3a12383a8a4e67c GIT binary patch literal 26580 zcmY&<1yCHpv;G-yxVyW%69R`j!9vjB7F>gdJA%8rOMoE3AwhCD91twQgF6XMfI#5! z`~T~`SFd(jS$Q{gS&Cujd!2_eyYST*U_ZE7Ngj>Cyva3IXR=UCA zfjQOo!xY7DGE-uQ2Q>X&;&hc_GeWcFiUu@8_;NIn-oZcnhvz#vCeLNA_x4|Uv4Mk` z&Uj{V7JWmQh_;AcXYTpozr=I2IEK{q%umT7JW#b1fMuuY8e+llIa zT>@40U&TiqdK+}XJtba$=U{FUAW>{W28!O#8FE$G%7DvE%|{~X2Lm1$2k zm>#Oe-T(j}^M6jDe}$~yQzeFvnwApAHab3-2=FU;LG`JM(nrb2N5S3I)y~Zapx|X^ z#DtMc1uyZvm>tIiTE62csff_Hoai27G8kXNS)BlZRuXMprbe#iB{3ao;YPixNxVU zf3!DSUJnOZNVfq~wy`!&?~{%HBTlIZVoiD!*7Xzhi3g%wy27=*+!P)i;4Sq(b|&g> zlEU-9N4gt;+Zp0#qF_b!0vB9-u>XCN#FqvDbceGE?|q#BcFu$1YhRJG|NDUJ7u(zJ z5P0Rm%*=2YYdAK+|4O&X`!nFaLb8LVcg|fvQ3w4$=8=d$HPTtMpg$rpW;BC){P)N5 z%-^iU>c}|Xz3`Q1ZGTPm4k(T5fKH2DF8o+V zljU_pZj>Y!mj8dJuy1#l6c4C^ z!)*W9bH&j6#Xs4+F|I<)1(ZQIoZOgPRgQ-^k&RBB>iK4t0~*&pc-)Pi{sR^%b0M^m zFiRUtW=nzwu?D@7!8?FIwm)q)q$^CIh(s$LD447eLLjC6jqNfJHBGPB|E8E)Ct(Iy z0#259QqF#VPTLm@(rr{D5(&b6>IRb0z~pipd+*1Z@pm4+#SZqaRUj%TUy2Oc2ireR z?rLEHuY;bRDh9}T?0)~r@##h$eex}ksWL%~Dw^0xa$q0lQl27Sh-3lBXw5OC1(1fQ zBzTBB$Lq^K(coeZhDmAH>>(O`7$#zoQb;z4^%fP93yI3n+C5hVT7ZP%_`+KklHt|m zw}x-j0<@kzsfyp9!d)PfprDXnXZ}gngMO^gfww_Qx#0}ol0ajH0fG???4|spep-C6 zmYR}pEDcT_#0yzJpd`Q7fXe_d)@7>@3Vcmo9LM?zLs1}x{79NQxu+7*o?E^I=H6#dJ z6VGwv3`(m4@U8T#tq|?;`aU+iquNMcWGZkyU?)ZT2UPG zE9!NBGzYU@)(Wb_OIYtNzCnz=Qqvr5CrjG((>-&hYO zI)%?{k~t!?@UetAd;m8n6#ROQg*pgZD$c4}w(DSGgXD*aC#_wsEsclU$R-#GMM?IW z_Il=nY`xQ8!NjI9&t^y&{=Nm%f?+D_2I=^SX$U0`s;lT8hOzD+UOgaj6aHLX_~%Fc z^1RVd=3HBR>n`kj;{BJFpBflXyVxX6(qzPF8Ae8|BSu$gw5MyyZ3sSAv3C^5#>TaL z>w+CiBsQ}cq8B2X)*N^QyyWGe1W85Mfy|m;QxgYnh&^Rk1?-Nu{#oZ-LWYR9LUV0N zyD4S9jB^iiu20xL52;#rTc^VkPs4?=dhmLDPUP0q5Mg%+ky4g;*smMpWys%T99qL< z3RilzhF#Y34b5TL6Dt)DIf3K|A-FvF6ICPBefC2TQ8SqMZy$!OlDhjGM7-;^O1?Be zhkPc|^lI&m;&4!eM8sRw*+4wyfcFd;ZjByHoQEO@Op2JzTz+O44kd++gPf_p%%dmp z*#we3m?fz@>64ah@2dK)G?E{I7Q=r3k{7i;&4J}{7HBtKt_K#kw};I6U>ujm#yJ(s zt31g^Yl@*!AWs+M*h0`L-NZ6O&D8Q!f34R>((3-hw#*cd)j#cj!()zFJ6>x0fN>vJ;CFNDA#Md^(1oG=YzOsCTy*v4xp4ArGBs`D{H17-j4dorXLntvgaetb{ z@W;v^{Oee`Y`1XVN6heWjdAlc5JvnS9twWnowr*cick?9eV4lK^a*cx0sXuksRi4! z4t*J(l4{x09yr=mQqt75`!tk+{f!6p?O#@v&F~m@v<&(TE_ifYi&;2}fsT+}@YBTV zwC=5SjxNYn#-q5=XSy+oA2{0@@c!BZ=OfC>59dq8T;vBWcq`^+?(czue(b5#)I7{HmryK?sy)^l>m6T%Hp2Tl7JC2|(Yjr6V^xfqv^c~5ibdK=ePFvXbcYkkm4*ai~Ah}5B)d(lqFESIY! z)H2-$D7glB@5{xWA^FxhW0^{UHw7&I-)s6}{H<0oJCa~8dHp^RIp|YnDrdnaWmx354DRE94XS@ggWnr5aSH6GW>5f z7ws1#yHh?}?o(KjnKG`R*Y4`;l^X!B9iMk<;Jyg-l^}Gb5m&smh>6B`V%XSJ7@eKh z34L4|#Hc(aCz|VPIx1`^UjOJrBcDsE+Dz4VNal071 z;$>-bBCB#N1;J!_rv;&%Z}<;rEm_Z_aD%n#GOaHr3|9ip@cT>(~hNrws{D;=9!&ahKlk~R3*w2Kd4lrGb9~?+HCC|$F zfPQ@KlKf_!PD{v$Nb};*Lw*ToP|Z8YzF8luOD-3?Yll`E9J#ff`w%%smP;KrH=RR4 z%29y$K~7AHp8P>vp8sZpIlu@0j#_%(9Kl(swYy&Og94v6q7=E&$CZn}C2L=k;4q+x7PtQn*j0CO^B!^Ozvvb}ZmG#vz7Hn$k(1H)hg& ziX4X%znp<3?3{F-XC(|2(E=+qy`y&nuP1fX$EXg8syEQw129Ucdnd}#$N=<#WfDqo zb8(rSjpW_TD=0|LM1rIH*u075mh_a!sXpYGBXEBov{Iy91!E^r*pV=(1T&ijkHm(k zjn1}+T=hI|`ul^z=YXDn8Ku!&c7IzIlC9&9?+JavVxRO@P)R@Hq<#GSN@$KQ5$qHQ z;HKuB2wrD)C#i%sP;EC7V)D)|{52B9fA#h^muI4KwtBvm35JOU!`*DmONJS8E_To> zo8_jD1Pe6V(?2nWxvmaS_t*p`7*H@F8xY+6fNj08`hw_QAyK7UD!+><-&p>lk14#& zmL;xhqd@bqokZ}CSZ!)OVUq+{M9n+TTb@Hc(<~-*{*4zp+pUo)%?(OoFnf{Tv1(}+ z?EeK^m8h5la@m^55}sowz2mN4_shZcC zYhO5nw0!0jxU4b%Tf2uO1+HGw9xJqB6(ll)@1KsupJ<$j;|Nmc74GKBPnM_*XS>eo zHRsQ_Xh4)Sb>y_@YhJh#>sVE3Zbb{S4(#Cyov+TScG_iJ5Vyes5?DH&DEUW9#IPz} z7|6TGiJSNnETHl@-D|@}xRAq=?eHm61l!+YX}rs;FJhDamO-!k$pQe6alhlf&5D*basVb22Qz^#3>A-(p- z6s><4*`Fo?VtIB0SpE;fkmCv(nCH1nOQd2ytJ$G zwN*LcxE}Q^{>ynQx0v!6mblCnPLS0LWzSe^M_TPzWbhJ7=7^(uXZBQEzZPsj6%g89 z>y@c2>Oqb=(|A z?LWRa$hIp5VmX3la!j`f2jX(`Lr|@<<kzSmdP{ zB()zt10`bi>pUj2Aa5h@$K{Mh;f(fMo)Uf(aZI_kwJb~o^x>j9g?-w}AFcODQJZVq zns7%63`aI)$w$b$qbuj!Nd(ww*GW9yn`t4LCUK%A4;x_$KVt2T8#8M;JP2&v(HUMrH-7;HVrJ9;cWA&gJ5Pp;Lf<1Q zcc958p9t6oa@f^Wiia$x3o+0&!um7WWdN$U7p%QDsq4_N;3IMeNc`Y!+4t;o1wWU@ z#wT!a`~(h4pq|e>d?870=-OG3P_DDjcIYUxlNfDo4zL^BP}^S@XwbB2AWZ5f_z6D^ z*2t2~z{2pfK8?*?ggRdO2_DJ9av71baV;|@&|35!pgqt6xCZjpC1WhtK@of;_^9&* z&<&@9*e`M0$>@5sqf|d;bAP=~Sy${M_+>ZvnR3IU`ZfYSwWM{dxsIddg)P9=d>a%` z^7v=hFSFxTjR<2-*nmYm%`evX+Kya$NjITe{|94V z!!)*2tW)`2VQ{ueJetVtJ+@5`E2R;)4kEcUR-^!WKRge9mvQUTmpajQF}MczUJSQi zTu=!k?j5Sa>n*(M|2aUx$h=fkB2T0_$MOvDsw|&9YWi2*F;7HCNx}=Px4j;*B$D~* ziMx)Q!HNVv&ny}VP2kSD%4)pLrKXMt_&!2<|LEW|PTb~*AYHNd(iQGn!wi`{G!%zF zXt8GD&j|uvwcQ?sj+nrw*fDXkf&>fu#H|9bIxsrOZ^G=!?irqts^2gh8d=?1fs+2i z(7eGpQ1BSdy8Ix%ff4a|^BVRj-TjK#LqwfO&OF$IN!sgWs{LC9)?B>r+w#Fin&H`X zzVXRR9y4{4XzH!jQ1+;_8m0o%k*=V)(i*#5H?-83LBW#fk^L9N434fkLTKaLDMcIi zv&_#+LN_<8)Xlc6u>AxWwkgno+(>~-F0dOr`V5eqN!Z{e8r&+-B|q}wB3$In^GTg= z!XneuH_RRoxx|$}Jc(bGvfCacWw2<7?}v1Z+0?_Ly4CWd7e;i9r61nwt1~GQdyso% zu^EFGzzZo1zV|cM>>|WQmE0&>mf3`!(hM953#Q=T&%ZfgyqfJRGZ`Mwhm60d zfyWOeM(7B7GvQ{u(wz>!w?8NpaV2BuxyPPTCG}JWlcKRmYXY?$#FD(uU%X5c7>ugm ziIrmxe=bRG~hR9^H$z+c#Joc6_|5m`Fl(7!8!mN=?xSq>)`eC zag4f3tO{{?m2?R?uAN1_{#R&?qun_Y3AJ|R5*DhsYk~aUOLF8h@gE}A2Df4$BkcRfpxt@uayQwdy2J{`t!%}BfjeNB5#J&iDRnWqo?;9uof;W#Y1b3;$2fmH0srwAQb z6&KfXuF2|FWG2eveI7qHzRS^e*w1Q9dfMRvA!*aIr+C%tjCJezQTkazzY6Jx9+#hA zO#g{t5>TUic8X(Y^M-rldpzrl;jj=w-;NG5hQ24K=--0oG2LTR^v?V=&xJR0Z0XG~ z4Bx4G;G|e%D^vui;-Spf)rOsBOMS=%cm1)nhdsT%eS}o6@vZ|ovL^ht`I$9LqrtS$ z@ERGU6y#v$cl0*OSL6b6YVIeS9En6#rQy#}ODpFqohqzlZeHCA7U)XZ;$e~Ic%FBg6tF?ne*kzuyG-L5RAd3Td>LA} z89S`*iFWZ%AwMQ9@^n7vkDLS*NyODlZ1q?QZ1^olGixu+r&h7X|2VSDL1>FbG+SFu zg29#M#mrM^`?nFNsm4XS#5Y@f3?1d!O1Z{f+0_X(X{KVrdWiv$fb)F$ zXYMo){T6$N6o*b93b733CBPC=!Y7Koo=7c|$>ufFX#U6IRp8747fbXR5h3R~W3u%o<@o1VOso^5mqSUtlao+zuL)Om zK)1l2ik_)b+a=D{(^B%sw&Ox|>Wz`VKC*YSC%K}w0MKf&Z{jcsd|nZ`a0s38LFXdm zB0G9)9H&raF4xV)B)LJ?Y69Fq{Sz3}?`_qxahq*`8bFRpe{Tw!JYO6|qi4eIZU7ub z;~WNI!#F-4_jZ87zyS*CQ=jyc$0Kc2%blM zeOGstk7pKnPQIQU9qSWf|7m9Bu=>T#vnl@4^Bzb(ES}tv&^D@c=G`9fZiXcZ)qu8m z-Dt=gEw?oB6&NaH#)!}S3uD~9PTmk6wTFDBx)9A^G}C2a0ZIz&D6;#p_z`m36N=`N zA?Xy-z7^O}rvxQ)z(m#9%}> zM#V!*iAY0!uBqmeMFOJ$oy6JB!wNj|R8M3Axkook_Rq)wH497r=;oo+_{bzWsB>zE@uN_`gGjRu9`8f1g=RggWG+qwiFr&T#uKpi9*XE=B87-g?lI-psJ#Ze z0fyAVKC>N(tA&P1FfY>a%;DZnb@F^k+1;jB>{_{qVCj&Y`SS&>1o41uY!Lt%arSKv zz<IKEmedlPfiV`sfD06*~K{Xo4Z zoGb~O!L)j@J{7;OW8Y98jy$)fKnbLCi;lV?Gki8g7l+Gz$F6N^aI8qCS5Oc6A|53y z{_P2C%TNh2>P5n({-qW^-(XY!pKm*r*BLpt64FRw0AuFusNn0o@ zxBgMWXncJFzY2@W$%>O&YnQ*yuoucU6RBmn=DSQc*XD3!=&ouR={d0P^+1jV*5>=> zg-9EmmjjfsUJ`TAM5~$wEsp!#oZpRTs$>Hs$KZ^Oj!72vr6c<%XbJ;nIAWlfU z7V#+j?xnzDN< zlRsm`%?}&Nc%|*OU7qH3-9MK9>%m_D5IXb?cXx9f{g28mYA}k(Br5fCn#F-|%RD^_ z{twF_*eG8ciHQ`MF{@NlXfJOo{bRb9F*U3}>!~G#BG;jQc`cq2O0tTas znu$+Y`u^pLq`6vo8j3K<0LHTv4I2x^&RBh7M3^Ou;tI?J&{Vy7JYJ2w=t-9_7w)|c zwXFx7yN6*XHQbQ+s3_Wx`6*@LxYPCVP5D&dIE_@_G-v|l!D|_-Na*{FRCH~H>|cDC ztjyB2HEIu9>lQb!T(V7ebA>>xx4c?j^@(N82qD+)?oU6u=+3hjh&F)hgqF*okChaN zmlH3g0%JD+oZ!-Y|2h&80pDo6)DCiM5`Cg<9Dl7YJZKQ*6CV24mNm0U#xgLE*Fk!d z;u6f^+vgM{ z&0pxRA*NB*0{DgMSt^?X{`rMBdH}x*DK?=Do|?arQkof9T7kf^RYx*Y;?=!N*IS66 zs7~99icCqRU{#a}&upL=$PFk(@%xoH0rn)XqIk(A3L8>Q26&IWX+SOodVe8VTxY8sL#6nnG$`s6;J7$HG{iPvTL@U4Ii_&FMjKL!-hiL7dA!a}LaVo94L^JnJ&FdA z`_yj@;-oE@1P3bKW7v|D4fLeZQl0-TX62_U0;uE4$-J?7UZAgQ&&!Jzr@!8(klMi} z$w^%D&k<|wZCiIbuyU%8*o6LY8%s`yr(O6BZPA{vUBTR}dD;rj3gnWr>C2t0R+HWC z2?q6ncbfOgyBcC6F=JzuwXsdwFGM$g@dTEV9n7fU)PN%;7_A8A< z9!a~CQ0W8jKqK=p=VDIjCpD+nO)ZhHy0Nfe;Z?x&P=b2y!@t4(i{tJTiUcaWJbKWm z>ADvmM{>^;sko9@_$JQtBD-XH+R{HptVd2zCC!f4(TD85@8%ec3KT4=aD0xxkHE-)?|TOWO?} zuMCP;u-L!^AZZ+&EJ(nbs8ed0&If{Wx`eId>bR)ZL^nbxLB_VsZ=1GqVewwqL9kAw zDEYHnY27x!aK!z0eKl|P4U_Q1Ql5VZ7ZZ_2-912Om>Fy5xKf)riQe1W9eeU{T14yk z%M=eR&;3US`aLC9>G%@OwEXwy`5U| zPhS*QBASAulAUvco-0KCxK?X_D6Y35Oh3W|5t!H#^*y9oTD_jH4h(#giUD_K413=e zg3c^mf5kYjmFtW9qgO>wL9FvytNV^8#a*Z8{0#?AIXcu@-<)v><$i_1I(=Fq` z1K<0+xQfLO%r0^~4-Gi3(5v3YihJ28n-_~;39~or$(7h-zRyNcBmv9dT%S^QW-$F# zj}`^P9bA9?_=(~b=t|r2)cv4VkK)-TWz|diDz2C4?lc-8jjth|?>=Vbs@j{gE6rfl zGT9{`|Ga|jtM0kzXd=fa!t&3)?Jah+uw zs{&Ax$oYU!qa0Y0j)E1Z0L{Uo0n5Y{gv;~^l)AJFTt+>X@A%M6$-f;iv-MTF`RY13 zaiZXdaZIlf@1qNO>x|Ev>S&R8W9WA1hswUHU!V2Ms~UGX_sgUzoYYv3uV6kXjT24g z-!1t(reE*tqxhL{VXQ`sNG7@8arDgHM2e+#$y_y!2AFTtQm_j0OCt=cj? zz;M;vY1)$bTPIbj@cnkOP8hAQ31V-Rt-N7ihGpw?3=g(wMyXODs;`c7h(j6+0I z!_InM^k7lS@7TVp%|I?mJSx4Wmm+8!cZ-7b;pVt>&=ZEC76%#BiNf&5nhFmZUd9}4s>rB2!nu}C6K>9u^3_zVu99kp%d#9lM$DUGq6=z9*4NB4 z$Q8&NceX%X(fKxq^*r{K+y)~v%zgW7%PFAur`vILB3jYu4c_)b=t?f%<*pM@J7VF7 z$Vb%FKGwNDu#}KP-04jK=K(>w4=~+Ap$hR(JB>4rTK?ch5{gzy)#>;nw^UX$Ev+%wQ07!}8_qT{degFX=z?i(B; zu5&rZ>SXWmLtLaY%B$XOY$P|4~*K;M(C)sTm>(fh%MX{o^Xlt+l$bYbQi z(G_DNTx8U1+=!TXkae)4rEY=gmkc>+gSEIy3b$51lw< zTjef8gaHRVkm6|AMkiMRQzoaByFoo>lA3y@e`R2jw$P4vn1K@>`DKuTE;?cOJ&oT&;x}h(};IZrg+ls6DRzqOG;2lHZAK zlQY`;b7Fq>SN+6lzreKJS{~o|YquuF9=Y4Tni9BDG*xkY%}7cH2OtAvu5h*D1|Y)O zw=Fl+2W&0hRA4fgPF0_oFS@1VJe+xB6(FcYnI_d49TXP?)Mt@Y~|Dqt&R21 z5E4aW(f6{d?&#qN|Ml*CEP`AXZAzQd=!aW-0O~+;Df$z-&l#6%1t4X&+b=%J8==rm z^_zZb8BqcLMPl|E`dUZ_#Rody5sXOI0N8g9+Oeh3*b#$` z4tZGae13g00!g4hyLRiczaJX;&X6D`=?{7nix>~wcD083oa+Ek7OG+zlppOeKFBX3 zHufiO{3?OMc2gD#hW|*&IBA=*mK6aVU*id|I^=yhBCsSm_9G;#bTr2sYREn}ZvRFu zlp0`67x)MC?GKm8;I`RA_S`hFsd2?StGY5Z>+%jr5Lt3Bisu(QCfl}Fa8(&s8s5@- z;BHd*+#c(X@`C4i_P&;{!T5i=L|$KUap3(i$B6dk`i<#f!8XPGy(ASq@y=0u_|mm~ z@#721IjCSxh9?w-b;RR9vT|QLW|?HbZ{>x@5XKZ zxj16J#{x`E8=!~goNSZ4adNeQ^boOgK-c59wcJ|$#d@H%oi{8I{kOvU;b%!EaP+8O zx^F&H-m*3&6_h~K(gXM|%J)RKeco>PN z_4HWGK4y5sVNHB~wHPvrM%jbc_cP9;<4VuL%7Tn#aCA3}LdT1&XG6tOWcHq4f!aN9 zyik4xZk+^_OK=?5Tz&=Wwd9h7PpITbe%nrT+tc>lJH=ns`iQ_UHoQciP95>KKJXQ3 zA75)HuJDVfiLc`oqbh$+RfF)H_uOwjRJEF}y9{Z@dN+`}4@rs082^U`Eu?uU z(=TINB&-r&z~fx^QS(rEjp3fki{S2FjvAUPH{y;88o0W#W4NmFC$Ff``u8ajOL})i z4-Kkjn=$iUa6BjpD32>=Ry3D*(O}LGcnBZpd48to-rR*npnw5HaV=7@Uv-FY%gs9RMVCvdn=lA<2(4>X1^Dnu#!d+lM&@m? z<;lo!*Ys|m)$}DXWuCa{(Q7pgyN|Er&IC{K7`{~^ElmGa(Amk|N1giT8*DjJHjPm8 ztbrh&u!R|;&ppf&o!CL)7Y&DMu=Q&??z4v}wc zB2D+J1qubyKG6=l;FVX-yokW58tAtuJ;ifZdzMvZT&kFUVpt# zVhKeJaZnRDgjm-OOV24#gf{_EL(pYVB{&JtoX|7tmOH*EGnVSByZnBhi<{84*TYM< zNL%jos2QH|IeE@()d0%}@5lQ_N{O@Z$G~S1a+HD$6P7kRxiP0s!$0LiKI9cR-$9^t zmCsN=WNI}%pr@K-)EDnKe!LE;E7h9AACMqgSgENKfk049PI(b1dbAewmI)MI4Z;T3=-EDR+coB93!pMr;a{LB-xxX432r6+5 zDX_QKsVOzd&B})Hd|z%Ht+2EdxTh2RTPB(Ec!qYJ^F$t+3ZmEkSYqL zQ+ZH5ux(8_vyMwbWXF*a%^5+nUUBcH@J?BhR&Ba+;I8kE!#GJ=t4VTgPoI-#ml#5n zukP_)1jC9?-FWwODv2TW-yDfy^2|%oQ3kb^Tb-S}(zy%eqZg2T%vv4T$sAM~Ta!T` zDg@&Oi!q@Ta!o|5`Sz6rN3V(IbD$Eii8Ra~@cUf}YcRNq?gk zy7@NfBN!+#l zu4M}Ep1wrS?;`LP{ElN!Dc31wV8-326|W>#DEEdGWrdWB6q6mZezx?krjt)w8x2}# zgS%b@3aE@hI;M9LknuR15kPwKFr_Pf&Ej;lEd#vK8bxgc9AqB-}*1nVMet3Mw=m4vES|4VNXeZh=PQ#7F7Od5=H9AS?^8U zzsr9I2lZ14H^)>z-sa`HhWL8F{XV3Rq7Rai` zZg^2>l}Kyd5V!I8Xs1E4BCZ6gH%PU-q!j5Yop9?Entr<5E_tQN7e2FP!3xg#v7$Hp zCUWRPICY&^R$bB}mF4PwelLA8*;Rp)hCfx>76#n70qvR~K4H1_*MF zPy7?w&FbNZqN1aw2eE5}1$ljGR26uAloRds%Jj}k5K2(KA2tC?GR%fi-f4vC(73fG zzC)@ioXB#e-d5*_&W>{`QfD`j%hNbI4Z9mP?FNXh=u^LMAnxCONmEHHeJk**ftelf zjKRk;0&2$3@-LxX@n!%Tyu#ZUO|cdsk@Nnp+kqEmYc1>IepxVsY~`TdQ4hXZWIPH* z>Oge`oT+P$_I2FV#rQ5C^6%2{9W2GWPh6pSyC%UmR>9v-F%fp(FId@O(4X)h!N$f+ z{GcFI2@lk>Ko;+rVDK^Xw_9CliLFCHna%5y)j~<#VZ8`mPyS!<7-|Y*{ah%-Wq34~ zb{K^6u_SqpD(3m#LjHo$E6!#97cOB6V0zvtM+X1ONsgo3SG|jVoK3?Uwyx-6BFn=7 z{pDNxT}alQ`U}IzR{g?wCms6`oQQ;BCixET=DNy}R6;G#XZckX?BG!Pd#`m(J!}zr z2Nu?xgfATz`^!FdBP297al_YCnb@5uOy^0|3_+39CeANXHy9x+W^*5&1p=Aw^p$hp zEsXMAs6m{+X88J1$vvgvI??~*F0t4F``|5>1=wGV1urE3L66pk?>p6MT7>^?!8J-L zQnBQH{vlNz!PSF16^LZx?WJj|3|MT@O)E9kr&-? zs;4;OUn6nz5iv@EoS_!d9%4cCw7EmFScq1oidl0jYLT~rBLqiXw(goOS{>ey`ER49 zfvy~3bsD=sY}L0*t7c0Y5#;`BMKO4i#`3M&sZTb32IMWMor-3yyT2O11=TAvwk-Lc zD}eiaXx->B?Yk}gUK#Dy7Tr2w*~MC?kkFnn)C_*JQ}Q;OrLWs^sxjS${rP3^x2sKu`OKKjrJ+oLxC?kLT?l9klciw9RuTPUv_UkV&P>ds)z(^%$$&pobyh7cjT! zB8hTO)toQ|?vH;JqGrsP4}=?yTTJOz3*L*U>bryyfb}(GtR|;*|t~#6&K? zeWKov6I~z@vrv)bMS)atiA6^ZER!2=`P;<<_=V4jr=Ap1C^FC~-Z_z7lQLW#tHk3bFk3sId*c z_uiKE!XGXNw1*-%a^5%9d{_3?8O^SFT*~XExtRX-gl`;3Em@gQ1jWCnp8*Y5Ui83j z=Q^9xuI}%HSw#eJ7WlsxOo?kqTi1tqMRZz+^TP}%xb>w)z=P`_-oRq65%`Dz*IbE1 z4u!?psb@TZ#B_ydnOs)_tw$RLU;UixS9DPX<><}w-zf#!`VCzQxOIiwU%s&9r?9I> z<8J?mjhFM3^vADa2(n`E+nkY*6=L@$8LkYQGPb25A8(x58~bb;M~_W7R5C)o z%mD}d_dG_qBb2|VX0N#ttZ8XCdEvWD;D#U*@oArwTWF9jzz;s8 zU39vjC^P^%JqImtwM2aW zwe_8Z7Ll1lm9*)G5o;&B1BC^1XFfTl?PF(@osGR4&2pr^PDqTyC$5n*{RKSGPtoC6{3|H$dSmh@DD7poT@r>Y!VeMq zVIn-Jzj(VQ;p|O?pZbXCEOFOW!xP}@>G;)~c(lV{gD@J)c8vi?8?2$^g_O)q`lPE) zrJgFytX#2G6kx@hW>BlRTteUG@B1q4Mg_ttaCA=xZ7m;18hh8D1rc zy=eO$xuIeQ(wZl_`5J&*Z}EuJg@2#IaC7?y#_J)=NoURYoEPJJJYv+W=h-x_)L>k& zftYfS)r38x@tErG2^Ifk$1y(vy+n~zi>K7*sSE*qPTst?9C0F|MlXt^QodxfiH?g) z$pji#GwVqvr8LQ59`h5MO#bon>r7Wr8`|K2yiO-Ho}A9CHR;2HEm9jzk92-L{JG%d zJ6~XgD^Dud)qR>>z=YA+YopUPEoJKaHxvVmO^IfPoZ0I81?qy}%n16SMSsG{bY@s< zI_q-QuntxZ2+E(3x3;sn#(N`%-!|RDqrVvpzqOB6rBR|PqiT~bA z}+azJB3_AT9}+ozCtTxA1Wl{m8``gAcfv7JDqn;XY6aX zYh_EJJqIKo{|GdKK;jp~@@DhR zxYD0%pC7B)n^BU1`qWxvg6!DW-O`0GBk4Dlvk4h$wb{O6NF8;Q(iQ2hW`^Jfrwm^I zrKs-Yw+mk+ku==29fxjE76P|a{!)L$&eKIj)J;GM8fn(7W2-G|bv<(Ds7F9dABIYr zZ|+y}uexkUf4DQAP0do95;FWhTNs8LkU_NJq+cv@l-IbI!1Xk4k`#$|-uxu*{AMAz1l@qV@lW?}AI z&Ur&iy3i+@ zN(t_0m3rD3-6c>J2d?ve(>!vb?i9QQwZ%93xq5*JgeekEuHZk!zIHn~So!}W}S`>xwRp93nI z?|Wq$LE#yQ3;B@KTC#IT@@{Svqp}&r67xB}asY5a;;@52F#H18G_ z<;P|7!65mcMpgCEpB%BI>*zDXl=!-N`FDjCztr9RU-@N@F~M%dr=GVse0$Mb+7%Vi zNwWV&v__G7A6xqUxhXAm1)yXcLq^n0HS(cMwFs`Dr;f;M>lCye736)6u=yzuV z%Z`-Ia(LFoef$-4w%vWPi@CK$asI{t^utezxnO)E05u({p0*4~zbgFeDHsSOSH8K| zUWM%Xt18<%WMp{CQ8+r9<39V>PC8#7VN2ez!pV49tzMP-6R{TYXG-MMl|${!5Xi@y zs&V$TU1ui0LhWY#BL@Up0@O5>s}1*HZDeYGZxkaM!)Lc99iHST@hM>qOK&iyDV3?a@k zRxdwoK4Geh;arhaoT3CCWXjxNoC9aOR`MluN+&94mRef6jn&EJezky4{+N-c4y9lD z7iFlNe}HI)oVDn!eol`K>$?-AXd%rL?x?ZfdMMKn$P5K;H4N^}(0l1yGbY=dS9Ds1 zSrUL}bY}kET?@mo{t5(GJgTt%6&PAK6u@^CD00{!4yotL;f#U4$M~g+;?2b`{w18g z>AmL}?+28GNpvQhIC;niq8Dl>noEKa5e8A~c7eH6#eE22JlG`*IeEt^B$RJttCECS0 zwG|96(0gdDG?%;)x`DAcslvC1kRc+_o9LBEhy=?l4_$Y!^_OM=G}He<{9Efq>RfRo zCv3*tb!~Y$F{K5197H>wpxKUay$`Pc9_@j;W6)QlPH5vIR#%qoik_OGP_L<%j$@?* zo6src%5Lem!v+5;k0@gMb(xD2xm3dV+vGZ&LQ&jFrM^?zqTV5@mHKu;GO-24Vo~da z#$=$ZtcY{2!Tl7aVphz=3+-%ap3ZO5khb%xa>Xa5uq68GRECY-1qjRo(EgEYq^IrO z)K@{nl)nPNlBmvpgKc`#z?ha0G!jD@3wEHg2pHXaPNV~7hr?ni;S-Mf7RhfRcLFQU z%Xv7K5n8ZuNdfG7p;ssK583(HpwBj+r9Clxl=H9k(?&mh^9oGhK@{n>R{l;7MSSo7pTrKM1&?vYudONeiyfPyn_~GYUtDaf*W~#{($#p$T zdFl(MOA?zh(=_-_`V+zdBPid_Fa3D2d)jEHzLp`>%+6w@3@CtZRCuM@7*yI02r07p z4#Hr}Y(8r&$*G*R8+@4wcM(REOrqjBt-+Ffnx-vq5T_&j(}CfH5v3$HT?mx*B_dg5 zX#qRdJ8@?hycXJKH<7ibkl5ILje|{-38o@2bnFXmmt?bH+{T?d`#?ybMT0{LFHD3Z zz!XhDg*e%}P}LkZ26Wu`?Of#LNPdM>j#O6?vPsd;yVRdpdu!Mbvi~xd4Fl_H$s}gW z=V{I0n%Y59WkTccH3IAUKw#h6SaA=1UF& zf~L-y0&X$tTzHuR_Z*xe4QkfJgjkP6_m*j|r1g8B3o)O=PO79!`hoB)7onHHsiW&x z1`ifU?ZxXl1@H7x40V$HOVtf=zURJpjy9>1~ ziLFUiTGVF+=@wEqYwlEiM!)%!3!7IxVIf?m??B{+BwSs5G5$cwiF*{rc=Fn=#3hX{ znhe}QGI0i9nGxsGaXQ6|=mIw)iuIJ3y8%p4EO=Bhn#~gDjP#oXQg2Nbv(leVm>1~e zqx~TEy+OfwVO9U76x2y|zF(KLA7sP0$K^WiH=)V zyJ}9JxTQv(hqaw=^b&!}Cjhd%g*&>*DXN#pCp%7E78-7as>~MlE}U$qKnU#Cys-2f z`a5=&#kGi|A_fcr=Fi1;+??3(`nb$|BKRMwR&=5Cc2<-6!*HTA+p5+|tb(U=mQJ&P zoSUi<{HF`)J&e=lA!~E*FfvoG9L5^~pNR5F-uEMS+q%9M&UuGbrt(1mUgcXTzD2bkzE|#!(F5y}QWb|k zrU}%c&hhI{!1O#Yqk|C8AC9qIjxaI;m>1;+>s`}6lceC~aUYfg)@Sm+Dr}a=G)q62 zR;~O%omL#x4Q$ws-v{9Hy8yP;>#e5;jh(I|HjCRxdBWVXbEcp}$2eVlE*-o$+$NZt znir%wf#1jyZ%%HBI{n@rxtoaM!le1O=x=4>@^I8cyx#!XzKk_P`3W}>4;`|Nf|c2e zC6TQo<6CK_FSRiR z!>d0}><6`V%qNe==Ql=C(+BRelW%FJpzgm0J0*%Xq47wSWAJnPP(5<}mO(x382%A< z;JZ)CzBR4PDh?0*42&+{&|S3(t+rxP_8jr$+7t2rT=)!SGklM*m_({SgnLG)9muLb zv|52l4uuUvWoZ0$$!2uUYq1LD`Ow)=DNXVazl&3|f{gj;^t2*!xq5JzVgsb!@-152 zF4x4gOVDCL_l@CMk54SP^qpL~4JM8mTPs`NXaGwmLP395p-JnexLZlaV78KIDIea1 zrP9cZOK0R4n_YuWH3s z2FtMP1-+7DejxsFT&MT2|+{;%e4^>i*?9i@pCsR^do zvoJMtM`%FCcB|JcB9y0Dmt0t7F+hv7EG;Xs=eO_AEy^3K2Xa0hgl`e5i%v>wgTt8H zcRpC$cz^@o4EavGo=4es=Zx5M%9P;v(}_6aliqGlCAzdvihJsESN$3OcV}rKmDfz) zHwoG$M^-@w&wwh}oXlIdrsHh^9?^J}0Ma_JXTK^{ZbRR7hoB*s0Vd8r~-| zguG~Q8tVyo0W(W&V9KG7F0pV4cnHirK!cCS*PQ3O8;TkZaH;Zh)SdVAejOknog|>7 z-5}Wn&wV~0cOX@devOj9H3*H2eRzyk^V&nGWLNWB#;H!YjcnGp?7`{E_Z;D29y-O# zAt;z8n7|7Xobs${uausinQIs#WlAg8!q&N`m0P#+ZRO~zR|S$3@4M%Jh22$)L@^yh z8tszp7|gDXwT_}ns*?JHD0){wgi$dm$asHU6OPvF5^Z^IzIC!mkzI-x>n~t)TO=kkD2zd0?O2gKgYq0P|VV zg?*o5{oyA)Q{0_Br!AdkTqBUrNR~5ZU+&c4cc-_GFg~`{(1r^)6{VQQcJC zX1yWOCI{yX$$h0all)#bAlG)MYxLl^5}F_EuS|x>12` zulenVgeJ}F7a`+JOxGXB(pMA`=zlN=U^KC4pt@&@VRl*X2h1Q`Pi7S)4qOiK@PqFK z*lGs|gi(_$>f4LMxMqDLmk0L+s^>=#3LI7kg~shqjMIL$NN_ca!w#SM+2Dl4VP^M_0*7HcqO{p%*meF0F`54c+ONN!^9 zMg@Fo1YJkJNpq*~E#wGUdBt(uXgrOOis7jehdv zpc(xxl?<17rWe{>_T_5v?5QOf$pRXIF2GNj6jOLYMJJwX5zeh>%lhzaw6 zH)dl_>;0M${wF29jYuPQbY#_E)4Cbx#LdBTu&)w78VsjX2ex%(54p{aNhg_{% zH}Q8UxMY`?%$5XEz0A8R*fCVYDWa8j@4(L`UP|8w7$P6;6mHj&hO?EW7LyD#xLAu@ zy4qyV3ynyWB*;slp(NvuPB#&4Nemut$8MkQYoB!Lh_3>P_0G(*zasgU1qBZLw)g3d zPgpwtovb%6LShs>hVDEcHq8Tfm6esw)m!?~3G4IAlaZdfBU_*KQ|8%QcIT+RiSQ;} z3$q?`#-Vib$Z0*Jyhi-># zBs4S>p~u=y3ZX3Xwp;{av%Rd36Tl))BRop73QXb!a*VgH8mtqF&fJSmur(8yd_w85 zuXEet55m>Tig$q*=wenBch_tCI@g0X7C*H2RgnVQcYLZ_6>z)1kcwX}tPIwT$Ep^k ztlne6`x`>nXFKnvkfJBzuA;YR>ehG@409->+j(sj1y}SevIGzEuc~x;Btx;1wljh0 zPSf8D!>t9hu)B8sff;eljDgHInTv%sF1ZS%96HfIisfAeVwfu_18%YxOyOk=;8Fp# zmYw3*J?gE&i7~un?2Z&A*>RT#C0jh*R5q(kiqoqyxEQ%`Aw--`eID|S9S>1$B38zs z!Dp<0<)pz!bk$PW7vn>syH!!t6%Vy~_#gK%HT6dk)P~Aq37oR-EMce@Y@Bazkhm_| zIfoS6d~>FLJW;O3B9D+R4L-%B4rrgmw5K6Ud@9k&_yNv4KW6puKh}`pXZSve` z??BkHd;WHyb8~RGg)B37qbdugG2CF{dbsz$#IPd0}l9)&9G(%o0Q-+ zm!k9F_Mob)rI~KXo`8OBS+Zlrg@dZEn$lmV{@5>f(*3-umeCwU|O2FR@HEyYVd}u8nnK zsKd^DZ1SM8-L=5K%QLmjC6;%ts_b`{8j~vgD9J&3)Mm9aWu%}9+5|qb7}ql(U#&I2 zo6G@oiUTiDU;Nyj0W_Gk`L2H&BA8W+iAg1b^tRq1??#@@VZiHCJmLPlI_E}R5Pb5p zp!Tnr1_>BC;9d_%aB{suZdtfJ9u4P{%=NTt1L}|4WoC`nISHz7FfR2;Fm0vBHib?FF`^5moFCSg=KeSDF1 z8%t$7-6qF8Pue)-f!m?9$eHrP%wmPIXgJVz=3bK~2 zMQ+CeJnygqt5GY&e8iM8qgcBWrjK@A$Z}3S&-_!6>_S7KZlauMSR^ZWC|*ta*TwKnt&u&C^2k|av)Ls>G85eiCWciv|mk<+|F zwga5gXYOC@qKmH>MRQ$)f_RqBHn(3NWXofhnwhzEN$XYgYPkVrtgbDPLg=2Fvg;{} zvvlp)21|HleTPyY)7b*BdKqfW;aPPyx}k!l@h*4<2?ga3*!;68_s}n6Ce^7=_1x(Z zZxoN9TVT8?R(EP#_l{_c4_dHtmRy;xCutIZL5oY-^(fl!j?dhjee)bPPzlQ$ndEqi~X8tP% zNq;aM7v+y?=0lxa(hL+cK;PFoX$QKG>g{Nij}(dN{IuD9M_XrD^~ zbb?g(`-kgVa=Qd>^Ubf_8Bd9FpkluCgew!wjTzk+imkB?FqneeVRLmmpjp*BiwRn( zx#lh4SHkQ1y4GTJ?J+- zN49aK(Clhgh?8OQ&74iz3&LG5)c2enuA(@9tWRS-JPXhwJ(-hA43W^wu$1|}N_Rch z5m!AW)z{ai*peC*`*SFJ6hf2iVpuGARR@Y5z^`qgx2Wy|a|MYfY#ngT@*JXs&r_4a z3BeC|Hh_#iRCzmbD#p>%~?Ao9wLd)KH1IvMi zA5sC7Il%BFi{RwiuV|krz+r&?Nj{o-BVHnI_zwry^kk>(d2xNG99a7c95(2LXLxm+ z#Q=X#T)~^@d~I9yP_(b6p=Gn;H_9EFE-0cxj@raI^zW|tDE#D*5lXeSj6@5n?9CQd zncA?MfI9RWdPa`-CkBmnTb7w8_ml^acjs1C?@(9)uLkNOf~5dY8!V8Id%DBC+!J^d zHl62Q?H!(!O5d;5WIfZiHyW4+P1`6%wq?jAPR&xWG{2}#1W3FRl(eWHL~(yN;l6w4 zt!7*>7>?R0Zxj@*Pxn!64NarQ6sw1vnQ1d!E&9iBek{oOz7m4ybNI^!B`5}6_gT9v zG4p7`;T>)AWtYTFQ!pm}Uy0u6_d2m^T5I@0l5IPRnp&Uxx`D6A{Q}BgLw2BU{d_?u zuZB&8uep`=wAUl@9Jio46L<_94Iz@fXWb@Bt_dsAT_86^ap>LQiSp<}UHrhboGa;T zxVKQHGph2HL>MPxh~S+~@hyMbEJU#L9VxtwZO`aGAqVbkzFY_q_zyw8+dU(c%O}DP zQ#~?UE8d^JKe=0JVDEu^v|X@!C&;~`W6aw>C_ffywlq9QYB8XH0XJ`6`^4~G+`xj^zk zV0$X@9N&(UMEcx|-%5a%Mn_${h*s6Qlv%=NBEn5k7i_WDkJj^QADF?jPuP3K7V(C$J$%Q; zHhWQnYmm30tOTEFY+ZCu2(|oAX5hF7Z8M5)0m{Z<;seZYu{8J31!#)J<(L~>{mb(D z*59X~P-=)8N)PH97vbjmE4A0C>X5LQju?$FLhXo;-Sj{mlY82>6EW~;iO|pI z6WL>tt7Mz%FORf#&MQKp(i2xfY?muG9(Dd_gnTAnM!ztYSpH+ z-DT$5v%kWM!JskuRZ~OK6!*BU;ti*1E9!2;rs}3f9E^12dik;^%j3I=hUp@=74)b@ zW3ut=*e{_3dK482xLO#x%FwLAwH0!ik$8my(O${2r*u;XAYgczk{JCJ^AdfLiA<3= zKwm28RIzVhba5io0y?0%u;k7*bywN~sf?H$nmS)JBJe&YY^Kg@UY`k%4e(r5Z-VU> zjJoIN9(Fvd8n+0@Yu_~~1%5KIs`MO`Lz^L${y3e-Mw~Q@O zl*B`I^T$cO*xIOn8n?<1chOIl2B{#oV@+qlRrB1d?xM~4M54ZX*G_%xrKgXHI z&JUhH-=Zi_%1=~{dZ(>|TPKghpR(J|6J#YCP9{Lu$*yBWSn^}SfuGUlyhEym!2>bM z&VR9sc+2j(xn%(|ipEdYN=%G`g?H)@<7RWa$=jc(Oob_OhbEHH1^0MCjh3{;qx$w* z`X}w1eQpedvNX-(Mh|UXFIo)I1bzNv@XTsz>xEL}=gU2}KAC_xaZrN%9LyZk%^r6c z?~RD^khbvZv1g#5NTx>}bFeA*GeCeG@!X8HrvHs?odG#G2)?7m4X#>HS{5432ecs8 zH`jVNW;w$yEu_obmKMY!SCIFyAcb!w8;Pn=Hogf!s~;A*Iw9)5ksO+p*R(@jl&y@5ByIGWv`G=Tak~&*v?)xVJ=(fYW#ro~QBiB|qsHLFHWpvX z7laL2RbRHd?hl`_OrIbYWlOGWKCSOFc0(_r?=ocQfjN*2;R4HiP zVndEP>w2R)mhLh}!-glTnuLzvjnzX~;Y;SZ5 z0oQh3Ot*DG|FIX+6xL!?K*^6RSo8j7)QQva&613|)K*SS@q=k+H#eLN!Mu|Lxd80_`uU0cmb$Xm>bfh)`q&IN2$_Ub@jH?fePU0 zwRdQ1#yxcBo7_+f!cS#}!r1~91J2lu$rZ&es8t0hz(y@Vo0|6Lo$0c)TI?}BMLs-oK9;|=di8v)T`9ZfwY7+28R#x;DIIITDo9sdb_f+TDGLroP{{o zEOEfeTtNaByB#*~81*oCx+Iq3{8DES)O;dyfhrox?uzQHbsriULhC3Vd;0y*1e(~8 z(VV^Y+;&otFrpPAh>5S!;#{usM&)RvCZ3?82r2z(?Zz8S*G_lS>OgW{0xvJ{KnapU zoVn!}H-M{; ze-Cbw`iIWQfLu?FSV?i2@`7|exw`M=bjAc`t&D~g=a*vjDgdnO9pt~Fn)Gm~t^tt( zBMGg>o(1F2lT%hnerfOMTd%7=^TcGZYSScqI4l@WjY)5VCJ=WS)S))_8peLKbCQjJ z+9xJmBPOK(%B&ndKuu_e>_WUw+@3;2GhsPL#ch*g+FMD0%;KUu_}tx|Te|c~WFbKrESd{{YbndU+xD72QG|2lt1p!0qD#hLtj*P)LwS9tr~i1*226Ef zd&_g^ofnSN>e?6ZelfVdmA?( zJ?)CE69|U9eLbj&Ie=OF)ka4hG;TDVnlpD$YsHl?UV~h((4+?{K8c;*d6Zq9RY6}J zsjziNLGCT;3eGwiLbEwdK)+o8kc{w zs`Yy`7kuCVRNwwCZU0tNSYr~n>9Tfx`n;dihW{7vFUaUWjrG1A7}lIgyl|$#9wpDo z2tULOv7dPSsNo;h|NV%G*SAp0@pt80kg!R2yBpwQ!Yb##{{9~jIa-0o50t?Icq`1fui2T6Y~r6t(f{X&zqZM7d#T8`s0B^p zGH@K=MD#VoDM4sqWueXND*#3_M5*{JT&12=nSb zgxj|g%fq1fzK%|+=AViFKilUR^UI|{Idv;E!Cg^FDCs4Zfi(X=dL=o|Swc_OPZvy< zL8gF2QAV*n_!ann&BuOBq0$@hrjv48{{j5TcGu_0IXclXV o?}>V`d}OSQ0xEiWeWRYg8DJ6JdTIUpxC@M;teQ-Xlxf)i1JYR{hX4Qo literal 0 HcmV?d00001 diff --git a/vendor/github.com/brianvoe/gofakeit/v7/lookup.go b/vendor/github.com/brianvoe/gofakeit/v7/lookup.go new file mode 100644 index 0000000000..002ef40e8e --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/lookup.go @@ -0,0 +1,516 @@ +package gofakeit + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" + "sync" +) + +// FuncLookups is the primary map array with mapping to all available data +var FuncLookups map[string]Info +var lockFuncLookups sync.Mutex + +// MapParams is the values to pass into a lookup generate +type MapParams map[string]MapParamsValue + +type MapParamsValue []string + +// Info structures fields to better break down what each one generates +type Info struct { + Display string `json:"display"` + Category string `json:"category"` + Description string `json:"description"` + Example string `json:"example"` + Output string `json:"output"` + ContentType string `json:"content_type"` + Params []Param `json:"params"` + Any any `json:"any"` + Generate func(f *Faker, m *MapParams, info *Info) (any, error) `json:"-"` +} + +// Param is a breakdown of param requirements and type definition +type Param struct { + Field string `json:"field"` + Display string `json:"display"` + Type string `json:"type"` + Optional bool `json:"optional"` + Default string `json:"default"` + Options []string `json:"options"` + Description string `json:"description"` +} + +// Field is used for defining what name and function you to generate for file outuputs +type Field struct { + Name string `json:"name"` + Function string `json:"function"` + Params MapParams `json:"params"` +} + +func init() { initLookup() } + +// init will add all the functions to MapLookups +func initLookup() { + addAddressLookup() + addAnimalLookup() + addAppLookup() + addAuthLookup() + addBeerLookup() + addBookLookup() + addCarLookup() + addCelebrityLookup() + addColorLookup() + addCompanyLookup() + addDatabaseSQLLookup() + addDateTimeLookup() + addEmojiLookup() + addErrorLookup() + addFileCSVLookup() + addFileJSONLookup() + addFileLookup() + addFileXMLLookup() + addFinanceLookup() + addFoodLookup() + addGameLookup() + addGenerateLookup() + addHackerLookup() + addHipsterLookup() + addHtmlLookup() + addImageLookup() + addInternetLookup() + addLanguagesLookup() + addLoremLookup() + addMinecraftLookup() + addMiscLookup() + addMovieLookup() + addNumberLookup() + addPaymentLookup() + addPersonLookup() + addProductLookup() + addSchoolLookup() + addSongLookup() + addStringLookup() + addTemplateLookup() + addWeightedLookup() + addWordAdjectiveLookup() + addWordAdverbLookup() + addWordConnectiveLookup() + addWordGeneralLookup() + addWordGrammerLookup() + addWordNounLookup() + addWordPhraseLookup() + addWordPrepositionLookup() + addWordPronounLookup() + addWordSentenceLookup() + addWordVerbLookup() + addWordCommentLookup() + addWordMiscLookup() +} + +// internalFuncLookups is the internal map array with mapping to all available data +var internalFuncLookups map[string]Info = map[string]Info{ + "fields": { + Description: "Example fields for generating csv, json, xml, etc", + Output: "gofakeit.Field", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + function, _ := GetRandomSimpleFunc(f) + return Field{ + Name: function, + Function: function, + }, nil + }, + }, +} + +// NewMapParams will create a new MapParams +func NewMapParams() *MapParams { + return &MapParams{} +} + +// Add will take in a field and value and add it to the map params type +func (m *MapParams) Add(field string, value string) { + _, ok := (*m)[field] + if !ok { + (*m)[field] = []string{value} + return + } + + (*m)[field] = append((*m)[field], value) +} + +// Get will return the array of string from the provided field +func (m *MapParams) Get(field string) []string { + return (*m)[field] +} + +// Size will return the total size of the underlying map +func (m *MapParams) Size() int { + size := 0 + for range *m { + size++ + } + return size +} + +// UnmarshalJSON will unmarshal the json into the []string +func (m *MapParamsValue) UnmarshalJSON(data []byte) error { + // check if the data is an array + // if so, marshal it into m + if data[0] == '[' { + var values []any + err := json.Unmarshal(data, &values) + if err != nil { + return err + } + + // convert the values to array of strings + for _, value := range values { + typeOf := reflect.TypeOf(value).Kind().String() + + if typeOf == "map" { + v, err := json.Marshal(value) + if err != nil { + return err + } + *m = append(*m, string(v)) + } else { + *m = append(*m, fmt.Sprintf("%v", value)) + } + } + return nil + } + + // if not, then convert into a string and add it to m + var s any + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + *m = append(*m, fmt.Sprintf("%v", s)) + return nil +} + +func GetRandomSimpleFunc(f *Faker) (string, Info) { + // Loop through all the functions and add them to a slice + var keys []string + for k, info := range FuncLookups { + // Only grab simple functions + if info.Params == nil { + keys = append(keys, k) + } + } + + // Randomly grab a function from the slice + randomKey := randomString(f, keys) + + // Return the function name and info + return randomKey, FuncLookups[randomKey] +} + +// AddFuncLookup takes a field and adds it to map +func AddFuncLookup(functionName string, info Info) { + if FuncLookups == nil { + FuncLookups = make(map[string]Info) + } + + // Check content type + if info.ContentType == "" { + info.ContentType = "text/plain" + } + + lockFuncLookups.Lock() + FuncLookups[functionName] = info + lockFuncLookups.Unlock() +} + +// GetFuncLookup will lookup +func GetFuncLookup(functionName string) *Info { + var info Info + var ok bool + + // Check internal functions first + info, ok = internalFuncLookups[functionName] + if ok { + return &info + } + + info, ok = FuncLookups[functionName] + if ok { + return &info + } + + return nil +} + +// RemoveFuncLookup will remove a function from lookup +func RemoveFuncLookup(functionName string) { + _, ok := FuncLookups[functionName] + if !ok { + return + } + + lockFuncLookups.Lock() + delete(FuncLookups, functionName) + lockFuncLookups.Unlock() +} + +// GetAny will retrieve Any field from Info +func (i *Info) GetAny(m *MapParams, field string) (any, error) { + _, value, err := i.GetField(m, field) + if err != nil { + return nil, err + } + + // Make sure value[0] exists + if len(value) == 0 { + return nil, fmt.Errorf("could not find field: %s", field) + } + + var anyValue any + + // Try to convert to int + valueInt, err := strconv.ParseInt(value[0], 10, 64) + if err == nil { + return int(valueInt), nil + } + + // Try to convert to float + valueFloat, err := strconv.ParseFloat(value[0], 64) + if err == nil { + return valueFloat, nil + } + + // Try to convert to boolean + valueBool, err := strconv.ParseBool(value[0]) + if err == nil { + return valueBool, nil + } + + err = json.Unmarshal([]byte(value[0]), &anyValue) + if err == nil { + return valueBool, nil + } + + return value[0], nil +} + +// GetMap will retrieve map[string]any field from data +func (i *Info) GetMap(m *MapParams, field string) (map[string]any, error) { + _, value, err := i.GetField(m, field) + if err != nil { + return nil, err + } + + var mapValue map[string]any + err = json.Unmarshal([]byte(value[0]), &mapValue) + if err != nil { + return nil, fmt.Errorf("%s field could not parse to map[string]any", field) + } + + return mapValue, nil +} + +// GetField will retrieve field from data +func (i *Info) GetField(m *MapParams, field string) (*Param, []string, error) { + // Get param + var p *Param + for _, param := range i.Params { + if param.Field == field { + p = ¶m + break + } + } + if p == nil { + return nil, nil, fmt.Errorf("could not find param field %s", field) + } + + // Get value from map + if m != nil { + value, ok := (*m)[field] + if !ok { + // If default isnt empty use default + if p.Default != "" { + return p, []string{p.Default}, nil + } + + return nil, nil, fmt.Errorf("could not find field: %s", field) + } + + return p, value, nil + } else if p.Default != "" { + // If p.Type is []uint, then we need to convert it to []string + if strings.HasPrefix(p.Default, "[") { + // Remove [] from type + defaultClean := p.Default[1 : len(p.Default)-1] + + // Split on comma + defaultSplit := strings.Split(defaultClean, ",") + + return p, defaultSplit, nil + } + + // If default isnt empty use default + return p, []string{p.Default}, nil + } + + return nil, nil, fmt.Errorf("could not find field: %s", field) +} + +// GetBool will retrieve boolean field from data +func (i *Info) GetBool(m *MapParams, field string) (bool, error) { + p, value, err := i.GetField(m, field) + if err != nil { + return false, err + } + + // Try to convert to boolean + valueBool, err := strconv.ParseBool(value[0]) + if err != nil { + return false, fmt.Errorf("%s field could not parse to bool value", p.Field) + } + + return valueBool, nil +} + +// GetInt will retrieve int field from data +func (i *Info) GetInt(m *MapParams, field string) (int, error) { + p, value, err := i.GetField(m, field) + if err != nil { + return 0, err + } + + // Try to convert to int + valueInt, err := strconv.ParseInt(value[0], 10, 64) + if err != nil { + return 0, fmt.Errorf("%s field could not parse to int value", p.Field) + } + + return int(valueInt), nil +} + +// GetUint will retrieve uint field from data +func (i *Info) GetUint(m *MapParams, field string) (uint, error) { + p, value, err := i.GetField(m, field) + if err != nil { + return 0, err + } + + // Try to convert to int + valueUint, err := strconv.ParseUint(value[0], 10, 64) + if err != nil { + return 0, fmt.Errorf("%s field could not parse to int value", p.Field) + } + + return uint(valueUint), nil +} + +// GetFloat32 will retrieve int field from data +func (i *Info) GetFloat32(m *MapParams, field string) (float32, error) { + p, value, err := i.GetField(m, field) + if err != nil { + return 0, err + } + + // Try to convert to float + valueFloat, err := strconv.ParseFloat(value[0], 32) + if err != nil { + return 0, fmt.Errorf("%s field could not parse to float value", p.Field) + } + + return float32(valueFloat), nil +} + +// GetFloat64 will retrieve int field from data +func (i *Info) GetFloat64(m *MapParams, field string) (float64, error) { + p, value, err := i.GetField(m, field) + if err != nil { + return 0, err + } + + // Try to convert to float + valueFloat, err := strconv.ParseFloat(value[0], 64) + if err != nil { + return 0, fmt.Errorf("%s field could not parse to float value", p.Field) + } + + return valueFloat, nil +} + +// GetString will retrieve string field from data +func (i *Info) GetString(m *MapParams, field string) (string, error) { + _, value, err := i.GetField(m, field) + if err != nil { + return "", err + } + + return value[0], nil +} + +// GetStringArray will retrieve []string field from data +func (i *Info) GetStringArray(m *MapParams, field string) ([]string, error) { + _, values, err := i.GetField(m, field) + if err != nil { + return nil, err + } + + return values, nil +} + +// GetIntArray will retrieve []int field from data +func (i *Info) GetIntArray(m *MapParams, field string) ([]int, error) { + _, value, err := i.GetField(m, field) + if err != nil { + return nil, err + } + + var ints []int + for i := 0; i < len(value); i++ { + valueInt, err := strconv.ParseInt(value[i], 10, 64) + if err != nil { + return nil, fmt.Errorf("%s value could not parse to int", value[i]) + } + ints = append(ints, int(valueInt)) + } + + return ints, nil +} + +// GetUintArray will retrieve []uint field from data +func (i *Info) GetUintArray(m *MapParams, field string) ([]uint, error) { + _, value, err := i.GetField(m, field) + if err != nil { + return nil, err + } + + var uints []uint + for i := 0; i < len(value); i++ { + valueUint, err := strconv.ParseUint(value[i], 10, 64) + if err != nil { + return nil, fmt.Errorf("%s value could not parse to uint", value[i]) + } + uints = append(uints, uint(valueUint)) + } + + return uints, nil +} + +// GetFloat32Array will retrieve []float field from data +func (i *Info) GetFloat32Array(m *MapParams, field string) ([]float32, error) { + _, value, err := i.GetField(m, field) + if err != nil { + return nil, err + } + + var floats []float32 + for i := 0; i < len(value); i++ { + valueFloat, err := strconv.ParseFloat(value[i], 32) + if err != nil { + return nil, fmt.Errorf("%s value could not parse to float", value[i]) + } + floats = append(floats, float32(valueFloat)) + } + + return floats, nil +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/lorem.go b/vendor/github.com/brianvoe/gofakeit/v7/lorem.go new file mode 100644 index 0000000000..b4e48f5876 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/lorem.go @@ -0,0 +1,126 @@ +package gofakeit + +import ( + "errors" +) + +// LoremIpsumWord will generate a random word +func LoremIpsumWord() string { return loremIpsumWord(GlobalFaker) } + +// LoremIpsumWord will generate a random word +func (f *Faker) LoremIpsumWord() string { return loremIpsumWord(f) } + +func loremIpsumWord(f *Faker) string { return getRandValue(f, []string{"lorem", "word"}) } + +// LoremIpsumSentence will generate a random sentence +func LoremIpsumSentence(wordCount int) string { + return loremIpsumSentence(GlobalFaker, wordCount) +} + +// LoremIpsumSentence will generate a random sentence +func (f *Faker) LoremIpsumSentence(wordCount int) string { + return loremIpsumSentence(f, wordCount) +} + +func loremIpsumSentence(f *Faker, wordCount int) string { + return sentenceGen(f, wordCount, loremIpsumWord) +} + +// LoremIpsumParagraph will generate a random paragraphGenerator +func LoremIpsumParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return loremIpsumParagraph(GlobalFaker, paragraphCount, sentenceCount, wordCount, separator) +} + +// LoremIpsumParagraph will generate a random paragraphGenerator +func (f *Faker) LoremIpsumParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return loremIpsumParagraph(f, paragraphCount, sentenceCount, wordCount, separator) +} + +func loremIpsumParagraph(f *Faker, paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return paragraphGen(f, paragrapOptions{paragraphCount, sentenceCount, wordCount, separator}, loremIpsumSentence) +} + +func addLoremLookup() { + AddFuncLookup("loremipsumword", Info{ + Display: "Lorem Ipsum Word", + Category: "word", + Description: "Word of the Lorem Ipsum placeholder text used in design and publishing", + Example: "quia", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return loremIpsumWord(f), nil + }, + }) + + AddFuncLookup("loremipsumsentence", Info{ + Display: "Lorem Ipsum Sentence", + Category: "word", + Description: "Sentence of the Lorem Ipsum placeholder text used in design and publishing", + Example: "Quia quae repellat consequatur quidem.", + Output: "string", + Params: []Param{ + {Field: "wordcount", Display: "Word Count", Type: "int", Default: "5", Description: "Number of words in a sentence"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + wordCount, err := info.GetInt(m, "wordcount") + if err != nil { + return nil, err + } + if wordCount <= 0 || wordCount > 50 { + return nil, errors.New("invalid word count, must be greater than 0, less than 50") + } + + return loremIpsumSentence(f, wordCount), nil + }, + }) + + AddFuncLookup("loremipsumparagraph", Info{ + Display: "Lorem Ipsum Paragraph", + Category: "word", + Description: "Paragraph of the Lorem Ipsum placeholder text used in design and publishing", + Example: `Quia quae repellat consequatur quidem nisi quo qui voluptatum accusantium quisquam amet. Quas et ut non dolorem ipsam aut enim assumenda mollitia harum ut. Dicta similique veniam nulla voluptas at excepturi non ad maxime at non. Eaque hic repellat praesentium voluptatem qui consequuntur dolor iusto autem velit aut. Fugit tempore exercitationem harum consequatur voluptatum modi minima aut eaque et et. + +Aut ea voluptatem dignissimos expedita odit tempore quod aut beatae ipsam iste. Minus voluptatibus dolorem maiores eius sed nihil vel enim odio voluptatem accusamus. Natus quibusdam temporibus tenetur cumque sint necessitatibus dolorem ex ducimus iusto ex. Voluptatem neque dicta explicabo officiis et ducimus sit ut ut praesentium pariatur. Illum molestias nisi at dolore ut voluptatem accusantium et fugiat et ut. + +Explicabo incidunt reprehenderit non quia dignissimos recusandae vitae soluta quia et quia. Aut veniam voluptas consequatur placeat sapiente non eveniet voluptatibus magni velit eum. Nobis vel repellendus sed est qui autem laudantium quidem quam ullam consequatur. Aut iusto ut commodi similique quae voluptatem atque qui fugiat eum aut. Quis distinctio consequatur voluptatem vel aliquid aut laborum facere officiis iure tempora.`, + Output: "string", + Params: []Param{ + {Field: "paragraphcount", Display: "Paragraph Count", Type: "int", Default: "2", Description: "Number of paragraphs"}, + {Field: "sentencecount", Display: "Sentence Count", Type: "int", Default: "2", Description: "Number of sentences in a paragraph"}, + {Field: "wordcount", Display: "Word Count", Type: "int", Default: "5", Description: "Number of words in a sentence"}, + {Field: "paragraphseparator", Display: "Paragraph Separator", Type: "string", Default: "
", Description: "String value to add between paragraphs"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + paragraphCount, err := info.GetInt(m, "paragraphcount") + if err != nil { + return nil, err + } + if paragraphCount <= 0 || paragraphCount > 20 { + return nil, errors.New("invalid paragraph count, must be greater than 0, less than 20") + } + + sentenceCount, err := info.GetInt(m, "sentencecount") + if err != nil { + return nil, err + } + if sentenceCount <= 0 || sentenceCount > 20 { + return nil, errors.New("invalid sentence count, must be greater than 0, less than 20") + } + + wordCount, err := info.GetInt(m, "wordcount") + if err != nil { + return nil, err + } + if wordCount <= 0 || wordCount > 50 { + return nil, errors.New("invalid word count, must be greater than 0, less than 50") + } + + paragraphSeparator, err := info.GetString(m, "paragraphseparator") + if err != nil { + return nil, err + } + + return loremIpsumParagraph(f, paragraphCount, sentenceCount, wordCount, paragraphSeparator), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/minecraft.go b/vendor/github.com/brianvoe/gofakeit/v7/minecraft.go new file mode 100644 index 0000000000..5e5efa2013 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/minecraft.go @@ -0,0 +1,365 @@ +package gofakeit + +// MinecraftOre will generate a random Minecraft ore +func MinecraftOre() string { return minecraftOre(GlobalFaker) } + +// MinecraftOre will generate a random Minecraft ore +func (f *Faker) MinecraftOre() string { return minecraftOre(f) } + +func minecraftOre(f *Faker) string { return getRandValue(f, []string{"minecraft", "ore"}) } + +// MinecraftWood will generate a random Minecraft wood +func MinecraftWood() string { return minecraftWood(GlobalFaker) } + +// MinecraftWood will generate a random Minecraft wood +func (f *Faker) MinecraftWood() string { return minecraftWood(f) } + +func minecraftWood(f *Faker) string { return getRandValue(f, []string{"minecraft", "wood"}) } + +// MinecraftArmorTier will generate a random Minecraft armor tier +func MinecraftArmorTier() string { return minecraftArmorTier(GlobalFaker) } + +// MinecraftArmorTier will generate a random Minecraft armor tier +func (f *Faker) MinecraftArmorTier() string { return minecraftArmorTier(f) } + +func minecraftArmorTier(f *Faker) string { + return getRandValue(f, []string{"minecraft", "armortier"}) +} + +// MinecraftArmorPart will generate a random Minecraft armor part +func MinecraftArmorPart() string { return minecraftArmorPart(GlobalFaker) } + +// MinecraftArmorPart will generate a random Minecraft armor part +func (f *Faker) MinecraftArmorPart() string { return minecraftArmorPart(f) } + +func minecraftArmorPart(f *Faker) string { + return getRandValue(f, []string{"minecraft", "armorpart"}) +} + +// MinecraftWeapon will generate a random Minecraft weapon +func MinecraftWeapon() string { return minecraftWeapon(GlobalFaker) } + +// MinecraftWeapon will generate a random Minecraft weapon +func (f *Faker) MinecraftWeapon() string { return minecraftWeapon(f) } + +func minecraftWeapon(f *Faker) string { return getRandValue(f, []string{"minecraft", "weapon"}) } + +// MinecraftTool will generate a random Minecraft tool +func MinecraftTool() string { return minecraftTool(GlobalFaker) } + +// MinecraftTool will generate a random Minecraft tool +func (f *Faker) MinecraftTool() string { return minecraftTool(f) } + +func minecraftTool(f *Faker) string { return getRandValue(f, []string{"minecraft", "tool"}) } + +// MinecraftDye will generate a random Minecraft dye +func MinecraftDye() string { return minecraftDye(GlobalFaker) } + +// MinecraftDye will generate a random Minecraft dye +func (f *Faker) MinecraftDye() string { return minecraftDye(f) } + +func minecraftDye(f *Faker) string { return getRandValue(f, []string{"minecraft", "dye"}) } + +// MinecraftFood will generate a random Minecraft food +func MinecraftFood() string { return minecraftFood(GlobalFaker) } + +// MinecraftFood will generate a random Minecraft food +func (f *Faker) MinecraftFood() string { return minecraftFood(f) } + +func minecraftFood(f *Faker) string { return getRandValue(f, []string{"minecraft", "food"}) } + +// MinecraftAnimal will generate a random Minecraft animal +func MinecraftAnimal() string { return minecraftAnimal(GlobalFaker) } + +// MinecraftAnimal will generate a random Minecraft animal +func (f *Faker) MinecraftAnimal() string { return minecraftAnimal(f) } + +func minecraftAnimal(f *Faker) string { + return getRandValue(f, []string{"minecraft", "animal"}) +} + +// MinecraftVillagerJob will generate a random Minecraft villager job +func MinecraftVillagerJob() string { return minecraftVillagerJob(GlobalFaker) } + +// MinecraftVillagerJob will generate a random Minecraft villager job +func (f *Faker) MinecraftVillagerJob() string { return minecraftVillagerJob(f) } + +func minecraftVillagerJob(f *Faker) string { + return getRandValue(f, []string{"minecraft", "villagerjob"}) +} + +// MinecraftVillagerStation will generate a random Minecraft villager station +func MinecraftVillagerStation() string { return minecraftVillagerStation(GlobalFaker) } + +// MinecraftVillagerStation will generate a random Minecraft villager station +func (f *Faker) MinecraftVillagerStation() string { return minecraftVillagerStation(f) } + +func minecraftVillagerStation(f *Faker) string { + return getRandValue(f, []string{"minecraft", "villagerstation"}) +} + +// MinecraftVillagerLevel will generate a random Minecraft villager level +func MinecraftVillagerLevel() string { return minecraftVillagerLevel(GlobalFaker) } + +// MinecraftVillagerLevel will generate a random Minecraft villager level +func (f *Faker) MinecraftVillagerLevel() string { return minecraftVillagerLevel(f) } + +func minecraftVillagerLevel(f *Faker) string { + return getRandValue(f, []string{"minecraft", "villagerlevel"}) +} + +// MinecraftMobPassive will generate a random Minecraft mob passive +func MinecraftMobPassive() string { return minecraftMobPassive(GlobalFaker) } + +// MinecraftMobPassive will generate a random Minecraft mob passive +func (f *Faker) MinecraftMobPassive() string { return minecraftMobPassive(f) } + +func minecraftMobPassive(f *Faker) string { + return getRandValue(f, []string{"minecraft", "mobpassive"}) +} + +// MinecraftMobNeutral will generate a random Minecraft mob neutral +func MinecraftMobNeutral() string { return minecraftMobNeutral(GlobalFaker) } + +// MinecraftMobNeutral will generate a random Minecraft mob neutral +func (f *Faker) MinecraftMobNeutral() string { return minecraftMobNeutral(f) } + +func minecraftMobNeutral(f *Faker) string { + return getRandValue(f, []string{"minecraft", "mobneutral"}) +} + +// MinecraftMobHostile will generate a random Minecraft mob hostile +func MinecraftMobHostile() string { return minecraftMobHostile(GlobalFaker) } + +// MinecraftMobHostile will generate a random Minecraft mob hostile +func (f *Faker) MinecraftMobHostile() string { return minecraftMobHostile(f) } + +func minecraftMobHostile(f *Faker) string { + return getRandValue(f, []string{"minecraft", "mobhostile"}) +} + +// MinecraftMobBoss will generate a random Minecraft mob boss +func MinecraftMobBoss() string { return minecraftMobBoss(GlobalFaker) } + +// MinecraftMobBoss will generate a random Minecraft mob boss +func (f *Faker) MinecraftMobBoss() string { return minecraftMobBoss(f) } + +func minecraftMobBoss(f *Faker) string { + return getRandValue(f, []string{"minecraft", "mobboss"}) +} + +// MinecraftBiome will generate a random Minecraft biome +func MinecraftBiome() string { return minecraftBiome(GlobalFaker) } + +// MinecraftBiome will generate a random Minecraft biome +func (f *Faker) MinecraftBiome() string { return minecraftBiome(f) } + +func minecraftBiome(f *Faker) string { return getRandValue(f, []string{"minecraft", "biome"}) } + +// MinecraftWeather will generate a random Minecraft weather +func MinecraftWeather() string { return minecraftWeather(GlobalFaker) } + +// MinecraftWeather will generate a random Minecraft weather +func (f *Faker) MinecraftWeather() string { return minecraftWeather(f) } + +func minecraftWeather(f *Faker) string { return getRandValue(f, []string{"minecraft", "weather"}) } + +func addMinecraftLookup() { + AddFuncLookup("minecraftore", Info{ + Display: "Minecraft ore", + Category: "minecraft", + Description: "Naturally occurring minerals found in the game Minecraft, used for crafting purposes", + Example: "coal", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftOre(f), nil + }, + }) + + AddFuncLookup("minecraftwood", Info{ + Display: "Minecraft wood", + Category: "minecraft", + Description: "Natural resource in Minecraft, used for crafting various items and building structures", + Example: "oak", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftWood(f), nil + }, + }) + + AddFuncLookup("minecraftarmortier", Info{ + Display: "Minecraft armor tier", + Category: "minecraft", + Description: "Classification system for armor sets in Minecraft, indicating their effectiveness and protection level", + Example: "iron", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftArmorTier(f), nil + }, + }) + + AddFuncLookup("minecraftarmorpart", Info{ + Display: "Minecraft armor part", + Category: "minecraft", + Description: "Component of an armor set in Minecraft, such as a helmet, chestplate, leggings, or boots", + Example: "helmet", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftArmorPart(f), nil + }, + }) + + AddFuncLookup("minecraftweapon", Info{ + Display: "Minecraft weapon", + Category: "minecraft", + Description: "Tools and items used in Minecraft for combat and defeating hostile mobs", + Example: "bow", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftWeapon(f), nil + }, + }) + + AddFuncLookup("minecrafttool", Info{ + Display: "Minecraft tool", + Category: "minecraft", + Description: "Items in Minecraft designed for specific tasks, including mining, digging, and building", + Example: "shovel", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftTool(f), nil + }, + }) + + AddFuncLookup("minecraftdye", Info{ + Display: "Minecraft dye", + Category: "minecraft", + Description: "Items used to change the color of various in-game objects", + Example: "white", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftDye(f), nil + }, + }) + + AddFuncLookup("minecraftfood", Info{ + Display: "Minecraft food", + Category: "minecraft", + Description: "Consumable items in Minecraft that provide nourishment to the player character", + Example: "apple", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftFood(f), nil + }, + }) + + AddFuncLookup("minecraftanimal", Info{ + Display: "Minecraft animal", + Category: "minecraft", + Description: "Non-hostile creatures in Minecraft, often used for resources and farming", + Example: "chicken", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftAnimal(f), nil + }, + }) + + AddFuncLookup("minecraftvillagerjob", Info{ + Display: "Minecraft villager job", + Category: "minecraft", + Description: "The profession or occupation assigned to a villager character in the game", + Example: "farmer", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftVillagerJob(f), nil + }, + }) + + AddFuncLookup("minecraftvillagerstation", Info{ + Display: "Minecraft villager station", + Category: "minecraft", + Description: "Designated area or structure in Minecraft where villagers perform their job-related tasks and trading", + Example: "furnace", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftVillagerStation(f), nil + }, + }) + + AddFuncLookup("minecraftvillagerlevel", Info{ + Display: "Minecraft villager level", + Category: "minecraft", + Description: "Measure of a villager's experience and proficiency in their assigned job or profession", + Example: "master", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftVillagerLevel(f), nil + }, + }) + + AddFuncLookup("minecraftmobpassive", Info{ + Display: "Minecraft mob passive", + Category: "minecraft", + Description: "Non-aggressive creatures in the game that do not attack players", + Example: "cow", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftMobPassive(f), nil + }, + }) + + AddFuncLookup("minecraftmobneutral", Info{ + Display: "Minecraft mob neutral", + Category: "minecraft", + Description: "Creature in the game that only becomes hostile if provoked, typically defending itself when attacked", + Example: "bee", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftMobNeutral(f), nil + }, + }) + + AddFuncLookup("minecraftmobhostile", Info{ + Display: "Minecraft mob hostile", + Category: "minecraft", + Description: "Aggressive creatures in the game that actively attack players when encountered", + Example: "spider", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftMobHostile(f), nil + }, + }) + + AddFuncLookup("minecraftmobboss", Info{ + Display: "Minecraft mob boss", + Category: "minecraft", + Description: "Powerful hostile creature in the game, often found in challenging dungeons or structures", + Example: "ender dragon", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftMobBoss(f), nil + }, + }) + + AddFuncLookup("minecraftbiome", Info{ + Display: "Minecraft biome", + Category: "minecraft", + Description: "Distinctive environmental regions in the game, characterized by unique terrain, vegetation, and weather", + Example: "forest", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftBiome(f), nil + }, + }) + + AddFuncLookup("minecraftweather", Info{ + Display: "Minecraft weather", + Category: "minecraft", + Description: "Atmospheric conditions in the game that include rain, thunderstorms, and clear skies, affecting gameplay and ambiance", + Example: "rain", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minecraftWeather(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/misc.go b/vendor/github.com/brianvoe/gofakeit/v7/misc.go new file mode 100644 index 0000000000..b40ba1efc6 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/misc.go @@ -0,0 +1,164 @@ +package gofakeit + +import ( + "encoding/hex" + "reflect" + + "github.com/brianvoe/gofakeit/v7/data" +) + +// Bool will generate a random boolean value +func Bool() bool { return boolFunc(GlobalFaker) } + +// Bool will generate a random boolean value +func (f *Faker) Bool() bool { return boolFunc(f) } + +func boolFunc(f *Faker) bool { return randIntRange(f, 0, 1) == 1 } + +// UUID (version 4) will generate a random unique identifier based upon random numbers +// Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +func UUID() string { return uuid(GlobalFaker) } + +// UUID (version 4) will generate a random unique identifier based upon random numbers +// Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 8-4-4-4-12 +func (f *Faker) UUID() string { return uuid(f) } + +func uuid(f *Faker) string { + version := byte(4) + uuid := make([]byte, 16) + + // Read 16 random bytes + for i := 0; i < 16; i++ { + uuid[i] = byte(f.IntN(256)) + } + + // Set version + uuid[6] = (uuid[6] & 0x0f) | (version << 4) + + // Set variant + uuid[8] = (uuid[8] & 0xbf) | 0x80 + + buf := make([]byte, 36) + hex.Encode(buf[0:8], uuid[0:4]) + buf[8] = dash + hex.Encode(buf[9:13], uuid[4:6]) + buf[13] = dash + hex.Encode(buf[14:18], uuid[6:8]) + buf[18] = dash + hex.Encode(buf[19:23], uuid[8:10]) + buf[23] = dash + hex.Encode(buf[24:], uuid[10:]) + + return string(buf) +} + +// ShuffleAnySlice takes in a slice and outputs it in a random order +func ShuffleAnySlice(v any) { shuffleAnySlice(GlobalFaker, v) } + +// ShuffleAnySlice takes in a slice and outputs it in a random order +func (f *Faker) ShuffleAnySlice(v any) { shuffleAnySlice(f, v) } + +func shuffleAnySlice(f *Faker, v any) { + if v == nil { + return + } + + // Check type of passed in value, if not a slice return with no action taken + typ := reflect.TypeOf(v) + if typ.Kind() != reflect.Slice { + return + } + + s := reflect.ValueOf(v) + n := s.Len() + + if n <= 1 { + return + } + + swap := func(i, j int) { + tmp := reflect.ValueOf(s.Index(i).Interface()) + s.Index(i).Set(s.Index(j)) + s.Index(j).Set(tmp) + } + + //if size is > int32 probably it will never finish, or ran out of entropy + i := n - 1 + for ; i > 0; i-- { + j := int(int32NFunc(f, int32(i+1))) + swap(i, j) + } +} + +// FlipACoin will return a random value of Heads or Tails +func FlipACoin() string { return flipACoin(GlobalFaker) } + +// FlipACoin will return a random value of Heads or Tails +func (f *Faker) FlipACoin() string { return flipACoin(f) } + +func flipACoin(f *Faker) string { + if boolFunc(f) { + return "Heads" + } + + return "Tails" +} + +// RandomMapKey will return a random key from a map +func RandomMapKey(mapI any) any { return randomMapKey(GlobalFaker, mapI) } + +// RandomMapKey will return a random key from a map +func (f *Faker) RandomMapKey(mapI any) any { return randomMapKey(f, mapI) } + +func randomMapKey(f *Faker, mapI any) any { + keys := reflect.ValueOf(mapI).MapKeys() + return keys[f.IntN(len(keys))].Interface() +} + +// Categories will return a map string array of available data categories and sub categories +func Categories() map[string][]string { + types := make(map[string][]string) + for category, subCategoriesMap := range data.Data { + subCategories := make([]string, 0) + for subType := range subCategoriesMap { + subCategories = append(subCategories, subType) + } + types[category] = subCategories + } + return types +} + +func addMiscLookup() { + AddFuncLookup("uuid", Info{ + Display: "UUID", + Category: "misc", + Description: "128-bit identifier used to uniquely identify objects or entities in computer systems", + Example: "590c1440-9888-45b0-bd51-a817ee07c3f2", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return uuid(f), nil + }, + }) + + AddFuncLookup("bool", Info{ + Display: "Boolean", + Category: "misc", + Description: "Data type that represents one of two possible values, typically true or false", + Example: "true", + Output: "bool", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return boolFunc(f), nil + }, + }) + + AddFuncLookup("flipacoin", Info{ + Display: "Flip A Coin", + Category: "misc", + Description: "Decision-making method involving the tossing of a coin to determine outcomes", + Example: "Tails", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return flipACoin(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/movie.go b/vendor/github.com/brianvoe/gofakeit/v7/movie.go new file mode 100644 index 0000000000..27199cd682 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/movie.go @@ -0,0 +1,68 @@ +package gofakeit + +func MovieName() string { return movieName(GlobalFaker) } + +func (f *Faker) MovieName() string { return movieName(f) } + +func movieName(f *Faker) string { return getRandValue(f, []string{"movie", "name"}) } + +func MovieGenre() string { return movieGenre(GlobalFaker) } + +func (f *Faker) MovieGenre() string { return movieGenre(f) } + +func movieGenre(f *Faker) string { return getRandValue(f, []string{"movie", "genre"}) } + +type MovieInfo struct { + Name string `json:"name" xml:"name"` + Genre string `json:"genre" xml:"genre"` +} + +func Movie() *MovieInfo { return movie(GlobalFaker) } + +func (f *Faker) Movie() *MovieInfo { return movie(f) } + +func movie(f *Faker) *MovieInfo { + return &MovieInfo{ + Name: movieName(f), + Genre: movieGenre(f), + } +} + +func addMovieLookup() { + AddFuncLookup("movie", Info{ + Display: "Movie", + Category: "movie", + Description: "A story told through moving pictures and sound", + Example: `{ + "name": "Psycho", + "genre": "Mystery" +}`, + Output: "map[string]string", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return movie(f), nil + }, + }) + + AddFuncLookup("moviename", Info{ + Display: "Movie Name", + Category: "movie", + Description: "Title or name of a specific film used for identification and reference", + Example: "The Matrix", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return movieName(f), nil + }, + }) + + AddFuncLookup("moviegenre", Info{ + Display: "Genre", + Category: "movie", + Description: "Category that classifies movies based on common themes, styles, and storytelling approaches", + Example: "Action", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return movieGenre(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/number.go b/vendor/github.com/brianvoe/gofakeit/v7/number.go new file mode 100644 index 0000000000..e4cdfb9cc5 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/number.go @@ -0,0 +1,703 @@ +package gofakeit + +import ( + "math" + "math/bits" +) + +// Number will generate a random number between given min and max +func Number(min int, max int) int { return number(GlobalFaker, min, max) } + +// Number will generate a random number between given min and max +func (f *Faker) Number(min int, max int) int { return number(f, min, max) } + +func number(f *Faker, min int, max int) int { return randIntRange(f, min, max) } + +// Uint will generate a random uint value +func Uint() uint { return uintFunc(GlobalFaker) } + +// Uint will generate a random uint value +func (f *Faker) Uint() uint { return uintFunc(f) } + +func uintFunc(f *Faker) uint { return uint(f.Uint64()) } + +// UintN will generate a random uint value between 0 and n +func UintN(n uint) uint { return uintNFunc(GlobalFaker, n) } + +// UintN will generate a random uint value between 0 and n +func (f *Faker) UintN(n uint) uint { return uintNFunc(f, n) } + +func uintNFunc(f *Faker, n uint) uint { + if n == 0 { + return 0 + } + return uint(uint64NFunc(f, uint64(n))) +} + +// Uint8 will generate a random uint8 value +func Uint8() uint8 { return uint8Func(GlobalFaker) } + +// Uint8 will generate a random uint8 value +func (f *Faker) Uint8() uint8 { return uint8Func(f) } + +func uint8Func(f *Faker) uint8 { return uint8(randIntRange(f, minUint, math.MaxUint8)) } + +// Uint16 will generate a random uint16 value +func Uint16() uint16 { return uint16Func(GlobalFaker) } + +// Uint16 will generate a random uint16 value +func (f *Faker) Uint16() uint16 { return uint16Func(f) } + +func uint16Func(f *Faker) uint16 { return uint16(randIntRange(f, minUint, math.MaxUint16)) } + +// Uint32 will generate a random uint32 value +func Uint32() uint32 { return uint32Func(GlobalFaker) } + +// Uint32 will generate a random uint32 value +func (f *Faker) Uint32() uint32 { return uint32Func(f) } + +func uint32Func(f *Faker) uint32 { return uint32(f.Uint64() >> 32) } + +// Uint64 will generate a random uint64 value +func Uint64() uint64 { return GlobalFaker.Uint64() } + +// Uint64 will generate a random uint64 value +// This is the primary location in which the random number is generated. +// This will be the only location in which reading from Rand.Uint64() is lockable +func (f *Faker) Uint64() uint64 { + // Check if the source is locked + if f.Locked { + // Lock the source + f.mu.Lock() + defer f.mu.Unlock() + } + + return f.Rand.Uint64() +} + +// uint64n is the no-bounds-checks version of Uint64N. +// See https://cs.opensource.google/go/go/+/refs/tags/go1.22.0:src/math/rand/v2/rand.go;l=78 +// hidden as to not clutter with additional N functions +func uint64NFunc(f *Faker, n uint64) uint64 { + if is32bit && uint64(uint32(n)) == n { + // create reusable function here + uint32NFunc := func(f *Faker, n uint32) uint32 { + if n&(n-1) == 0 { // n is power of two, can mask + return uint32(f.Uint64()) & (n - 1) + } + + x := f.Uint64() + lo1a, lo0 := bits.Mul32(uint32(x), n) + hi, lo1b := bits.Mul32(uint32(x>>32), n) + lo1, c := bits.Add32(lo1a, lo1b, 0) + hi += c + if lo1 == 0 && lo0 < uint32(n) { + n64 := uint64(n) + thresh := uint32(-n64 % n64) + for lo1 == 0 && lo0 < thresh { + x := f.Uint64() + lo1a, lo0 = bits.Mul32(uint32(x), n) + hi, lo1b = bits.Mul32(uint32(x>>32), n) + lo1, c = bits.Add32(lo1a, lo1b, 0) + hi += c + } + } + return hi + } + + return uint64(uint32NFunc(f, uint32(n))) + } + if n&(n-1) == 0 { // n is power of two, can mask + return f.Uint64() & (n - 1) + } + + hi, lo := bits.Mul64(f.Uint64(), n) + if lo < n { + thresh := -n % n + for lo < thresh { + hi, lo = bits.Mul64(f.Uint64(), n) + } + } + return hi +} + +// UintRange will generate a random uint value between min and max +func UintRange(min, max uint) uint { return uintRangeFunc(GlobalFaker, min, max) } + +// UintRange will generate a random uint value between min and max +func (f *Faker) UintRange(min, max uint) uint { return uintRangeFunc(f, min, max) } + +func uintRangeFunc(f *Faker, min, max uint) uint { return randUintRange(f, min, max) } + +// Int will generate a random int value +func Int() int { return intFunc(GlobalFaker) } + +// Int will generate a random int value +func (f *Faker) Int() int { return intFunc(f) } + +func intFunc(f *Faker) int { return int(uint(f.Uint64()) << 1 >> 1) } + +// IntN will generate a random int value between 0 and n +func IntN(n int) int { return intNFunc(GlobalFaker, n) } + +// IntN will generate a random int value between 0 and n +func (f *Faker) IntN(n int) int { return intNFunc(f, n) } + +func intNFunc(f *Faker, n int) int { + if n <= 0 { + return 0 + } + return int(uint64NFunc(f, uint64(n))) +} + +// Int8 will generate a random Int8 value +func Int8() int8 { return int8Func(GlobalFaker) } + +// Int8 will generate a random Int8 value +func (f *Faker) Int8() int8 { return int8Func(f) } + +func int8Func(f *Faker) int8 { return int8(randIntRange(f, math.MinInt8, math.MaxInt8)) } + +// Int16 will generate a random int16 value +func Int16() int16 { return int16Func(GlobalFaker) } + +// Int16 will generate a random int16 value +func (f *Faker) Int16() int16 { return int16Func(f) } + +func int16Func(f *Faker) int16 { return int16(randIntRange(f, math.MinInt16, math.MaxInt16)) } + +// Int32 will generate a random int32 value +func Int32() int32 { return int32Func(GlobalFaker) } + +// Int32 will generate a random int32 value +func (f *Faker) Int32() int32 { return int32Func(f) } + +func int32Func(f *Faker) int32 { return int32(f.Uint64() >> 33) } + +// int32n is an identical computation to int64n +// hidden as to not clutter with additional N functions +func int32NFunc(f *Faker, n int32) int32 { + if n <= 0 { + return 0 + } + return int32(uint64NFunc(f, uint64(n))) +} + +// Int64 will generate a random int64 value +func Int64() int64 { return int64Func(GlobalFaker) } + +// Int64 will generate a random int64 value +func (f *Faker) Int64() int64 { return int64Func(f) } + +func int64Func(f *Faker) int64 { return int64(f.Uint64() &^ (1 << 63)) } + +// IntRange will generate a random int value between min and max +func IntRange(min, max int) int { return intRangeFunc(GlobalFaker, min, max) } + +// IntRange will generate a random int value between min and max +func (f *Faker) IntRange(min, max int) int { return intRangeFunc(f, min, max) } + +func intRangeFunc(f *Faker, min, max int) int { return randIntRange(f, min, max) } + +// Float32 will generate a random float32 value +func Float32() float32 { return float32Func(GlobalFaker) } + +// Float32 will generate a random float32 value +func (f *Faker) Float32() float32 { return float32Func(f) } + +func float32Func(f *Faker) float32 { + // There are exactly 1<<24 float32s in [0,1). Use Intn(1<<24) / (1<<24). + return float32(f.Uint32()<<8>>8) / (1 << 24) +} + +// Float32Range will generate a random float32 value between min and max +func Float32Range(min, max float32) float32 { + return float32Range(GlobalFaker, min, max) +} + +// Float32Range will generate a random float32 value between min and max +func (f *Faker) Float32Range(min, max float32) float32 { + return float32Range(f, min, max) +} + +func float32Range(f *Faker, min, max float32) float32 { + if min == max { + return min + } + return f.Float32()*(max-min) + min +} + +// Float64 will generate a random float64 value +func Float64() float64 { + return float64Func(GlobalFaker) +} + +// Float64 will generate a random float64 value +func (f *Faker) Float64() float64 { + return float64Func(f) +} + +func float64Func(f *Faker) float64 { + // There are exactly 1<<53 float64s in [0,1). Use Intn(1<<53) / (1<<53). + return float64(f.Uint64()<<11>>11) / (1 << 53) +} + +// Float64Range will generate a random float64 value between min and max +func Float64Range(min, max float64) float64 { + return float64Range(GlobalFaker, min, max) +} + +// Float64Range will generate a random float64 value between min and max +func (f *Faker) Float64Range(min, max float64) float64 { + return float64Range(f, min, max) +} + +func float64Range(f *Faker, min, max float64) float64 { + if min == max { + return min + } + return f.Float64()*(max-min) + min +} + +// ShuffleInts will randomize a slice of ints +func ShuffleInts(a []int) { shuffleInts(GlobalFaker, a) } + +// ShuffleInts will randomize a slice of ints +func (f *Faker) ShuffleInts(a []int) { shuffleInts(f, a) } + +func shuffleInts(f *Faker, a []int) { + for i := range a { + j := f.IntN(i + 1) + a[i], a[j] = a[j], a[i] + } +} + +// RandomInt will take in a slice of int and return a randomly selected value +func RandomInt(i []int) int { return randomInt(GlobalFaker, i) } + +// RandomInt will take in a slice of int and return a randomly selected value +func (f *Faker) RandomInt(i []int) int { return randomInt(f, i) } + +func randomInt(f *Faker, i []int) int { + size := len(i) + if size == 0 { + return 0 + } + if size == 1 { + return i[0] + } + return i[f.IntN(size)] +} + +// RandomUint will take in a slice of uint and return a randomly selected value +func RandomUint(u []uint) uint { return randomUint(GlobalFaker, u) } + +// RandomUint will take in a slice of uint and return a randomly selected value +func (f *Faker) RandomUint(u []uint) uint { return randomUint(f, u) } + +func randomUint(f *Faker, u []uint) uint { + size := len(u) + if size == 0 { + return 0 + } + if size == 1 { + return u[0] + } + return u[f.IntN(size)] +} + +// HexUint will generate a random uint hex value with "0x" prefix +func HexUint(bitSize int) string { return hexUint(GlobalFaker, bitSize) } + +// HexUint will generate a random uint hex value with "0x" prefix +func (f *Faker) HexUint(bitSize int) string { return hexUint(f, bitSize) } + +func hexUint(f *Faker, bitSize int) string { + digits := []byte("0123456789abcdef") + hexLen := (bitSize >> 2) + 2 + if hexLen <= 2 { + return "0x" + } + + s := make([]byte, hexLen) + s[0], s[1] = '0', 'x' + for i := 2; i < hexLen; i++ { + s[i] = digits[f.IntN(16)] + } + return string(s) +} + +func addNumberLookup() { + AddFuncLookup("number", Info{ + Display: "Number", + Category: "number", + Description: "Mathematical concept used for counting, measuring, and expressing quantities or values", + Example: "14866", + Output: "int", + Params: []Param{ + {Field: "min", Display: "Min", Type: "int", Default: "-2147483648", Description: "Minimum integer value"}, + {Field: "max", Display: "Max", Type: "int", Default: "2147483647", Description: "Maximum integer value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetInt(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetInt(m, "max") + if err != nil { + return nil, err + } + + return number(f, min, max), nil + }, + }) + + AddFuncLookup("uint", Info{ + Display: "Uint", + Category: "number", + Description: "Unsigned integer", + Example: "14866", + Output: "uint", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return uintFunc(f), nil + }, + }) + + AddFuncLookup("uintn", Info{ + Display: "UintN", + Category: "number", + Description: "Unsigned integer between 0 and n", + Example: "32783", + Output: "uint", + Params: []Param{ + {Field: "n", Display: "N", Type: "uint", Default: "4294967295", Description: "Maximum uint value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + n, err := info.GetUint(m, "n") + if err != nil { + return nil, err + } + + return uintNFunc(f, n), nil + }, + }) + + AddFuncLookup("uint8", Info{ + Display: "Uint8", + Category: "number", + Description: "Unsigned 8-bit integer, capable of representing values from 0 to 255", + Example: "152", + Output: "uint8", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return uint8Func(f), nil + }, + }) + + AddFuncLookup("uint16", Info{ + Display: "Uint16", + Category: "number", + Description: "Unsigned 16-bit integer, capable of representing values from 0 to 65,535", + Example: "34968", + Output: "uint16", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return uint16Func(f), nil + }, + }) + + AddFuncLookup("uint32", Info{ + Display: "Uint32", + Category: "number", + Description: "Unsigned 32-bit integer, capable of representing values from 0 to 4,294,967,295", + Example: "1075055705", + Output: "uint32", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return uint32Func(f), nil + }, + }) + + AddFuncLookup("uint64", Info{ + Display: "Uint64", + Category: "number", + Description: "Unsigned 64-bit integer, capable of representing values from 0 to 18,446,744,073,709,551,615", + Example: "843730692693298265", + Output: "uint64", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return f.Uint64(), nil + }, + }) + + AddFuncLookup("uintrange", Info{ + Display: "UintRange", + Category: "number", + Description: "Non-negative integer value between given range", + Example: "1075055705", + Output: "uint", + Params: []Param{ + {Field: "min", Display: "Min", Type: "uint", Default: "0", Description: "Minimum uint value"}, + {Field: "max", Display: "Max", Type: "uint", Default: "4294967295", Description: "Maximum uint value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetUint(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetUint(m, "max") + if err != nil { + return nil, err + } + + return uintRangeFunc(f, min, max), nil + }, + }) + + AddFuncLookup("int", Info{ + Display: "Int", + Category: "number", + Description: "Signed integer", + Example: "14866", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return intFunc(f), nil + }, + }) + + AddFuncLookup("intn", Info{ + Display: "IntN", + Category: "number", + Description: "Integer value between 0 and n", + Example: "32783", + Output: "int", + Params: []Param{ + {Field: "n", Display: "N", Type: "int", Default: "2147483647", Description: "Maximum int value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + n, err := info.GetInt(m, "n") + if err != nil { + return nil, err + } + + return intNFunc(f, n), nil + }, + }) + + AddFuncLookup("int8", Info{ + Display: "Int8", + Category: "number", + Description: "Signed 8-bit integer, capable of representing values from -128 to 127", + Example: "24", + Output: "int8", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return int8Func(f), nil + }, + }) + + AddFuncLookup("int16", Info{ + Display: "Int16", + Category: "number", + Description: "Signed 16-bit integer, capable of representing values from 32,768 to 32,767", + Example: "2200", + Output: "int16", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return int16Func(f), nil + }, + }) + + AddFuncLookup("int32", Info{ + Display: "Int32", + Category: "number", + Description: "Signed 32-bit integer, capable of representing values from -2,147,483,648 to 2,147,483,647", + Example: "-1072427943", + Output: "int32", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return int32Func(f), nil + }, + }) + + AddFuncLookup("int64", Info{ + Display: "Int64", + Category: "number", + Description: "Signed 64-bit integer, capable of representing values from -9,223,372,036,854,775,808 to -9,223,372,036,854,775,807", + Example: "-8379641344161477543", + Output: "int64", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return int64Func(f), nil + }, + }) + + AddFuncLookup("intrange", Info{ + Display: "IntRange", + Category: "number", + Description: "Integer value between given range", + Example: "-8379477543", + Output: "int", + Params: []Param{ + {Field: "min", Display: "Min", Type: "int", Description: "Minimum int value"}, + {Field: "max", Display: "Max", Type: "int", Description: "Maximum int value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetInt(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetInt(m, "max") + if err != nil { + return nil, err + } + + return intRangeFunc(f, min, max), nil + }, + }) + + AddFuncLookup("float32", Info{ + Display: "Float32", + Category: "number", + Description: "Data type representing floating-point numbers with 32 bits of precision in computing", + Example: "3.1128167e+37", + Output: "float32", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return float32Func(f), nil + }, + }) + + AddFuncLookup("float32range", Info{ + Display: "Float32 Range", + Category: "number", + Description: "Float32 value between given range", + Example: "914774.6", + Output: "float32", + Params: []Param{ + {Field: "min", Display: "Min", Type: "float", Description: "Minimum float32 value"}, + {Field: "max", Display: "Max", Type: "float", Description: "Maximum float32 value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetFloat32(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetFloat32(m, "max") + if err != nil { + return nil, err + } + + return float32Range(f, min, max), nil + }, + }) + + AddFuncLookup("float64", Info{ + Display: "Float64", + Category: "number", + Description: "Data type representing floating-point numbers with 64 bits of precision in computing", + Example: "1.644484108270445e+307", + Output: "float64", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return float64Func(f), nil + }, + }) + + AddFuncLookup("float64range", Info{ + Display: "Float64 Range", + Category: "number", + Description: "Float64 value between given range", + Example: "914774.5585333086", + Output: "float64", + Params: []Param{ + {Field: "min", Display: "Min", Type: "float", Description: "Minimum float64 value"}, + {Field: "max", Display: "Max", Type: "float", Description: "Maximum float64 value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetFloat64(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetFloat64(m, "max") + if err != nil { + return nil, err + } + + return float64Range(f, min, max), nil + }, + }) + + AddFuncLookup("shuffleints", Info{ + Display: "Shuffle Ints", + Category: "number", + Description: "Shuffles an array of ints", + Example: "1,2,3,4 => 3,1,4,2", + Output: "[]int", + Params: []Param{ + {Field: "ints", Display: "Integers", Type: "[]int", Description: "Delimited separated integers"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + ints, err := info.GetIntArray(m, "ints") + if err != nil { + return nil, err + } + + shuffleInts(f, ints) + + return ints, nil + }, + }) + + AddFuncLookup("randomint", Info{ + Display: "Random Int", + Category: "number", + Description: "Randomly selected value from a slice of int", + Example: "-1,2,-3,4 => -3", + Output: "int", + Params: []Param{ + {Field: "ints", Display: "Integers", Type: "[]int", Description: "Delimited separated integers"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + ints, err := info.GetIntArray(m, "ints") + if err != nil { + return nil, err + } + + return randomInt(f, ints), nil + }, + }) + + AddFuncLookup("randomuint", Info{ + Display: "Random Uint", + Category: "number", + Description: "Randomly selected value from a slice of uint", + Example: "1,2,3,4 => 4", + Output: "uint", + Params: []Param{ + {Field: "uints", Display: "Unsigned Integers", Type: "[]uint", Description: "Delimited separated unsigned integers"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + uints, err := info.GetUintArray(m, "uints") + if err != nil { + return nil, err + } + + return randomUint(f, uints), nil + }, + }) + + AddFuncLookup("hexuint", Info{ + Display: "HexUint", + Category: "number", + Description: "Hexadecimal representation of an unsigned integer", + Example: "0x87", + Output: "string", + Params: []Param{ + {Field: "bitSize", Display: "Bit Size", Type: "int", Default: "8", Description: "Bit size of the unsigned integer"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + bitSize, err := info.GetInt(m, "bitSize") + if err != nil { + return nil, err + } + + return hexUint(f, bitSize), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/payment.go b/vendor/github.com/brianvoe/gofakeit/v7/payment.go new file mode 100644 index 0000000000..52496153b2 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/payment.go @@ -0,0 +1,443 @@ +package gofakeit + +import ( + "math" + "strconv" + "strings" + "time" + + "github.com/brianvoe/gofakeit/v7/data" +) + +// CurrencyInfo is a struct of currency information +type CurrencyInfo struct { + Short string `json:"short" xml:"short"` + Long string `json:"long" xml:"long"` +} + +// Currency will generate a struct with random currency information +func Currency() *CurrencyInfo { return currency(GlobalFaker) } + +// Currency will generate a struct with random currency information +func (f *Faker) Currency() *CurrencyInfo { return currency(f) } + +func currency(f *Faker) *CurrencyInfo { + index := f.IntN(len(data.Data["currency"]["short"])) + return &CurrencyInfo{ + Short: data.Data["currency"]["short"][index], + Long: data.Data["currency"]["long"][index], + } +} + +// CurrencyShort will generate a random short currency value +func CurrencyShort() string { return currencyShort(GlobalFaker) } + +// CurrencyShort will generate a random short currency value +func (f *Faker) CurrencyShort() string { return currencyShort(f) } + +func currencyShort(f *Faker) string { return getRandValue(f, []string{"currency", "short"}) } + +// CurrencyLong will generate a random long currency name +func CurrencyLong() string { return currencyLong(GlobalFaker) } + +// CurrencyLong will generate a random long currency name +func (f *Faker) CurrencyLong() string { return currencyLong(f) } + +func currencyLong(f *Faker) string { return getRandValue(f, []string{"currency", "long"}) } + +// Price will take in a min and max value and return a formatted price +func Price(min, max float64) float64 { return price(GlobalFaker, min, max) } + +// Price will take in a min and max value and return a formatted price +func (f *Faker) Price(min, max float64) float64 { return price(f, min, max) } + +func price(f *Faker, min, max float64) float64 { + return math.Floor(float64Range(f, min, max)*100) / 100 +} + +// CreditCardInfo is a struct containing credit variables +type CreditCardInfo struct { + Type string `json:"type" xml:"type"` + Number string `json:"number" xml:"number"` + Exp string `json:"exp" xml:"exp"` + Cvv string `json:"cvv" xml:"cvv"` +} + +// CreditCard will generate a struct full of credit card information +func CreditCard() *CreditCardInfo { return creditCard(GlobalFaker) } + +// CreditCard will generate a struct full of credit card information +func (f *Faker) CreditCard() *CreditCardInfo { return creditCard(f) } + +func creditCard(f *Faker) *CreditCardInfo { + ccType := randomString(f, data.CreditCardTypes) + ccv, _ := generate(f, strings.Repeat("#", int(data.CreditCards[randomString(f, data.CreditCardTypes)].Code.Size))) + + return &CreditCardInfo{ + Type: data.CreditCards[randomString(f, data.CreditCardTypes)].Display, + Number: creditCardNumber(f, &CreditCardOptions{Types: []string{ccType}}), + Exp: creditCardExp(f), + Cvv: ccv, + } +} + +// CreditCardType will generate a random credit card type string +func CreditCardType() string { return creditCardType(GlobalFaker) } + +// CreditCardType will generate a random credit card type string +func (f *Faker) CreditCardType() string { return creditCardType(f) } + +func creditCardType(f *Faker) string { + return data.CreditCards[randomString(f, data.CreditCardTypes)].Display +} + +// CreditCardOptions is the options for credit card number +type CreditCardOptions struct { + Types []string `json:"types"` + Bins []string `json:"bins"` // optional parameter of prepended numbers + Gaps bool `json:"gaps"` +} + +// CreditCardNumber will generate a random luhn credit card number +func CreditCardNumber(cco *CreditCardOptions) string { return creditCardNumber(GlobalFaker, cco) } + +// CreditCardNumber will generate a random luhn credit card number +func (f *Faker) CreditCardNumber(cco *CreditCardOptions) string { return creditCardNumber(f, cco) } + +func creditCardNumber(f *Faker, cco *CreditCardOptions) string { + if cco == nil { + cco = &CreditCardOptions{} + } + if cco.Types == nil || len(cco.Types) == 0 { + cco.Types = data.CreditCardTypes + } + ccType := randomString(f, cco.Types) + + // Get Card info + var cardInfo data.CreditCardInfo + if info, ok := data.CreditCards[ccType]; ok { + cardInfo = info + } else { + ccType = randomString(f, data.CreditCardTypes) + cardInfo = data.CreditCards[ccType] + } + + // Get length and pattern + length := randomUint(f, cardInfo.Lengths) + numStr := "" + if len(cco.Bins) >= 1 { + numStr = randomString(f, cco.Bins) + } else { + numStr = strconv.FormatUint(uint64(randomUint(f, cardInfo.Patterns)), 10) + } + numStr += strings.Repeat("#", int(length)-len(numStr)) + numStr = numerify(f, numStr) + ui, _ := strconv.ParseUint(numStr, 10, 64) + + // Loop through until its a valid luhn + for { + valid := isLuhn(strconv.FormatUint(ui, 10)) + if valid { + break + } + ui++ + } + numStr = strconv.FormatUint(ui, 10) + + // Add gaps to number + if cco.Gaps { + for i, spot := range cardInfo.Gaps { + numStr = numStr[:(int(spot)+i)] + " " + numStr[(int(spot)+i):] + } + } + + return numStr +} + +// CreditCardExp will generate a random credit card expiration date string +// Exp date will always be a future date +func CreditCardExp() string { return creditCardExp(GlobalFaker) } + +// CreditCardExp will generate a random credit card expiration date string +// Exp date will always be a future date +func (f *Faker) CreditCardExp() string { return creditCardExp(f) } + +func creditCardExp(f *Faker) string { + month := strconv.Itoa(randIntRange(f, 1, 12)) + if len(month) == 1 { + month = "0" + month + } + + var currentYear = time.Now().Year() - 2000 + return month + "/" + strconv.Itoa(randIntRange(f, currentYear+1, currentYear+10)) +} + +// CreditCardCvv will generate a random CVV number +// Its a string because you could have 017 as an exp date +func CreditCardCvv() string { return creditCardCvv(GlobalFaker) } + +// CreditCardCvv will generate a random CVV number +// Its a string because you could have 017 as an exp date +func (f *Faker) CreditCardCvv() string { return creditCardCvv(f) } + +func creditCardCvv(f *Faker) string { return numerify(f, "###") } + +// isLuhn check is used for checking if credit card is a valid luhn card +func isLuhn(s string) bool { + var t = [...]int{0, 2, 4, 6, 8, 1, 3, 5, 7, 9} + odd := len(s) & 1 + var sum int + for i, c := range s { + if c < '0' || c > '9' { + return false + } + if i&1 == odd { + sum += t[c-'0'] + } else { + sum += int(c - '0') + } + } + return sum%10 == 0 +} + +// AchRouting will generate a 9 digit routing number +func AchRouting() string { return achRouting(GlobalFaker) } + +// AchRouting will generate a 9 digit routing number +func (f *Faker) AchRouting() string { return achRouting(f) } + +func achRouting(f *Faker) string { return numerify(f, "#########") } + +// AchAccount will generate a 12 digit account number +func AchAccount() string { return achAccount(GlobalFaker) } + +// AchAccount will generate a 12 digit account number +func (f *Faker) AchAccount() string { return achAccount(f) } + +func achAccount(f *Faker) string { return numerify(f, "############") } + +// BitcoinAddress will generate a random bitcoin address consisting of numbers, upper and lower characters +func BitcoinAddress() string { return bitcoinAddress(GlobalFaker) } + +// BitcoinAddress will generate a random bitcoin address consisting of numbers, upper and lower characters +func (f *Faker) BitcoinAddress() string { return bitcoinAddress(f) } + +func bitcoinAddress(f *Faker) string { + return randomString(f, []string{"1", "3"}) + password(f, true, true, true, false, false, number(f, 25, 34)) +} + +// BitcoinPrivateKey will generate a random bitcoin private key base58 consisting of numbers, upper and lower characters +func BitcoinPrivateKey() string { return bitcoinPrivateKey(GlobalFaker) } + +// BitcoinPrivateKey will generate a random bitcoin private key base58 consisting of numbers, upper and lower characters +func (f *Faker) BitcoinPrivateKey() string { return bitcoinPrivateKey(f) } + +func bitcoinPrivateKey(f *Faker) string { + var b strings.Builder + for i := 0; i < 49; i++ { + b.WriteString(randCharacter(f, base58)) + } + return "5" + randomString(f, []string{"H", "J", "K"}) + b.String() +} + +func addPaymentLookup() { + AddFuncLookup("currency", Info{ + Display: "Currency", + Category: "payment", + Description: "Medium of exchange, often in the form of paper money or coins, used for trade and transactions", + Example: `{ + "short": "IQD", + "long": "Iraq Dinar" +}`, + Output: "map[string]string", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return currency(f), nil + }, + }) + + AddFuncLookup("currencyshort", Info{ + Display: "Currency Short", + Category: "payment", + Description: "Short 3-letter word used to represent a specific currency", + Example: "USD", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return currencyShort(f), nil + }, + }) + + AddFuncLookup("currencylong", Info{ + Display: "Currency Long", + Category: "payment", + Description: "Complete name of a specific currency used for official identification in financial transactions", + Example: "United States Dollar", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return currencyLong(f), nil + }, + }) + + AddFuncLookup("price", Info{ + Display: "Price", + Category: "payment", + Description: "The amount of money or value assigned to a product, service, or asset in a transaction", + Example: "92.26", + Output: "float64", + Params: []Param{ + {Field: "min", Display: "Min", Type: "float", Default: "0", Description: "Minimum price value"}, + {Field: "max", Display: "Max", Type: "float", Default: "1000", Description: "Maximum price value"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + min, err := info.GetFloat64(m, "min") + if err != nil { + return nil, err + } + + max, err := info.GetFloat64(m, "max") + if err != nil { + return nil, err + } + + return price(f, min, max), nil + }, + }) + + AddFuncLookup("creditcard", Info{ + Display: "Credit Card", + Category: "payment", + Description: "Plastic card allowing users to make purchases on credit, with payment due at a later date", + Example: `{ + "type": "UnionPay", + "number": "4364599489953698", + "exp": "02/24", + "cvv": "300" +}`, + Output: "map[string]any", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return creditCard(f), nil + }, + }) + + AddFuncLookup("creditcardtype", Info{ + Display: "Credit Card Type", + Category: "payment", + Description: "Classification of credit cards based on the issuing company", + Example: "Visa", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return creditCardType(f), nil + }, + }) + + AddFuncLookup("creditcardnumber", Info{ + Display: "Credit Card Number", + Category: "payment", + Description: "Unique numerical identifier on a credit card used for making electronic payments and transactions", + Example: "4136459948995369", + Output: "string", + Params: []Param{ + { + Field: "types", Display: "Types", Type: "[]string", Default: "all", + Options: []string{"visa", "mastercard", "american-express", "diners-club", "discover", "jcb", "unionpay", "maestro", "elo", "hiper", "hipercard"}, + Description: "A select number of types you want to use when generating a credit card number", + }, + {Field: "bins", Display: "Bins", Type: "[]string", Optional: true, Description: "Optional list of prepended bin numbers to pick from"}, + {Field: "gaps", Display: "Gaps", Type: "bool", Default: "false", Description: "Whether or not to have gaps in number"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + types, err := info.GetStringArray(m, "types") + if err != nil { + return nil, err + } + if len(types) == 1 && types[0] == "all" { + types = []string{} + } + + bins, _ := info.GetStringArray(m, "bins") + + gaps, err := info.GetBool(m, "gaps") + if err != nil { + return nil, err + } + + options := CreditCardOptions{ + Types: types, + Gaps: gaps, + } + + if len(bins) >= 1 { + options.Bins = bins + } + + return creditCardNumber(f, &options), nil + }, + }) + + AddFuncLookup("creditcardexp", Info{ + Display: "Credit Card Exp", + Category: "payment", + Description: "Date when a credit card becomes invalid and cannot be used for transactions", + Example: "01/21", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return creditCardExp(f), nil + }, + }) + + AddFuncLookup("creditcardcvv", Info{ + Display: "Credit Card CVV", + Category: "payment", + Description: "Three or four-digit security code on a credit card used for online and remote transactions", + Example: "513", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return creditCardCvv(f), nil + }, + }) + + AddFuncLookup("achrouting", Info{ + Display: "ACH Routing Number", + Category: "payment", + Description: "Unique nine-digit code used in the U.S. for identifying the bank and processing electronic transactions", + Example: "513715684", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return achRouting(f), nil + }, + }) + + AddFuncLookup("achaccount", Info{ + Display: "ACH Account Number", + Category: "payment", + Description: "A bank account number used for Automated Clearing House transactions and electronic transfers", + Example: "491527954328", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return achAccount(f), nil + }, + }) + + AddFuncLookup("bitcoinaddress", Info{ + Display: "Bitcoin Address", + Category: "payment", + Description: "Cryptographic identifier used to receive, store, and send Bitcoin cryptocurrency in a peer-to-peer network", + Example: "1lWLbxojXq6BqWX7X60VkcDIvYA", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bitcoinAddress(f), nil + }, + }) + + AddFuncLookup("bitcoinprivatekey", Info{ + Display: "Bitcoin Private Key", + Category: "payment", + Description: "Secret, secure code that allows the owner to access and control their Bitcoin holdings", + Example: "5vrbXTADWJ6sQBSYd6lLkG97jljNc0X9VPBvbVqsIH9lWOLcoqg", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return bitcoinPrivateKey(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/person.go b/vendor/github.com/brianvoe/gofakeit/v7/person.go new file mode 100644 index 0000000000..3eb804c3bb --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/person.go @@ -0,0 +1,423 @@ +package gofakeit + +import ( + "math" + "strconv" + "strings" +) + +// PersonInfo is a struct of person information +type PersonInfo struct { + FirstName string `json:"first_name" xml:"first_name"` + LastName string `json:"last_name" xml:"last_name"` + Gender string `json:"gender" xml:"gender"` + SSN string `json:"ssn" xml:"ssn"` + Hobby string `json:"hobby" xml:"hobby"` + Job *JobInfo `json:"job" xml:"job"` + Address *AddressInfo `json:"address" xml:"address"` + Contact *ContactInfo `json:"contact" xml:"contact"` + CreditCard *CreditCardInfo `json:"credit_card" xml:"credit_card"` +} + +// Person will generate a struct with person information +func Person() *PersonInfo { return person(GlobalFaker) } + +// Person will generate a struct with person information +func (f *Faker) Person() *PersonInfo { return person(f) } + +func person(f *Faker) *PersonInfo { + return &PersonInfo{ + FirstName: firstName(f), + LastName: lastName(f), + Gender: gender(f), + SSN: ssn(f), + Hobby: hobby(f), + Job: job(f), + Address: address(f), + Contact: contact(f), + CreditCard: creditCard(f), + } +} + +// Name will generate a random First and Last Name +func Name() string { return name(GlobalFaker) } + +// Name will generate a random First and Last Name +func (f *Faker) Name() string { return name(f) } + +func name(f *Faker) string { + return getRandValue(f, []string{"person", "first"}) + " " + getRandValue(f, []string{"person", "last"}) +} + +// FirstName will generate a random first name +func FirstName() string { return firstName(GlobalFaker) } + +// FirstName will generate a random first name +func (f *Faker) FirstName() string { return firstName(f) } + +func firstName(f *Faker) string { return getRandValue(f, []string{"person", "first"}) } + +// MiddleName will generate a random middle name +func MiddleName() string { return middleName(GlobalFaker) } + +// MiddleName will generate a random middle name +func (f *Faker) MiddleName() string { return middleName(f) } + +func middleName(f *Faker) string { return getRandValue(f, []string{"person", "middle"}) } + +// LastName will generate a random last name +func LastName() string { return lastName(GlobalFaker) } + +// LastName will generate a random last name +func (f *Faker) LastName() string { return lastName(f) } + +func lastName(f *Faker) string { return getRandValue(f, []string{"person", "last"}) } + +// NamePrefix will generate a random name prefix +func NamePrefix() string { return namePrefix(GlobalFaker) } + +// NamePrefix will generate a random name prefix +func (f *Faker) NamePrefix() string { return namePrefix(f) } + +func namePrefix(f *Faker) string { return getRandValue(f, []string{"person", "prefix"}) } + +// NameSuffix will generate a random name suffix +func NameSuffix() string { return nameSuffix(GlobalFaker) } + +// NameSuffix will generate a random name suffix +func (f *Faker) NameSuffix() string { return nameSuffix(f) } + +func nameSuffix(f *Faker) string { return getRandValue(f, []string{"person", "suffix"}) } + +// SSN will generate a random Social Security Number +func SSN() string { return ssn(GlobalFaker) } + +// SSN will generate a random Social Security Number +func (f *Faker) SSN() string { return ssn(f) } + +func ssn(f *Faker) string { return strconv.Itoa(randIntRange(f, 100000000, 999999999)) } + +// Gender will generate a random gender string +func Gender() string { return gender(GlobalFaker) } + +// Gender will generate a random gender string +func (f *Faker) Gender() string { return gender(f) } + +func gender(f *Faker) string { + if boolFunc(f) { + return "male" + } + + return "female" +} + +// Hobby will generate a random hobby string +func Hobby() string { return hobby(GlobalFaker) } + +// Hobby will generate a random hobby string +func (f *Faker) Hobby() string { return hobby(f) } + +func hobby(f *Faker) string { return getRandValue(f, []string{"person", "hobby"}) } + +// ContactInfo struct full of contact info +type ContactInfo struct { + Phone string `json:"phone" xml:"phone"` + Email string `json:"email" xml:"email"` +} + +// Contact will generate a struct with information randomly populated contact information +func Contact() *ContactInfo { return contact(GlobalFaker) } + +// Contact will generate a struct with information randomly populated contact information +func (f *Faker) Contact() *ContactInfo { return contact(f) } + +func contact(f *Faker) *ContactInfo { + return &ContactInfo{ + Phone: phone(f), + Email: email(f), + } +} + +// Phone will generate a random phone number string +func Phone() string { return phone(GlobalFaker) } + +// Phone will generate a random phone number string +func (f *Faker) Phone() string { return phone(f) } + +func phone(f *Faker) string { return replaceWithNumbers(f, "##########") } + +// PhoneFormatted will generate a random phone number string +func PhoneFormatted() string { return phoneFormatted(GlobalFaker) } + +// PhoneFormatted will generate a random phone number string +func (f *Faker) PhoneFormatted() string { return phoneFormatted(f) } + +func phoneFormatted(f *Faker) string { + return replaceWithNumbers(f, getRandValue(f, []string{"person", "phone"})) +} + +// Email will generate a random email string +func Email() string { return email(GlobalFaker) } + +// Email will generate a random email string +func (f *Faker) Email() string { return email(f) } + +func email(f *Faker) string { + email := getRandValue(f, []string{"person", "first"}) + getRandValue(f, []string{"person", "last"}) + email += "@" + email += getRandValue(f, []string{"person", "last"}) + "." + getRandValue(f, []string{"internet", "domain_suffix"}) + + return strings.ToLower(email) +} + +// Teams takes in an array of people and team names and randomly places the people into teams as evenly as possible +func Teams(peopleArray []string, teamsArray []string) map[string][]string { + return teams(GlobalFaker, peopleArray, teamsArray) +} + +// Teams takes in an array of people and team names and randomly places the people into teams as evenly as possible +func (f *Faker) Teams(peopleArray []string, teamsArray []string) map[string][]string { + return teams(f, peopleArray, teamsArray) +} + +func teams(f *Faker, people []string, teams []string) map[string][]string { + // Shuffle the people if more than 1 + if len(people) > 1 { + shuffleStrings(f, people) + } + + peopleIndex := 0 + teamsOutput := make(map[string][]string) + numPer := math.Ceil(float64(len(people)) / float64(len(teams))) + for _, team := range teams { + teamsOutput[team] = []string{} + for i := 0.00; i < numPer; i++ { + if peopleIndex < len(people) { + teamsOutput[team] = append(teamsOutput[team], people[peopleIndex]) + peopleIndex++ + } + } + } + + return teamsOutput +} + +func addPersonLookup() { + AddFuncLookup("person", Info{ + Display: "Person", + Category: "person", + Description: "Personal data, like name and contact details, used for identification and communication", + Example: `{ + "first_name": "Markus", + "last_name": "Moen", + "gender": "male", + "ssn": "275413589", + "image": "https://picsum.photos/208/500", + "hobby": "Lacrosse", + "job": { + "company": "Intermap Technologies", + "title": "Developer", + "descriptor": "Direct", + "level": "Paradigm" + }, + "address": { + "address": "369 North Cornerbury, Miami, North Dakota 24259", + "street": "369 North Cornerbury", + "city": "Miami", + "state": "North Dakota", + "zip": "24259", + "country": "Ghana", + "latitude": -6.662595, + "longitude": 23.921575 + }, + "contact": { + "phone": "3023202027", + "email": "lamarkoelpin@heaney.biz" + }, + "credit_card": { + "type": "Maestro", + "number": "39800889982276", + "exp": "01/29", + "cvv": "932" + } +}`, + Output: "map[string]any", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return person(f), nil + }, + }) + + AddFuncLookup("name", Info{ + Display: "Name", + Category: "person", + Description: "The given and family name of an individual", + Example: "Markus Moen", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return name(f), nil + }, + }) + + AddFuncLookup("nameprefix", Info{ + Display: "Name Prefix", + Category: "person", + Description: "A title or honorific added before a person's name", + Example: "Mr.", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return namePrefix(f), nil + }, + }) + + AddFuncLookup("namesuffix", Info{ + Display: "Name Suffix", + Category: "person", + Description: "A title or designation added after a person's name", + Example: "Jr.", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nameSuffix(f), nil + }, + }) + + AddFuncLookup("firstname", Info{ + Display: "First Name", + Category: "person", + Description: "The name given to a person at birth", + Example: "Markus", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return firstName(f), nil + }, + }) + + AddFuncLookup("middlename", Info{ + Display: "Middle Name", + Category: "person", + Description: "Name between a person's first name and last name", + Example: "Belinda", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return middleName(f), nil + }, + }) + + AddFuncLookup("lastname", Info{ + Display: "Last Name", + Category: "person", + Description: "The family name or surname of an individual", + Example: "Daniel", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return lastName(f), nil + }, + }) + + AddFuncLookup("gender", Info{ + Display: "Gender", + Category: "person", + Description: "Classification based on social and cultural norms that identifies an individual", + Example: "male", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return gender(f), nil + }, + }) + + AddFuncLookup("ssn", Info{ + Display: "SSN", + Category: "person", + Description: "Unique nine-digit identifier used for government and financial purposes in the United States", + Example: "296446360", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return ssn(f), nil + }, + }) + + AddFuncLookup("hobby", Info{ + Display: "Hobby", + Category: "person", + Description: "An activity pursued for leisure and pleasure", + Example: "Swimming", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hobby(f), nil + }, + }) + + AddFuncLookup("email", Info{ + Display: "Email", + Category: "person", + Description: "Electronic mail used for sending digital messages and communication over the internet", + Example: "markusmoen@pagac.net", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return email(f), nil + }, + }) + + AddFuncLookup("phone", Info{ + Display: "Phone", + Category: "person", + Description: "Numerical sequence used to contact individuals via telephone or mobile devices", + Example: "6136459948", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phone(f), nil + }, + }) + + AddFuncLookup("phoneformatted", Info{ + Display: "Phone Formatted", + Category: "person", + Description: "Formatted phone number of a person", + Example: "136-459-9489", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phoneFormatted(f), nil + }, + }) + + AddFuncLookup("teams", Info{ + Display: "Teams", + Category: "person", + Description: "Randomly split people into teams", + Example: `{ + "Team 1": [ + "Justin", + "Connor", + "Jeff" + ], + "Team 2": [ + "Sharon", + "Fabian", + "Billy" + ], + "Team 3": [ + "Steve", + "Robert" + ] +}`, + Output: "map[string][]string", + ContentType: "application/json", + Params: []Param{ + {Field: "people", Display: "Strings", Type: "[]string", Description: "Array of people"}, + {Field: "teams", Display: "Strings", Type: "[]string", Description: "Array of teams"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + people, err := info.GetStringArray(m, "people") + if err != nil { + return nil, err + } + + teamsArray, err := info.GetStringArray(m, "teams") + if err != nil { + return nil, err + } + + return teams(f, people, teamsArray), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/product.go b/vendor/github.com/brianvoe/gofakeit/v7/product.go new file mode 100644 index 0000000000..23f8c8b76b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/product.go @@ -0,0 +1,390 @@ +package gofakeit + +import ( + "fmt" + "strings" +) + +type ProductInfo struct { + Name string `json:"name" xml:"name"` + Description string `json:"description" xml:"description"` + Categories []string `json:"categories" xml:"categories"` + Price float64 `json:"price" xml:"price"` + Features []string `json:"features" xml:"features"` + Color string `json:"color" xml:"color"` + Material string `json:"material" xml:"material"` + UPC string `json:"upc" xml:"upc"` + Audience []string `json:"audience" xml:"audience"` + Dimension string `json:"dimension" xml:"dimension"` + UseCase string `json:"use_case" xml:"use_case"` + Benefit string `json:"benefit" xml:"benefit"` + Suffix string `json:"suffix" xml:"suffix"` +} + +// Product will generate a random set of product information +func Product() *ProductInfo { return product(GlobalFaker) } + +// Product will generate a random set of product information +func (f *Faker) Product() *ProductInfo { return product(f) } + +func product(f *Faker) *ProductInfo { + // Categories + categories := []string{} + weightedCategory, _ := weighted(f, []any{1, 2, 3, 4}, []float32{1, 4, 3, 4}) + + for i := 0; i < weightedCategory.(int); i++ { + categories = append(categories, productCategory(f)) + } + + // Features + features := []string{} + for i := 0; i < number(f, 1, 5); i++ { + features = append(features, productFeature(f)) + } + + product := &ProductInfo{ + Name: productName(f), + Description: productDescription(f), + Categories: categories, + Price: price(f, 3.00, 100.00), + UPC: productUPC(f), + Features: features, + Color: safeColor(f), + Material: productMaterial(f), + Audience: productAudience(f), + Dimension: productDimension(f), + UseCase: productUseCase(f), + Benefit: productBenefit(f), + Suffix: productSuffix(f), + } + + return product +} + +// ProductName will generate a random product name +func ProductName() string { return productName(GlobalFaker) } + +// ProductName will generate a random product name +func (f *Faker) ProductName() string { return productName(f) } + +func productName(f *Faker) string { + name := getRandValue(f, []string{"product", "name"}) + switch number(f, 0, 9) { + case 1: + // Name + Adjective + Feature + return title(fmt.Sprintf("%s %s %s", name, getRandValue(f, []string{"product", "adjective"}), productFeature(f))) + case 2: + // Adjective + Material + Name + return title(fmt.Sprintf("%s %s %s", getRandValue(f, []string{"product", "adjective"}), productMaterial(f), name)) + case 3: + // Color + Name + Suffix + return title(fmt.Sprintf("%s %s %s", safeColor(f), name, getRandValue(f, []string{"product", "suffix"}))) + case 4: + // Feature + Name + Adjective + return title(fmt.Sprintf("%s %s %s", productFeature(f), name, getRandValue(f, []string{"product", "adjective"}))) + case 5: + // Material + Color + Name + return title(fmt.Sprintf("%s %s %s", productMaterial(f), safeColor(f), name)) + case 6: + // Name + Suffix + Material + return title(fmt.Sprintf("%s %s %s", name, getRandValue(f, []string{"product", "suffix"}), productMaterial(f))) + case 7: + // Adjective + Feature + Name + return title(fmt.Sprintf("%s %s %s", getRandValue(f, []string{"product", "adjective"}), productFeature(f), name)) + case 8: + // Color + Material + Name + return title(fmt.Sprintf("%s %s %s", safeColor(f), productMaterial(f), name)) + case 9: + // Suffix + Adjective + Name + return title(fmt.Sprintf("%s %s %s", getRandValue(f, []string{"product", "suffix"}), getRandValue(f, []string{"product", "adjective"}), name)) + } + + // case: 0 - Adjective + Name + Suffix + return title(fmt.Sprintf("%s %s %s", getRandValue(f, []string{"product", "adjective"}), name, getRandValue(f, []string{"product", "suffix"}))) +} + +// ProductDescription will generate a random product description +func ProductDescription() string { return productDescription(GlobalFaker) } + +// ProductDescription will generate a random product description +func (f *Faker) ProductDescription() string { return productDescription(f) } + +func productDescription(f *Faker) string { + prodDesc := getRandValue(f, []string{"product", "description"}) + + // Replace all {productaudience} with join "and" + for strings.Contains(prodDesc, "{productaudience}") { + prodDesc = strings.Replace(prodDesc, "{productaudience}", strings.Join(productAudience(f), " and "), 1) + } + + desc, _ := generate(f, prodDesc) + return desc +} + +// ProductCategory will generate a random product category +func ProductCategory() string { return productCategory(GlobalFaker) } + +// ProductCategory will generate a random product category +func (f *Faker) ProductCategory() string { return productCategory(f) } + +func productCategory(f *Faker) string { + return getRandValue(f, []string{"product", "category"}) +} + +// ProductFeature will generate a random product feature +func ProductFeature() string { return productFeature(GlobalFaker) } + +// ProductFeature will generate a random product feature +func (f *Faker) ProductFeature() string { return productFeature(f) } + +func productFeature(f *Faker) string { + return getRandValue(f, []string{"product", "feature"}) +} + +// ProductMaterial will generate a random product material +func ProductMaterial() string { return productMaterial(GlobalFaker) } + +// ProductMaterial will generate a random product material +func (f *Faker) ProductMaterial() string { return productMaterial(f) } + +func productMaterial(f *Faker) string { + return getRandValue(f, []string{"product", "material"}) +} + +// ProductUPC will generate a random product UPC +func ProductUPC() string { return productUPC(GlobalFaker) } + +// ProductUPC will generate a random product UPC +func (f *Faker) ProductUPC() string { return productUPC(f) } + +func productUPC(f *Faker) string { + // The first digit of a UPC is a fixed digit (usually 0) + upc := "0" + + // Generate the remaining 11 digits randomly + for i := 1; i < 12; i++ { + digit := number(f, 0, 9) + upc += fmt.Sprintf("%d", digit) + } + + return upc +} + +// ProductAudience will generate a random target audience +func ProductAudience() []string { return productAudience(GlobalFaker) } + +// ProductAudience will generate a random target audience +func (f *Faker) ProductAudience() []string { return productAudience(f) } + +func productAudience(f *Faker) []string { + audiences := []string{} + for i := 0; i < number(f, 1, 2); i++ { + // Check if the target audience is already in the list + // If it is, generate a new target audience + for { + audience := getRandValue(f, []string{"product", "target_audience"}) + // Check if in array + if !stringInSlice(audience, audiences) { + audiences = append(audiences, audience) + break + } + } + } + return audiences +} + +// ProductDimension will generate a random product dimension +func ProductDimension() string { return productDimension(GlobalFaker) } + +// ProductDimension will generate a random product dimension +func (f *Faker) ProductDimension() string { return productDimension(f) } + +func productDimension(f *Faker) string { + return getRandValue(f, []string{"product", "dimension"}) +} + +// ProductUseCase will generate a random product use case +func ProductUseCase() string { return productUseCase(GlobalFaker) } + +// ProductUseCase will generate a random product use case +func (f *Faker) ProductUseCase() string { return productUseCase(f) } + +func productUseCase(f *Faker) string { + return getRandValue(f, []string{"product", "use_case"}) +} + +// ProductBenefit will generate a random product benefit +func ProductBenefit() string { return productBenefit(GlobalFaker) } + +// ProductBenefit will generate a random product benefit +func (f *Faker) ProductBenefit() string { return productBenefit(f) } + +func productBenefit(f *Faker) string { + return getRandValue(f, []string{"product", "benefit"}) +} + +// ProductSuffix will generate a random product suffix +func ProductSuffix() string { return productSuffix(GlobalFaker) } + +// ProductSuffix will generate a random product suffix +func (f *Faker) ProductSuffix() string { return productSuffix(f) } + +func productSuffix(f *Faker) string { + return getRandValue(f, []string{"product", "suffix"}) +} + +func addProductLookup() { + AddFuncLookup("product", Info{ + Display: "Product", + Category: "product", + Description: "An item created for sale or use", + Example: `{ + "name": "olive copper monitor", + "description": "Backwards caused quarterly without week it hungry thing someone him regularly. Whomever this revolt hence from his timing as quantity us these yours.", + "categories": [ + "clothing", + "tools and hardware" + ], + "price": 7.61, + "features": [ + "ultra-lightweight" + ], + "color": "navy", + "material": "brass", + "upc": "012780949980", + "audience": [ + "adults" + ], + "dimension": "medium", + "use_case": "home", + "benefit": "comfort", + "suffix": "pro" +}`, + Output: "map[string]any", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return product(f), nil + }, + }) + + AddFuncLookup("productname", Info{ + Display: "Product Name", + Category: "product", + Description: "Distinctive title or label assigned to a product for identification and marketing", + Example: "olive copper monitor", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productName(f), nil + }, + }) + + AddFuncLookup("productdescription", Info{ + Display: "Product Description", + Category: "product", + Description: "Explanation detailing the features and characteristics of a product", + Example: "Backwards caused quarterly without week it hungry thing someone him regularly. Whomever this revolt hence from his timing as quantity us these yours.", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productDescription(f), nil + }, + }) + + AddFuncLookup("productcategory", Info{ + Display: "Product Category", + Category: "product", + Description: "Classification grouping similar products based on shared characteristics or functions", + Example: "clothing", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productCategory(f), nil + }, + }) + + AddFuncLookup("productfeature", Info{ + Display: "Product Feature", + Category: "product", + Description: "Specific characteristic of a product that distinguishes it from others products", + Example: "ultra-lightweight", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productFeature(f), nil + }, + }) + + AddFuncLookup("productmaterial", Info{ + Display: "Product Material", + Category: "product", + Description: "The substance from which a product is made, influencing its appearance, durability, and properties", + Example: "brass", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productMaterial(f), nil + }, + }) + + AddFuncLookup("productupc", Info{ + Display: "Product UPC", + Category: "product", + Description: "Standardized barcode used for product identification and tracking in retail and commerce", + Example: "012780949980", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productUPC(f), nil + }, + }) + + AddFuncLookup("productaudience", Info{ + Display: "Product Audience", + Category: "product", + Description: "The group of people for whom the product is designed or intended", + Example: "adults", + Output: "[]string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productAudience(f), nil + }, + }) + + AddFuncLookup("productdimension", Info{ + Display: "Product Dimension", + Category: "product", + Description: "The size or dimension of a product", + Example: "medium", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productDimension(f), nil + }, + }) + + AddFuncLookup("productusecase", Info{ + Display: "Product Use Case", + Category: "product", + Description: "The scenario or purpose for which a product is typically used", + Example: "home", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productUseCase(f), nil + }, + }) + + AddFuncLookup("productbenefit", Info{ + Display: "Product Benefit", + Category: "product", + Description: "The key advantage or value the product provides", + Example: "comfort", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productBenefit(f), nil + }, + }) + + AddFuncLookup("productsuffix", Info{ + Display: "Product Suffix", + Category: "product", + Description: "A suffix used to differentiate product models or versions", + Example: "pro", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return productSuffix(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/school.go b/vendor/github.com/brianvoe/gofakeit/v7/school.go new file mode 100644 index 0000000000..b100ab805b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/school.go @@ -0,0 +1,25 @@ +package gofakeit + +// School will generate a random School type +func School() string { return school(GlobalFaker) } + +func (f *Faker) School() string { return school(f) } + +func school(f *Faker) string { + return getRandValue(f, []string{"school", "name"}) + " " + + getRandValue(f, []string{"school", "isPrivate"}) + " " + + getRandValue(f, []string{"school", "type"}) +} + +func addSchoolLookup() { + AddFuncLookup("school", Info{ + Display: "School", + Category: "school", + Description: "An institution for formal education and learning", + Example: `Harborview State Academy`, + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return school(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/slice.go b/vendor/github.com/brianvoe/gofakeit/v7/slice.go new file mode 100644 index 0000000000..f9636eec08 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/slice.go @@ -0,0 +1,15 @@ +package gofakeit + +import ( + "reflect" +) + +// Slice fills built-in types and exported fields of a struct with random data. +func Slice(v any) { sliceFunc(GlobalFaker, v) } + +// Slice fills built-in types and exported fields of a struct with random data. +func (f *Faker) Slice(v any) { sliceFunc(f, v) } + +func sliceFunc(f *Faker, v any) { + r(f, reflect.TypeOf(v), reflect.ValueOf(v), "", -1) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/song.go b/vendor/github.com/brianvoe/gofakeit/v7/song.go new file mode 100644 index 0000000000..d8917430c5 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/song.go @@ -0,0 +1,87 @@ +package gofakeit + +func SongName() string { return songName(GlobalFaker) } + +func (f *Faker) SongName() string { return songName(f) } + +func songName(f *Faker) string { return getRandValue(f, []string{"song", "name"}) } + +func SongArtist() string { return songArtist(GlobalFaker) } + +func (f *Faker) SongArtist() string { return songArtist(f) } + +func songArtist(f *Faker) string { return getRandValue(f, []string{"song", "artist"}) } + +func SongGenre() string { return songGenre(GlobalFaker) } + +func (f *Faker) SongGenre() string { return songGenre(f) } + +func songGenre(f *Faker) string { return getRandValue(f, []string{"song", "genre"}) } + +type SongInfo struct { + Name string `json:"name" xml:"name"` + Artist string `json:"artist" xml:"artist"` + Genre string `json:"genre" xml:"genre"` +} + +func Song() *SongInfo { return song(GlobalFaker) } + +func (f *Faker) Song() *SongInfo { return song(f) } + +func song(f *Faker) *SongInfo { + return &SongInfo{ + Name: songName(f), + Artist: songArtist(f), + Genre: songGenre(f), + } +} + +func addSongLookup() { + AddFuncLookup("song", Info{ + Display: "Song", + Category: "song", + Description: "Song with a drum and horn instrumentation", + Example: `{ + "name": "New Rules", + "genre": "Tropical house" +}`, + Output: "map[string]string", + ContentType: "application/json", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return song(f), nil + }, + }) + + AddFuncLookup("songname", Info{ + Display: "Song Name", + Category: "song", + Description: "Title or name of a specific song used for identification and reference", + Example: "New Rules", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return songName(f), nil + }, + }) + + AddFuncLookup("songartist", Info{ + Display: "Song Artist", + Category: "song", + Description: "The artist of maker of song", + Example: "Dua Lipa", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return songArtist(f), nil + }, + }) + + AddFuncLookup("songgenre", Info{ + Display: "Genre", + Category: "song", + Description: "Category that classifies song based on common themes, styles, and storytelling approaches", + Example: "Action", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return songGenre(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/source/BENCHMARKS.md b/vendor/github.com/brianvoe/gofakeit/v7/source/BENCHMARKS.md new file mode 100644 index 0000000000..f582b3d3e3 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/source/BENCHMARKS.md @@ -0,0 +1,16 @@ +go test -bench=. -benchmem \ +goos: darwin \ +goarch: amd64 \ +pkg: github.com/brianvoe/gofakeit/v7 \ +cpu: Apple M1 Max \ +Table generated with tablesgenerator.com/markdown_tables File->Paste table data + +| Benchmark | Iterations| Time/Iter | Bytes | Allocations | +|---------------------|-----------|-------------|--------|-------------| +| BenchmarkPCG-10 | 251946703 | 4.763 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkChaCha8-10 | 228052915 | 5.262 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJSF-10 | 323858558 | 3.712 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSFC-10 | 394809136 | 3.035 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkOld-10 | 207714157 | 5.733 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDumb-10 | 458967214 | 2.611 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCrypto-10 | 15747936 | 77.15 ns/op | 0 B/op | 0 allocs/op | \ No newline at end of file diff --git a/vendor/github.com/brianvoe/gofakeit/v7/source/README.md b/vendor/github.com/brianvoe/gofakeit/v7/source/README.md new file mode 100644 index 0000000000..3358ebea03 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/source/README.md @@ -0,0 +1,65 @@ +# Random Number Generators Collection + +This repository contains a collection of random number generators (RNGs) implemented in Go, designed to cater to a wide range of applications, from cryptographic operations to testing environments. Each RNG in the collection offers distinct features and performance characteristics, making it suitable for various use cases, including those requiring cryptographic security. + +## Generators + +### Crypto + +- **Description**: Utilizes Go's `crypto/rand` package to provide cryptographically secure random numbers, suitable for security-sensitive applications. +- **Usage**: + ```go + source := NewCryptoSource() + number := source.Uint64() + ``` + +### JSF (Jenkins Small Fast) + +- **Description**: An implementation of the Jenkins Small Fast hash function for efficient pseudo-random number generation, balancing speed and randomness quality for general use. +- **Usage**: + ```go + source := NewJSFSource(seed) + number := source.Uint64() + ``` + +### SFC (Simple Fast Counter) + +- **Description**: Based on the Simple Fast Counter algorithm, this source offers rapid number generation with satisfactory randomness properties, ideal for simulations and non-cryptographic applications. +- **Usage**: + ```go + source := NewSFCSource(seed) + number := source.Uint64() + ``` + +### Dumb + +- **Description**: A deterministic generator designed primarily for testing, providing predictable output for scenarios where consistent results are more beneficial than high-quality randomness. +- **Usage**: + ```go + source := NewDumb(seed) + number := source.Uint64() + ``` + +## Installation + +To use these RNGs in your Go project, import the package as follows: + +```go +import "github.com/yourusername/randsource" +``` + +Replace `yourusername` with your GitHub username or organization name where the repository is hosted. + +## Usage + +After importing the package, initialize the desired RNG with or without a seed (as applicable) and use the `Uint64` method to generate random numbers. See the usage examples under each generator's description for more details. + +## Benchmarks + +Performance benchmarks for each RNG are provided to help you choose the right generator for your application. These benchmarks cover various aspects, including speed and randomness quality. + +For detailed benchmark results, see the [Benchmarks](https://github.com/brianvoe/gofakeit/blob/master/source/BENCHMARKS.md) file. + +## Contributing + +We welcome contributions and suggestions! Please open an issue or submit a pull request with your improvements. diff --git a/vendor/github.com/brianvoe/gofakeit/v7/source/crypto.go b/vendor/github.com/brianvoe/gofakeit/v7/source/crypto.go new file mode 100644 index 0000000000..9563409263 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/source/crypto.go @@ -0,0 +1,55 @@ +package source + +import ( + "crypto/rand" + "encoding/binary" +) + +// Package source implements a cryptographically secure pseudo-random number generator (CSPRNG) +// using Go's crypto/rand. The Crypto type is designed for generating high-quality random +// uint64 values, suitable for cryptographic applications like secure token generation, +// cryptographic key creation, and other security-sensitive operations. It offers optional +// thread safety through a locking mechanism, making it suitable for concurrent usage. + +// Pros: +// - Provides cryptographically secure randomness, suitable for security-sensitive applications. +// - Optional thread safety with locking, enabling safe concurrent access. + +// Cons: +// - Locking mechanism, when enabled, may introduce performance overhead. +// - Does not utilize a seed, as it leverages the system's cryptographic RNG, which may be a +// limitation in scenarios where deterministic pseudo-randomness is desired. + +type Crypto struct { + buffer [64]byte // Buffer to hold a block of random data + offset int // Current offset in the buffer +} + +// NewCrypto creates a new instance of Crypto. +func NewCrypto() *Crypto { + return &Crypto{ + buffer: [64]byte{}, // Initialize buffer with zeros + offset: 64, // Set offset to the end of the buffer to trigger a refill on the first call + } +} + +// refillBuffer fills the buffer with random data from crypto/rand. +func (s *Crypto) refillBuffer() { + if _, err := rand.Read(s.buffer[:]); err != nil { + panic("crypto/rand failed: " + err.Error()) // Handle the error appropriately for your application + } + s.offset = 0 // Reset offset after refilling +} + +// Uint64 generates a pseudo-random 64-bit value using crypto/rand, served from a buffered block of data. +func (s *Crypto) Uint64() uint64 { + if s.offset+8 > len(s.buffer) { // Check if we need to refill the buffer + s.refillBuffer() + } + + // Extract a uint64 value from the current position in the buffer + val := binary.BigEndian.Uint64(s.buffer[s.offset:]) + s.offset += 8 // Move the offset for the next call + + return val +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/source/dumb.go b/vendor/github.com/brianvoe/gofakeit/v7/source/dumb.go new file mode 100644 index 0000000000..784f55893f --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/source/dumb.go @@ -0,0 +1,44 @@ +package source + +import "time" + +// Dumb is a deterministic pseudo-random number generator designed specifically for testing purposes. +// It offers predictable sequences of numbers based on the provided seed, making it ideal for scenarios +// where consistent and reproducible test results are critical. By default, if initialized with a seed of 0, +// Dumb uses the current timestamp to generate a starting point, ensuring some level of variability between runs. + +// Pros: +// - Predictability: Ensures reproducible outcomes in tests by providing a consistent sequence of numbers for a given seed. +// - Simplicity: Easy to understand and integrate into testing frameworks, with minimal overhead. +// - Default Variability: Uses the current timestamp as the default seed, providing variability across different test runs when no seed is specified. + +// Cons: +// - Not Suitable for Production: Lacks the randomness quality required for production-level cryptographic or statistical applications. +// - Limited Randomness: The simple incrementation approach does not simulate the complexity of real-world random number generation. + +// Dumb is a simplistic generator for predictable testing. +type Dumb struct { + state uint64 +} + +// NewDumb initializes a Dumb generator. +// If the seed is 0, initializes with the current timestamp. +func NewDumb(seed uint64) *Dumb { + d := &Dumb{} + d.Seed(seed) + return d +} + +// Seed sets the generator's state. If the seed is 0, it uses the current timestamp as the seed. +func (d *Dumb) Seed(seed uint64) { + if seed == 0 { + seed = uint64(time.Now().UnixNano()) + } + d.state = seed +} + +// Uint64 returns the next number in the sequence, incrementing the state. +func (d *Dumb) Uint64() uint64 { + d.state += 1 + return d.state +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/source/jsf.go b/vendor/github.com/brianvoe/gofakeit/v7/source/jsf.go new file mode 100644 index 0000000000..1432d66280 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/source/jsf.go @@ -0,0 +1,50 @@ +package source + +// The JSF(Jenkins Small Fast) pseudo-random number generator. +// Developed by Bob Jenkins, JSF is known for its speed and efficiency, making it suitable +// for applications requiring fast, non-cryptographic quality random numbers. This implementation +// offers seamless integration with Go's math/rand package and includes an improved seeding mechanism. + +// Pros: +// - Fast and efficient, ideal for high-performance requirements. +// - Good randomness quality for non-cryptographic applications. +// - Small state size and simple operations, ensuring a minimal memory footprint. + +// Cons: +// - Not suitable for cryptographic purposes due to its non-cryptographic security level. +// - Quality of randomness may not match that of more complex algorithms. + +type JSF struct { + a, b, c, d uint32 +} + +// NewJSF creates and returns a new JSF pseudo-random number generator. +func NewJSF(seed uint64) *JSF { + jsf := &JSF{} + jsf.Seed(seed) + return jsf +} + +// Seed sets the seed of the JSF with an improved seeding mechanism. +func (jsf *JSF) Seed(seed uint64) { + // Use the seed to derive initial values for a, b, c, d with better distribution + // Splitting the 64-bit seed into parts and using different operations to diversify + s1 := uint32(seed) + s2 := uint32(seed >> 32) + jsf.a = 0xf1ea5eed + jsf.b = s1 ^ jsf.a + jsf.c = s2 ^ jsf.b + jsf.d = s1 +} + +// Uint64 generates a pseudo-random 64-bit value using the improved JSF algorithm. +func (jsf *JSF) Uint64() uint64 { + e := jsf.a - (jsf.b<<27 | jsf.b>>(32-27)) + f := jsf.b ^ (jsf.c << 17) + jsf.c += jsf.d + jsf.d += e + jsf.a = jsf.b + f + jsf.b = jsf.c + e + jsf.c = f + jsf.a + return uint64(jsf.d)<<32 | uint64(jsf.a) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/source/sfc.go b/vendor/github.com/brianvoe/gofakeit/v7/source/sfc.go new file mode 100644 index 0000000000..0357aeec62 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/source/sfc.go @@ -0,0 +1,44 @@ +package source + +// The SFC(Simple Fast Counter) algorithm is designed for fast and efficient generation of pseudo-random numbers, +// utilizing arithmetic and bitwise operations across state variables and a counter to ensure +// good randomness quality. It is particularly well-suited for applications requiring rapid +// number generation without the need for cryptographic security. + +// Pros: +// - High efficiency and speed, ideal for performance-sensitive applications. +// - Simple to implement and maintain, with minimal computational overhead. +// - Offers a balance between speed and randomness quality, suitable for a wide range of uses. + +// Cons: +// - Not designed for cryptographic applications due to its level of randomness. +// - Initial seeding mechanism is basic; may require enhancement for more complex use cases. + +type SFC struct { + a, b, c, counter uint64 +} + +// NewSFC creates and returns a new SFC pseudo-random number generator seeded with a given seed. +func NewSFC(seed uint64) *SFC { + s := &SFC{} + s.Seed(seed) + return s +} + +// Seed sets the seed of the SFC. This implementation can be enhanced to +// provide a more distributed seeding process across the state variables. +func (s *SFC) Seed(seed uint64) { + s.a = seed + s.b = seed + s.c = seed + s.counter = 1 // Reset counter with new seed +} + +// Uint64 generates a pseudo-random 64-bit value using the SFC algorithm. +func (s *SFC) Uint64() uint64 { + s.a += s.b + s.counter + s.b ^= s.c + s.c -= s.a + s.counter++ + return s.c + s.b +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/sql.go b/vendor/github.com/brianvoe/gofakeit/v7/sql.go new file mode 100644 index 0000000000..cf76775896 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/sql.go @@ -0,0 +1,156 @@ +package gofakeit + +import ( + "encoding/json" + "errors" + "fmt" + "strings" +) + +type SQLOptions struct { + Table string `json:"table" xml:"table"` // Table name we are inserting into + Count int `json:"count" xml:"count"` // How many entries (tuples) we're generating + Fields []Field `json:"fields" xml:"fields"` // The fields to be generated +} + +func SQL(so *SQLOptions) (string, error) { return sqlFunc(GlobalFaker, so) } + +func (f *Faker) SQL(so *SQLOptions) (string, error) { return sqlFunc(f, so) } + +func sqlFunc(f *Faker, so *SQLOptions) (string, error) { + if so.Table == "" { + return "", errors.New("must provide table name to generate SQL") + } + if so.Fields == nil || len(so.Fields) <= 0 { + return "", errors.New(("must pass fields in order to generate SQL queries")) + } + if so.Count <= 0 { + return "", errors.New("must have entry count") + } + + var sb strings.Builder + sb.WriteString("INSERT INTO " + so.Table + " ") + + // Loop through each field and put together column names + var cols []string + for _, f := range so.Fields { + cols = append(cols, f.Name) + } + sb.WriteString("(" + strings.Join(cols, ", ") + ")") + + sb.WriteString(" VALUES ") + for i := 0; i < so.Count; i++ { + // Start opening value + sb.WriteString("(") + + // Now, we need to add all of our fields + var endStr string + for ii, field := range so.Fields { + // Set end of value string + endStr = ", " + if ii == len(so.Fields)-1 { + endStr = "" + } + + // If autoincrement, add based upon loop + if field.Function == "autoincrement" { + sb.WriteString(fmt.Sprintf("%d%s", i+1, endStr)) + continue + } + + // Get the function info for the field + funcInfo := GetFuncLookup(field.Function) + if funcInfo == nil { + return "", errors.New("invalid function, " + field.Function + " does not exist") + } + + // Generate the value + val, err := funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return "", err + } + + // Convert the output value to the proper SQL type + convertType := sqlConvertType(funcInfo.Output, val) + + // If its the last field, we need to close the value + sb.WriteString(convertType + endStr) + } + + // If its the last value, we need to close the value + if i == so.Count-1 { + sb.WriteString(");") + } else { + sb.WriteString("),") + } + } + + return sb.String(), nil +} + +// sqlConvertType will take in a type and value and convert it to the proper SQL type +func sqlConvertType(t string, val any) string { + switch t { + case "string": + return `'` + fmt.Sprintf("%v", val) + `'` + case "[]byte": + return `'` + fmt.Sprintf("%s", val) + `'` + default: + return fmt.Sprintf("%v", val) + } +} + +func addDatabaseSQLLookup() { + AddFuncLookup("sql", Info{ + Display: "SQL", + Category: "database", + Description: "Command in SQL used to add new data records into a database table", + Example: `INSERT INTO people + (id, first_name, price, age, created_at) +VALUES + (1, 'Markus', 804.92, 21, '1937-01-30 07:58:01'), + (2, 'Santino', 235.13, 40, '1964-07-07 22:25:40');`, + Output: "string", + ContentType: "application/sql", + Params: []Param{ + {Field: "table", Display: "Table", Type: "string", Description: "Name of the table to insert into"}, + {Field: "count", Display: "Count", Type: "int", Default: "100", Description: "Number of inserts to generate"}, + {Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + so := SQLOptions{} + + table, err := info.GetString(m, "table") + if err != nil { + return nil, err + } + so.Table = table + + count, err := info.GetInt(m, "count") + if err != nil { + return nil, err + } + so.Count = count + + fieldsStr, err := info.GetStringArray(m, "fields") + if err != nil { + return nil, err + } + + // Check to make sure fields has length + if len(fieldsStr) > 0 { + so.Fields = make([]Field, len(fieldsStr)) + + for i, f := range fieldsStr { + // Unmarshal fields string into fields array + err = json.Unmarshal([]byte(f), &so.Fields[i]) + if err != nil { + return nil, err + } + } + } + + return sqlFunc(f, &so) + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/string.go b/vendor/github.com/brianvoe/gofakeit/v7/string.go new file mode 100644 index 0000000000..5be37826d0 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/string.go @@ -0,0 +1,270 @@ +package gofakeit + +// Letter will generate a single random lower case ASCII letter +func Letter() string { return letter(GlobalFaker) } + +// Letter will generate a single random lower case ASCII letter +func (f *Faker) Letter() string { return letter(f) } + +func letter(f *Faker) string { return string(randLetter(f)) } + +// LetterN will generate a random ASCII string with length N. Note that this function returns a string with a length of 1 when 0 is passed. +func LetterN(n uint) string { return letterN(GlobalFaker, n) } + +// LetterN will generate a random ASCII string with length N. Note that this function returns a string with a length of 1 when 0 is passed. +func (f *Faker) LetterN(n uint) string { return letterN(f, n) } + +func letterN(f *Faker, n uint) string { + // Make sure we dont use 0 + if n == 0 { + n = 1 + } + out := make([]rune, n) + for i := 0; i < int(n); i++ { + out[i] = randLetter(f) + } + return string(out) +} + +// Vowel will generate a single random lower case vowel +func Vowel() string { return vowel(GlobalFaker) } + +// Vowel will generate a single random lower case vowel +func (f *Faker) Vowel() string { return vowel(f) } + +func vowel(f *Faker) string { return string(randCharacter(f, vowels)) } + +// Digit will generate a single ASCII digit +func Digit() string { return digit(GlobalFaker) } + +// Digit will generate a single ASCII digit +func (f *Faker) Digit() string { return digit(f) } + +func digit(f *Faker) string { return string(randDigit(f)) } + +// DigitN will generate a random string of length N consists of ASCII digits. Note that the string generated can start with 0 and this function returns a string with a length of 1 when 0 is passed. +func DigitN(n uint) string { return digitN(GlobalFaker, n) } + +// DigitN will generate a random string of length N consists of ASCII digits. Note that the string generated can start with 0 and this function returns a string with a length of 1 when 0 is passed. +func (f *Faker) DigitN(n uint) string { return digitN(f, n) } + +func digitN(f *Faker, n uint) string { + // Make sure we dont use 0 + if n == 0 { + n = 1 + } + out := make([]rune, n) + for i := 0; i < int(n); i++ { + out[i] = randDigit(f) + } + return string(out) +} + +// Numerify will replace # with random numerical values +func Numerify(str string) string { return numerify(GlobalFaker, str) } + +// Numerify will replace # with random numerical values +func (f *Faker) Numerify(str string) string { return numerify(f, str) } + +func numerify(f *Faker, str string) string { return replaceWithNumbers(f, str) } + +// Lexify will replace ? with random generated letters +func Lexify(str string) string { return lexify(GlobalFaker, str) } + +// Lexify will replace ? with random generated letters +func (f *Faker) Lexify(str string) string { return lexify(f, str) } + +func lexify(f *Faker, str string) string { return replaceWithLetters(f, str) } + +// ShuffleStrings will randomize a slice of strings +func ShuffleStrings(a []string) { shuffleStrings(GlobalFaker, a) } + +// ShuffleStrings will randomize a slice of strings +func (f *Faker) ShuffleStrings(a []string) { shuffleStrings(f, a) } + +func shuffleStrings(f *Faker, a []string) { + swap := func(i, j int) { + a[i], a[j] = a[j], a[i] + } + //to avoid upgrading to 1.10 I copied the algorithm + n := len(a) + if n <= 1 { + return + } + + //if size is > int32 probably it will never finish, or ran out of entropy + i := n - 1 + for ; i > 0; i-- { + j := int(int32NFunc(f, int32(i+1))) + swap(i, j) + } +} + +// RandomString will take in a slice of string and return a randomly selected value +func RandomString(a []string) string { return randomString(GlobalFaker, a) } + +// RandomString will take in a slice of string and return a randomly selected value +func (f *Faker) RandomString(a []string) string { return randomString(f, a) } + +func randomString(f *Faker, a []string) string { + size := len(a) + if size == 0 { + return "" + } + if size == 1 { + return a[0] + } + return a[f.IntN(size)] +} + +func addStringLookup() { + AddFuncLookup("letter", Info{ + Display: "Letter", + Category: "string", + Description: "Character or symbol from the American Standard Code for Information Interchange (ASCII) character set", + Example: "g", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return letter(f), nil + }, + }) + + AddFuncLookup("lettern", Info{ + Display: "LetterN", + Category: "string", + Description: "ASCII string with length N", + Example: "gbRMaRxHki", + Output: "string", + Params: []Param{ + {Field: "count", Display: "Count", Type: "uint", Description: "Number of digits to generate"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + ui, err := info.GetUint(m, "count") + if err != nil { + return nil, err + } + + return letterN(f, ui), nil + }, + }) + + AddFuncLookup("vowel", Info{ + Display: "Vowel", + Category: "string", + Description: "Speech sound produced with an open vocal tract", + Example: "a", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return vowel(f), nil + }, + }) + + AddFuncLookup("digit", Info{ + Display: "Digit", + Category: "string", + Description: "Numerical symbol used to represent numbers", + Example: "0", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return digit(f), nil + }, + }) + + AddFuncLookup("digitn", Info{ + Display: "DigitN", + Category: "string", + Description: "string of length N consisting of ASCII digits", + Example: "0136459948", + Output: "string", + Params: []Param{ + {Field: "count", Display: "Count", Type: "uint", Description: "Number of digits to generate"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + ui, err := info.GetUint(m, "count") + if err != nil { + return nil, err + } + + return digitN(f, ui), nil + }, + }) + + AddFuncLookup("numerify", Info{ + Display: "Numerify", + Category: "string", + Description: "Replace # with random numerical values", + Example: "(###)###-#### => (555)867-5309", + Output: "string", + Params: []Param{ + {Field: "str", Display: "String", Type: "string", Description: "String value to replace #'s"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + str, err := info.GetString(m, "str") + if err != nil { + return nil, err + } + + return numerify(f, str), nil + }, + }) + + AddFuncLookup("lexify", Info{ + Display: "Lexify", + Category: "string", + Description: "Replace ? with random generated letters", + Example: "?????@??????.com => billy@mister.com", + Output: "string", + Params: []Param{ + {Field: "str", Display: "String", Type: "string", Description: "String value to replace ?'s"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + str, err := info.GetString(m, "str") + if err != nil { + return nil, err + } + + return lexify(f, str), nil + }, + }) + + AddFuncLookup("shufflestrings", Info{ + Display: "Shuffle Strings", + Category: "string", + Description: "Shuffle an array of strings", + Example: "hello,world,whats,up => whats,world,hello,up", + Output: "[]string", + ContentType: "application/json", + Params: []Param{ + {Field: "strs", Display: "Strings", Type: "[]string", Description: "Delimited separated strings"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + strs, err := info.GetStringArray(m, "strs") + if err != nil { + return nil, err + } + + shuffleStrings(f, strs) + + return strs, nil + }, + }) + + AddFuncLookup("randomstring", Info{ + Display: "Random String", + Category: "string", + Description: "Return a random string from a string array", + Example: "hello,world,whats,up => world", + Output: "[]string", + Params: []Param{ + {Field: "strs", Display: "Strings", Type: "[]string", Description: "Delimited separated strings"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + strs, err := info.GetStringArray(m, "strs") + if err != nil { + return nil, err + } + + return randomString(f, strs), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/struct.go b/vendor/github.com/brianvoe/gofakeit/v7/struct.go new file mode 100644 index 0000000000..b2ac99a3dc --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/struct.go @@ -0,0 +1,619 @@ +package gofakeit + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "time" +) + +// Struct fills in exported fields of a struct with random data +// based on the value of `fake` tag of exported fields +// or with the result of a call to the Fake() method +// if the field type implements `Fakeable`. +// Use `fake:"skip"` to explicitly skip an element. +// All built-in types are supported, with templating support +// for string types. +func Struct(v any) error { return structFunc(GlobalFaker, v) } + +// Struct fills in exported fields of a struct with random data +// based on the value of `fake` tag of exported fields. +// Use `fake:"skip"` to explicitly skip an element. +// All built-in types are supported, with templating support +// for string types. +func (f *Faker) Struct(v any) error { return structFunc(f, v) } + +func structFunc(f *Faker, v any) error { + return r(f, reflect.TypeOf(v), reflect.ValueOf(v), "", 0) +} + +func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + // Handle special types + + if t.PkgPath() == "encoding/json" { + // encoding/json has two special types: + // - RawMessage + // - Number + + switch t.Name() { + case "RawMessage": + return rJsonRawMessage(f, v, tag) + case "Number": + return rJsonNumber(f, v, tag) + default: + return errors.New("unknown encoding/json type: " + t.Name()) + } + } + + // Handle generic types + switch t.Kind() { + case reflect.Ptr: + return rPointer(f, t, v, tag, size) + case reflect.Struct: + return rStruct(f, t, v, tag) + case reflect.String: + return rString(f, t, v, tag) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return rUint(f, t, v, tag) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rInt(f, t, v, tag) + case reflect.Float32, reflect.Float64: + return rFloat(f, t, v, tag) + case reflect.Bool: + return rBool(f, t, v, tag) + case reflect.Array, reflect.Slice: + return rSlice(f, t, v, tag, size) + case reflect.Map: + return rMap(f, t, v, tag, size) + } + + return nil +} + +func rCustom(f *Faker, v reflect.Value, tag string) error { + // If tag is empty return error + if tag == "" { + return errors.New("tag is empty") + } + + fName, fParams := parseNameAndParamsFromTag(tag) + info := GetFuncLookup(fName) + + // Check to see if it's a replaceable lookup function + if info == nil { + return fmt.Errorf("function %q not found", tag) + } + + // Parse map params + mapParams, err := parseMapParams(info, fParams) + if err != nil { + return err + } + + // Call function + fValue, err := info.Generate(f, mapParams, info) + if err != nil { + return err + } + + // Create new element of expected type + field := reflect.New(reflect.TypeOf(fValue)) + field.Elem().Set(reflect.ValueOf(fValue)) + + // Check if element is pointer if so + // grab the underlying value + fieldElem := field.Elem() + if fieldElem.Kind() == reflect.Ptr { + fieldElem = fieldElem.Elem() + } + + // Check if field kind is the same as the expected type + if fieldElem.Kind() != v.Kind() { + // return error saying the field and kinds that do not match + return errors.New("field kind " + fieldElem.Kind().String() + " does not match expected kind " + v.Kind().String()) + } + + // Set the value + v.Set(fieldElem.Convert(v.Type())) + + // If a function is called to set the struct + // stop from going through sub fields + return nil +} + +func rStruct(f *Faker, t reflect.Type, v reflect.Value, tag string) error { + // Check if tag exists, if so run custom function + if t.Name() != "" && tag != "" { + return rCustom(f, v, tag) + } + + // Check if struct is fakeable + if isFakeable(t) { + value, err := callFake(f, v, reflect.Struct) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(value)) + return nil + } + + // Loop through all the fields of the struct + n := t.NumField() + for i := 0; i < n; i++ { + elementT := t.Field(i) + elementV := v.Field(i) + fakeTag, ok := elementT.Tag.Lookup("fake") + + // Check whether or not to skip this field + if ok && fakeTag == "skip" || fakeTag == "-" { + // Do nothing, skip it + continue + } + + // Check to make sure you can set it or that it's an embedded(anonymous) field + if !elementV.CanSet() && !elementT.Anonymous { + continue + } + + // Check if reflect type is of values we can specifically set + elemStr := elementT.Type.String() + switch elemStr { + case "time.Time", "*time.Time": + // Check if element is a pointer + elemV := elementV + if elemStr == "*time.Time" { + elemV = reflect.New(elementT.Type.Elem()).Elem() + } + + // Run rTime on the element + err := rTime(f, elementT, elemV, fakeTag) + if err != nil { + return err + } + + if elemStr == "*time.Time" { + elementV.Set(elemV.Addr()) + } + + continue + } + + // Check if fakesize is set + size := -1 // Set to -1 to indicate fakesize was not set + fs, ok := elementT.Tag.Lookup("fakesize") + if ok { + var err error + + // Check if size has params separated by , + if strings.Contains(fs, ",") { + sizeSplit := strings.SplitN(fs, ",", 2) + if len(sizeSplit) == 2 { + var sizeMin int + var sizeMax int + + sizeMin, err = strconv.Atoi(sizeSplit[0]) + if err != nil { + return err + } + sizeMax, err = strconv.Atoi(sizeSplit[1]) + if err != nil { + return err + } + + size = f.IntN(sizeMax-sizeMin+1) + sizeMin + } + } else { + size, err = strconv.Atoi(fs) + if err != nil { + return err + } + } + } + + // Recursively call r() to fill in the struct + err := r(f, elementT.Type, elementV, fakeTag, size) + if err != nil { + return err + } + } + + return nil +} + +func rPointer(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + elemT := t.Elem() + if v.IsNil() { + nv := reflect.New(elemT).Elem() + err := r(f, elemT, nv, tag, size) + if err != nil { + return err + } + + v.Set(nv.Addr()) + } else { + err := r(f, elemT, v.Elem(), tag, size) + if err != nil { + return err + } + } + + return nil +} + +func rSlice(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + // If you cant even set it dont even try + if !v.CanSet() { + return errors.New("cannot set slice") + } + + // Check if tag exists, if so run custom function + if t.Name() != "" && tag != "" { + // Check to see if custom function works if not continue to normal loop of values + err := rCustom(f, v, tag) + if err == nil { + return nil + } + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.Slice, reflect.Array) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(value)) + return nil + } + + // Grab original size to use if needed for sub arrays + ogSize := size + + // If the value has a len and is less than the size + // use that instead of the requested size + elemLen := v.Len() + if elemLen == 0 && size == -1 { + size = number(f, 1, 10) + } else if elemLen != 0 && (size == -1 || elemLen < size) { + size = elemLen + } + + // Get the element type + elemT := t.Elem() + + // Loop through the elements length and set based upon the index + for i := 0; i < size; i++ { + nv := reflect.New(elemT) + err := r(f, elemT, nv.Elem(), tag, ogSize) + if err != nil { + return err + } + + // If values are already set fill them up, otherwise append + if elemLen != 0 { + v.Index(i).Set(reflect.Indirect(nv)) + } else { + v.Set(reflect.Append(reflect.Indirect(v), reflect.Indirect(nv))) + } + } + + return nil +} + +func rMap(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + // If you cant even set it dont even try + if !v.CanSet() { + return errors.New("cannot set slice") + } + + // Check if tag exists, if so run custom function + if tag != "" { + return rCustom(f, v, tag) + } else if size > 0 { + // NOOP + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.Map) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(value)) + return nil + } + + // Set a size + newSize := size + if newSize == -1 { + newSize = number(f, 1, 10) + } + + // Create new map based upon map key value type + mapType := reflect.MapOf(t.Key(), t.Elem()) + newMap := reflect.MakeMap(mapType) + + for i := 0; i < newSize; i++ { + // Create new key + mapIndex := reflect.New(t.Key()) + err := r(f, t.Key(), mapIndex.Elem(), "", -1) + if err != nil { + return err + } + + // Create new value + mapValue := reflect.New(t.Elem()) + err = r(f, t.Elem(), mapValue.Elem(), "", -1) + if err != nil { + return err + } + + newMap.SetMapIndex(mapIndex.Elem(), mapValue.Elem()) + } + + // Set newMap into struct field + if t.Kind() == reflect.Ptr { + v.Set(newMap.Elem()) + } else { + v.Set(newMap) + } + + return nil +} + +func rString(f *Faker, t reflect.Type, v reflect.Value, tag string) error { + if tag != "" { + genStr, err := generate(f, tag) + if err != nil { + return err + } + + v.SetString(genStr) + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.String) + if err != nil { + return err + } + + valueStr, ok := value.(string) + if !ok { + return errors.New("call to Fake method did not return a string") + } + v.SetString(valueStr) + } else { + genStr, err := generate(f, strings.Repeat("?", number(f, 4, 10))) + if err != nil { + return err + } + + v.SetString(genStr) + } + + return nil +} + +func rInt(f *Faker, t reflect.Type, v reflect.Value, tag string) error { + if tag != "" { + genStr, err := generate(f, tag) + if err != nil { + return err + } + + i, err := strconv.ParseInt(genStr, 10, 64) + if err != nil { + return err + } + + v.SetInt(i) + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64) + if err != nil { + return err + } + + switch i := value.(type) { + case int: + v.SetInt(int64(i)) + case int8: + v.SetInt(int64(i)) + case int16: + v.SetInt(int64(i)) + case int32: + v.SetInt(int64(i)) + case int64: + v.SetInt(int64(i)) + default: + return errors.New("call to Fake method did not return an integer") + } + } else { + // If no tag or error converting to int, set with random value + switch t.Kind() { + case reflect.Int: + v.SetInt(int64Func(f)) + case reflect.Int8: + v.SetInt(int64(int8Func(f))) + case reflect.Int16: + v.SetInt(int64(int16Func(f))) + case reflect.Int32: + v.SetInt(int64(int32Func(f))) + case reflect.Int64: + v.SetInt(int64Func(f)) + } + } + + return nil +} + +func rUint(f *Faker, t reflect.Type, v reflect.Value, tag string) error { + if tag != "" { + genStr, err := generate(f, tag) + if err != nil { + return err + } + + u, err := strconv.ParseUint(genStr, 10, 64) + if err != nil { + return err + } + + v.SetUint(u) + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64) + if err != nil { + return err + } + + switch i := value.(type) { + case uint: + v.SetUint(uint64(i)) + case uint8: + v.SetUint(uint64(i)) + case uint16: + v.SetUint(uint64(i)) + case uint32: + v.SetUint(uint64(i)) + case uint64: + v.SetUint(uint64(i)) + default: + return errors.New("call to Fake method did not return an unsigned integer") + } + } else { + // If no tag or error converting to uint, set with random value + switch t.Kind() { + case reflect.Uint: + v.SetUint(f.Uint64()) + case reflect.Uint8: + v.SetUint(uint64(uint8Func(f))) + case reflect.Uint16: + v.SetUint(uint64(uint16Func(f))) + case reflect.Uint32: + v.SetUint(uint64(uint32Func(f))) + case reflect.Uint64: + v.SetUint(f.Uint64()) + } + } + + return nil +} + +func rFloat(f *Faker, t reflect.Type, v reflect.Value, tag string) error { + if tag != "" { + genStr, err := generate(f, tag) + if err != nil { + return err + } + + f, err := strconv.ParseFloat(genStr, 64) + if err != nil { + return err + } + + v.SetFloat(f) + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.Float32, reflect.Float64) + if err != nil { + return err + } + + switch i := value.(type) { + case float32: + v.SetFloat(float64(i)) + case float64: + v.SetFloat(float64(i)) + default: + return errors.New("call to Fake method did not return a float") + } + } else { + // If no tag or error converting to float, set with random value + switch t.Kind() { + case reflect.Float64: + v.SetFloat(float64Func(f)) + case reflect.Float32: + v.SetFloat(float64(float32Func(f))) + } + } + + return nil +} + +func rBool(f *Faker, t reflect.Type, v reflect.Value, tag string) error { + if tag != "" { + genStr, err := generate(f, tag) + if err != nil { + return err + } + + b, err := strconv.ParseBool(genStr) + if err != nil { + return err + } + + v.SetBool(b) + } else if isFakeable(t) { + value, err := callFake(f, v, reflect.Bool) + if err != nil { + return err + } + + switch i := value.(type) { + case bool: + v.SetBool(bool(i)) + default: + return errors.New("call to Fake method did not return a boolean") + } + } else { + // If no tag or error converting to boolean, set with random value + v.SetBool(boolFunc(f)) + } + + return nil +} + +// rTime will set a time.Time field the best it can from either the default date tag or from the generate tag +func rTime(f *Faker, t reflect.StructField, v reflect.Value, tag string) error { + if tag != "" { + // Generate time + timeOutput, err := generate(f, tag) + if err != nil { + return err + } + + // Check to see if timeOutput has monotonic clock reading + // if so, remove it. This is because time.Parse() does not + // support parsing the monotonic clock reading + if strings.Contains(timeOutput, " m=") { + timeOutput = strings.Split(timeOutput, " m=")[0] + } + + // Check to see if they are passing in a format to parse the time + timeFormat, timeFormatOK := t.Tag.Lookup("format") + if timeFormatOK { + timeFormat = javaDateFormatToGolangDateFormat(timeFormat) + } else { + // If tag == "{date}" use time.RFC3339 + // They are attempting to use the default date lookup + if tag == "{date}" { + timeFormat = time.RFC3339 + } else { + // Default format of time.Now().String() + timeFormat = "2006-01-02 15:04:05.999999999 -0700 MST" + } + } + + // If output is larger than format cut the output + // This helps us avoid errors from time.Parse + if len(timeOutput) > len(timeFormat) { + timeOutput = timeOutput[:len(timeFormat)] + } + + // Attempt to parse the time + timeStruct, err := time.Parse(timeFormat, timeOutput) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(timeStruct)) + return nil + } + + v.Set(reflect.ValueOf(date(f))) + return nil +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/template.go b/vendor/github.com/brianvoe/gofakeit/v7/template.go new file mode 100644 index 0000000000..5921fbf6d5 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/template.go @@ -0,0 +1,440 @@ +package gofakeit + +import ( + "bytes" + "fmt" + "strconv" + "time" + + "reflect" + "strings" + "text/template" +) + +// TemplateOptions defines values needed for template document generation +type TemplateOptions struct { + Funcs template.FuncMap `fake:"-"` + Data any `json:"data" xml:"data" fake:"-"` +} + +// Template generates an document based on the the supplied template +func Template(template string, co *TemplateOptions) (string, error) { + if co == nil { + co = &TemplateOptions{} + GlobalFaker.Struct(co) + } + return templateFunc(template, templateFuncMap(GlobalFaker, &co.Funcs), co) +} + +// Template generates an document based on the the supplied template +func (f *Faker) Template(template string, co *TemplateOptions) (string, error) { + if co == nil { + co = &TemplateOptions{} + f.Struct(co) + } + return templateFunc(template, templateFuncMap(f, &co.Funcs), co) +} + +// MarkdownOptions defines values needed for markdown document generation +type MarkdownOptions struct { +} + +// Template for Markdown +const templateMarkdown = ` +{{$repo := Gamertag}} +{{$language := RandomString (SliceString "go" "python" "javascript")}} +{{$username := Gamertag}} +{{$weightedSlice := SliceAny "github.com" "gitlab.com" "bitbucket.org"}} +{{$weightedWeights := SliceF32 5 1 1}} +{{$domain := Weighted $weightedSlice $weightedWeights}} +{{$action := RandomString (SliceString "process" "run" "execute" "perform" "handle")}} +{{$usage := RandomString (SliceString "whimsical story" "quirky message" "playful alert" "funny request" "lighthearted command")}} +{{$result := RandomString (SliceString "success" "error" "unknown" "completed" "failed" "finished" "in progress" "terminated")}} + +# {{$repo}} + +*Author: {{FirstName}} {{LastName}}* + +{{Paragraph 2 5 7 "\n\n"}} + +## Table of Contents +- [Installation](#installation) +- [Usage](#usage) +- [License](#license) + +## Installation +{{if eq $language "go"}}'''go +go get {{$domain}}/{{$username}}/{{$repo}} +'''{{else if eq $language "python"}}'''bash +pip install {{$repo}} +'''{{else if eq $language "javascript"}}'''js +npm install {{$repo}} +'''{{end}} + +## Usage +{{if eq $language "go"}}'''go +result := {{$repo}}.{{$action}}("{{ToLower $usage}}") +fmt.Println("{{ToLower $repo}} result:", "{{ToLower $result}}") +'''{{else if eq $language "python"}}'''python +result = {{ToLower $repo}}.{{$action}}("{{ToLower $usage}}") +print("{{ToLower $repo}} result:", "{{ToLower $result}}") +'''{{else if eq $language "javascript"}}'''javascript +const result = {{ToLower $repo}}.{{$action}}("{{ToLower $usage}}"); +console.log("{{ToLower $repo}} result:", "{{ToLower $result}}"); +'''{{end}} + +## License +{{RandomString (SliceString "MIT" "Apache 2.0" "GPL-3.0" "BSD-3-Clause" "ISC")}} +` + +// Markdown will return a single random Markdown template document +func Markdown(co *MarkdownOptions) (string, error) { + if co == nil { + co = &MarkdownOptions{} + GlobalFaker.Struct(co) + } + return templateFunc(templateMarkdown, templateFuncMap(GlobalFaker, nil), co) +} + +// Markdown will return a single random Markdown template document +func (f *Faker) Markdown(co *MarkdownOptions) (string, error) { + if co == nil { + co = &MarkdownOptions{} + f.Struct(co) + } + return templateFunc(templateMarkdown, templateFuncMap(f, nil), co) +} + +// EmailOptions defines values needed for email document generation +type EmailOptions struct { +} + +// Template for email text +const templateEmail = ` +Subject: {{RandomString (SliceString "Greetings" "Hello" "Hi")}} from {{FirstName}}! + +Dear {{LastName}}, + +{{RandomString (SliceString "Greetings!" "Hello there!" "Hi, how are you?")}} {{RandomString (SliceString "How's everything going?" "I hope your day is going well." "Sending positive vibes your way.")}} + +{{RandomString (SliceString "I trust this email finds you well." "I hope you're doing great." "Hoping this message reaches you in good spirits.")}} {{RandomString (SliceString "Wishing you a fantastic day!" "May your week be filled with joy." "Sending good vibes your way.")}} + +{{Paragraph 3 5 10 "\n\n"}} + +{{RandomString (SliceString "I would appreciate your thoughts on" "I'm eager to hear your feedback on" "I'm curious to know what you think about")}} it. If you have a moment, please feel free to check out the project on {{RandomString (SliceString "GitHub" "GitLab" "Bitbucket")}} + +{{RandomString (SliceString "Your insights would be invaluable." "I'm eager to hear what you think." "Feel free to share your opinions with me.")}} {{RandomString (SliceString "Looking forward to your feedback!" "Your perspective is highly valued." "Your thoughts matter to me.")}} + +{{RandomString (SliceString "Thank you for your consideration!" "I appreciate your attention to this matter." "Your support means a lot to me.")}} {{RandomString (SliceString "Wishing you a wonderful day!" "Thanks in advance for your time." "Your feedback is greatly appreciated.")}} + +{{RandomString (SliceString "Warm regards" "Best wishes" "Kind regards" "Sincerely" "With gratitude")}} +{{FirstName}} {{LastName}} +{{Email}} +{{PhoneFormatted}} +` + +// EmailText will return a single random text email template document +func EmailText(co *EmailOptions) (string, error) { + if co == nil { + co = &EmailOptions{} + GlobalFaker.Struct(co) + } + return templateFunc(templateEmail, templateFuncMap(GlobalFaker, nil), co) +} + +// EmailText will return a single random text email template document +func (f *Faker) EmailText(co *EmailOptions) (string, error) { + if co == nil { + co = &EmailOptions{} + f.Struct(co) + } + return templateFunc(templateEmail, templateFuncMap(f, nil), co) +} + +// functions that wont work with template engine +var templateExclusion = []string{ + "RandomMapKey", + "SQL", + "Template", +} + +// Build the template.FuncMap for the template engine +func templateFuncMap(f *Faker, fm *template.FuncMap) *template.FuncMap { + + // create a new function map + funcMap := template.FuncMap{} + + v := reflect.ValueOf(f) + + // loop through the methods + for i := 0; i < v.NumMethod(); i++ { + // check if the method is in the exclusion list + if stringInSlice(v.Type().Method(i).Name, templateExclusion) { + continue + } + + // Check if method has return values + // If not don't add to function map + if v.Type().Method(i).Type.NumOut() == 0 { + continue + } + + // add the method to the function map + funcMap[v.Type().Method(i).Name] = v.Method(i).Interface() + } + + // make string upper case + funcMap["ToUpper"] = strings.ToUpper + + // make string lower case + funcMap["ToLower"] = strings.ToLower + + // make string title case + funcMap["IntRange"] = func(start, end int) []int { + n := end - start + 1 + result := make([]int, n) + for i := 0; i < n; i++ { + result[i] = start + i + } + return result + } + + // enable passing any type to return a string + funcMap["ToInt"] = func(args any) int { + switch v := args.(type) { + case string: + i, err := strconv.Atoi(v) + if err != nil { + return 0 + } + + return i + case float64: + return int(v) + case float32: + return int(v) + case int: + return v + + // Anything else return 0 + default: + return 0 + } + } + + // enable passing any type to return a float64 + funcMap["ToFloat"] = func(args any) float64 { + switch v := args.(type) { + case string: + i, err := strconv.ParseFloat(v, 64) + if err != nil { + return 0 + } + + return i + case float64: + return v + case float32: + return float64(v) + case int: + return float64(v) + + // Anything else return 0 + default: + return 0 + } + } + + // ensable passing any type to return a string + funcMap["ToString"] = func(args any) string { + switch v := args.(type) { + case string: + return v + case float64: + return strconv.FormatFloat(v, 'f', -1, 64) + case float32: + return strconv.FormatFloat(float64(v), 'f', -1, 32) + case int: + return strconv.Itoa(v) + + // Anything else return empty string + default: + return "" + } + } + + // function to convert string to date time + funcMap["ToDate"] = func(dateString string) time.Time { + date, err := time.Parse("2006-01-02", dateString) + if err != nil { + return time.Now() + } + return date + } + + // enable passing slice of interface to functions + funcMap["SliceAny"] = func(args ...any) []any { + return args + } + + // enable passing slice of string to functions + funcMap["SliceString"] = func(args ...string) []string { + return args + } + + // enable passing slice of uint to functions + funcMap["SliceUInt"] = func(args ...uint) []uint { + return args + } + + // enable passing slice of int to functions + funcMap["SliceInt"] = func(args ...int) []int { + return args + } + + // enable passing slice of int to functions + funcMap["SliceF32"] = func(args ...float32) []float32 { + return args + } + + // Add passed in function map to the function map + if fm != nil { + for k, v := range *fm { + funcMap[k] = v + } + } + + return &funcMap +} + +// function to build the function map for the template engine from the global faker +func templateFunc(temp string, funcs *template.FuncMap, data any) (string, error) { + if temp == "" { + return "", fmt.Errorf("template parameter is empty") + } + + // Create a new template and parse + template_gen, err := template.New("CodeRun").Funcs(*funcs).Parse(temp) + if err != nil { + return "", err + } + + b := &bytes.Buffer{} + err = template_gen.Execute(b, data) + if err != nil { + return "", err + } + + // Return the result + return strings.ReplaceAll(b.String(), "\\n", "\n"), nil + +} + +// addTemplateLookup will add the template functions to the global lookup +func addTemplateLookup() { + AddFuncLookup("template", Info{ + Display: "Template", + Category: "template", + Description: "Generates document from template", + Example: `{{Firstname}} {{Lastname}} + +// output +Markus Moen`, + Output: "string", + ContentType: "text/plain", + Params: []Param{ + {Field: "template", Display: "Template", Type: "string", Description: "Golang template to generate the document from"}, + {Field: "data", Display: "Custom Data", Type: "string", Default: "", Optional: true, Description: "Custom data to pass to the template"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + tpl, err := info.GetString(m, "template") + if err != nil { + return nil, err + } + + data, err := info.GetAny(m, "data") + if err != nil { + return nil, err + } + + templateOut, err := templateFunc(tpl, templateFuncMap(f, nil), &TemplateOptions{Data: data}) + if err != nil { + return nil, err + } + + return templateOut, nil + }, + }) + + AddFuncLookup("markdown", Info{ + Display: "Random markdown document", + Category: "template", + Description: "Lightweight markup language used for formatting plain text", + Example: `# PurpleSheep5 + +*Author: Amie Feil* + +Quarterly without week it hungry thing someone. Him regularly today whomever this revolt hence. From his timing as quantity us these. Yours live these frantic not may another. How this ours his them those whose. + +Them batch its Iraqi most that few. Abroad cheese this whereas next how there. Gorgeous genetics time choir fiction therefore yourselves. Am those infrequently heap software quarterly rather. Punctuation yellow where several his orchard to. + +## Table of Contents +- [Installation](#installation) +- [Usage](#usage) +- [License](#license) + +## Installation +'''bash +pip install PurpleSheep5 +''' + +## Usage +'''python +result = purplesheep5.process("funny request") +print("purplesheep5 result:", "in progress") +''' + +## License +MIT`, + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + template_result, err := templateFunc(templateMarkdown, templateFuncMap(f, nil), &MarkdownOptions{}) + return string(template_result), err + }, + }) + + AddFuncLookup("email_text", Info{ + Display: "Random text email Document", + Category: "template", + Description: "Written content of an email message, including the sender's message to the recipient", + Example: `Subject: Greetings from Marcel! + +Dear Pagac, + +Hello there! Sending positive vibes your way. + +I hope you're doing great. May your week be filled with joy. + +Virtually woman where team late quarterly without week it hungry. Thing someone him regularly today whomever this revolt hence from. His timing as quantity us these yours live these frantic. Not may another how this ours his them those whose. Them batch its Iraqi most that few abroad cheese this. + +Whereas next how there gorgeous genetics time choir fiction therefore. Yourselves am those infrequently heap software quarterly rather punctuation yellow. Where several his orchard to frequently hence victorious boxers each. Does auspicious yourselves first soup tomorrow this that must conclude. Anyway some yearly who cough laugh himself both yet rarely. + +Me dolphin intensely block would leap plane us first then. Down them eager would hundred super throughout animal yet themselves. Been group flock shake part purchase up usually it her. None it hers boat what their there Turkmen moreover one. Lebanese to brace these shower in it everybody should whatever. + +I'm curious to know what you think about it. If you have a moment, please feel free to check out the project on Bitbucket + +I'm eager to hear what you think. Looking forward to your feedback! + +Thank you for your consideration! Thanks in advance for your time. + +Kind regards +Milford Johnston +jamelhaag@king.org +(507)096-3058`, + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + template_result, err := templateFunc(templateEmail, templateFuncMap(f, nil), &EmailOptions{}) + return string(template_result), err + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/time.go b/vendor/github.com/brianvoe/gofakeit/v7/time.go new file mode 100644 index 0000000000..555890349e --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/time.go @@ -0,0 +1,501 @@ +package gofakeit + +import ( + "strconv" + "strings" + "time" +) + +var currentYear = time.Now().Year() + +// Date will generate a random time.Time struct +func Date() time.Time { return date(GlobalFaker) } + +// Date will generate a random time.Time struct +func (f *Faker) Date() time.Time { return date(f) } + +func date(f *Faker) time.Time { + return time.Date(year(f), time.Month(month(f)), day(f), hour(f), minute(f), second(f), nanoSecond(f), time.UTC) +} + +// PastDate will generate a random past time.Time struct +func PastDate() time.Time { return pastDate(GlobalFaker) } + +// PastDate will generate a random past time.Time struct +func (f *Faker) PastDate() time.Time { return pastDate(f) } + +func pastDate(f *Faker) time.Time { + return time.Now().Add(time.Hour * -time.Duration(number(f, 1, 12))) +} + +// FutureDate will generate a random future time.Time struct +func FutureDate() time.Time { return futureDate(GlobalFaker) } + +// FutureDate will generate a random future time.Time struct +func (f *Faker) FutureDate() time.Time { return futureDate(f) } + +func futureDate(f *Faker) time.Time { + return time.Now().Add(time.Hour * time.Duration(number(f, 1, 12))) +} + +// DateRange will generate a random time.Time struct between a start and end date +func DateRange(start, end time.Time) time.Time { return dateRange(GlobalFaker, start, end) } + +// DateRange will generate a random time.Time struct between a start and end date +func (f *Faker) DateRange(start, end time.Time) time.Time { return dateRange(f, start, end) } + +func dateRange(f *Faker, start time.Time, end time.Time) time.Time { + return time.Unix(0, int64(number(f, int(start.UnixNano()), int(end.UnixNano())))).UTC() +} + +// NanoSecond will generate a random nano second +func NanoSecond() int { return nanoSecond(GlobalFaker) } + +// NanoSecond will generate a random nano second +func (f *Faker) NanoSecond() int { return nanoSecond(f) } + +func nanoSecond(f *Faker) int { return number(f, 0, 999999999) } + +// Second will generate a random second +func Second() int { return second(GlobalFaker) } + +// Second will generate a random second +func (f *Faker) Second() int { return second(f) } + +func second(f *Faker) int { return number(f, 0, 59) } + +// Minute will generate a random minute +func Minute() int { return minute(GlobalFaker) } + +// Minute will generate a random minute +func (f *Faker) Minute() int { return minute(f) } + +func minute(f *Faker) int { return number(f, 0, 59) } + +// Hour will generate a random hour - in military time +func Hour() int { return hour(GlobalFaker) } + +// Hour will generate a random hour - in military time +func (f *Faker) Hour() int { return hour(f) } + +func hour(f *Faker) int { return number(f, 0, 23) } + +// Day will generate a random day between 1 - 31 +func Day() int { return day(GlobalFaker) } + +// Day will generate a random day between 1 - 31 +func (f *Faker) Day() int { return day(f) } + +func day(f *Faker) int { return number(f, 1, 31) } + +// WeekDay will generate a random weekday string (Monday-Sunday) +func WeekDay() string { return weekDay(GlobalFaker) } + +// WeekDay will generate a random weekday string (Monday-Sunday) +func (f *Faker) WeekDay() string { return weekDay(f) } + +func weekDay(f *Faker) string { return time.Weekday(number(f, 0, 6)).String() } + +// Month will generate a random month int +func Month() int { return month(GlobalFaker) } + +// Month will generate a random month int +func (f *Faker) Month() int { return month(f) } + +func month(f *Faker) int { return number(f, 1, 12) } + +// MonthString will generate a random month string +func MonthString() string { return monthString(GlobalFaker) } + +// MonthString will generate a random month string +func (f *Faker) MonthString() string { return monthString(f) } + +func monthString(f *Faker) string { return time.Month(number(f, 1, 12)).String() } + +// Year will generate a random year between 1900 - current year +func Year() int { return year(GlobalFaker) } + +// Year will generate a random year between 1900 - current year +func (f *Faker) Year() int { return year(f) } + +func year(f *Faker) int { return number(f, 1900, currentYear) } + +// TimeZone will select a random timezone string +func TimeZone() string { return timeZone(GlobalFaker) } + +// TimeZone will select a random timezone string +func (f *Faker) TimeZone() string { return timeZone(f) } + +func timeZone(f *Faker) string { return getRandValue(f, []string{"timezone", "text"}) } + +// TimeZoneFull will select a random full timezone string +func TimeZoneFull() string { return timeZoneFull(GlobalFaker) } + +// TimeZoneFull will select a random full timezone string +func (f *Faker) TimeZoneFull() string { return timeZoneFull(f) } + +func timeZoneFull(f *Faker) string { return getRandValue(f, []string{"timezone", "full"}) } + +// TimeZoneRegion will select a random region style timezone string, e.g. "America/Chicago" +func TimeZoneRegion() string { return timeZoneRegion(GlobalFaker) } + +// TimeZoneRegion will select a random region style timezone string, e.g. "America/Chicago" +func (f *Faker) TimeZoneRegion() string { return timeZoneRegion(f) } + +func timeZoneRegion(f *Faker) string { return getRandValue(f, []string{"timezone", "region"}) } + +// TimeZoneAbv will select a random timezone abbreviation string +func TimeZoneAbv() string { return timeZoneAbv(GlobalFaker) } + +// TimeZoneAbv will select a random timezone abbreviation string +func (f *Faker) TimeZoneAbv() string { return timeZoneAbv(f) } + +func timeZoneAbv(f *Faker) string { return getRandValue(f, []string{"timezone", "abr"}) } + +// TimeZoneOffset will select a random timezone offset +func TimeZoneOffset() float32 { return timeZoneOffset(GlobalFaker) } + +// TimeZoneOffset will select a random timezone offset +func (f *Faker) TimeZoneOffset() float32 { return timeZoneOffset(f) } + +func timeZoneOffset(f *Faker) float32 { + value, _ := strconv.ParseFloat(getRandValue(f, []string{"timezone", "offset"}), 32) + return float32(value) +} + +// javaDateFormatToGolangDateFormat converts java date format into go date format +func javaDateFormatToGolangDateFormat(format string) string { + format = strings.Replace(format, "ddd", "_2", -1) + format = strings.Replace(format, "dd", "02", -1) + format = strings.Replace(format, "d", "2", -1) + + format = strings.Replace(format, "HH", "15", -1) + + format = strings.Replace(format, "hh", "03", -1) + format = strings.Replace(format, "h", "3", -1) + + format = strings.Replace(format, "mm", "04", -1) + format = strings.Replace(format, "m", "4", -1) + + format = strings.Replace(format, "ss", "05", -1) + format = strings.Replace(format, "s", "5", -1) + + format = strings.Replace(format, "yyyy", "2006", -1) + format = strings.Replace(format, "yy", "06", -1) + format = strings.Replace(format, "y", "06", -1) + + format = strings.Replace(format, "SSS", "000", -1) + + format = strings.Replace(format, "a", "pm", -1) + format = strings.Replace(format, "aa", "PM", -1) + + format = strings.Replace(format, "MMMM", "January", -1) + format = strings.Replace(format, "MMM", "Jan", -1) + format = strings.Replace(format, "MM", "01", -1) + format = strings.Replace(format, "M", "1", -1) + + format = strings.Replace(format, "ZZ", "-0700", -1) + + if !strings.Contains(format, "Z07") { + format = strings.Replace(format, "Z", "-07", -1) + } + + format = strings.Replace(format, "zz:zz", "Z07:00", -1) + format = strings.Replace(format, "zzzz", "Z0700", -1) + format = strings.Replace(format, "z", "MST", -1) + + format = strings.Replace(format, "EEEE", "Monday", -1) + format = strings.Replace(format, "E", "Mon", -1) + + return format +} + +func addDateTimeLookup() { + AddFuncLookup("date", Info{ + Display: "Date", + Category: "time", + Description: "Representation of a specific day, month, and year, often used for chronological reference", + Example: "2006-01-02T15:04:05Z07:00", + Output: "string", + Params: []Param{ + { + Field: "format", + Display: "Format", + Type: "string", + Default: "RFC3339", + Options: []string{"ANSIC", "UnixDate", "RubyDate", "RFC822", "RFC822Z", "RFC850", "RFC1123", "RFC1123Z", "RFC3339", "RFC3339Nano"}, + Description: "Date time string format output. You may also use golang time format or java time format", + }, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + format, err := info.GetString(m, "format") + if err != nil { + return nil, err + } + + switch format { + case "ANSIC": + return f.Date().Format(time.ANSIC), nil + case "UnixDate": + return f.Date().Format(time.UnixDate), nil + case "RubyDate": + return f.Date().Format(time.RubyDate), nil + case "RFC822": + return f.Date().Format(time.RFC822), nil + case "RFC822Z": + return f.Date().Format(time.RFC822Z), nil + case "RFC850": + return f.Date().Format(time.RFC850), nil + case "RFC1123": + return f.Date().Format(time.RFC1123), nil + case "RFC1123Z": + return f.Date().Format(time.RFC1123Z), nil + case "RFC3339": + return f.Date().Format(time.RFC3339), nil + case "RFC3339Nano": + return f.Date().Format(time.RFC3339Nano), nil + default: + if format == "" { + return f.Date().Format(time.RFC3339), nil + } + + return f.Date().Format(javaDateFormatToGolangDateFormat(format)), nil + } + }, + }) + + AddFuncLookup("daterange", Info{ + Display: "DateRange", + Category: "time", + Description: "Random date between two ranges", + Example: "2006-01-02T15:04:05Z07:00", + Output: "string", + Params: []Param{ + { + Field: "startdate", + Display: "Start Date", + Type: "string", + Default: "1970-01-01", + Description: "Start date time string", + }, + { + Field: "enddate", + Display: "End Date", + Type: "string", + Default: time.Now().Format("2006-01-02"), + Description: "End date time string", + }, + { + Field: "format", + Display: "Format", + Type: "string", + Default: "yyyy-MM-dd", + Description: "Date time string format", + }, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + format, err := info.GetString(m, "format") + if err != nil { + return nil, err + } + format = javaDateFormatToGolangDateFormat(format) + + startdate, err := info.GetString(m, "startdate") + if err != nil { + return nil, err + } + startDateTime, err := time.Parse(format, startdate) + if err != nil { + return nil, err + } + + enddate, err := info.GetString(m, "enddate") + if err != nil { + return nil, err + } + endDateTime, err := time.Parse(format, enddate) + if err != nil { + return nil, err + } + + return DateRange(startDateTime, endDateTime).Format(format), nil + }, + }) + + AddFuncLookup("pastdate", Info{ + Display: "PastDate", + Category: "time", + Description: "Date that has occurred before the current moment in time", + Example: "2007-01-24 13:00:35.820738079 +0000 UTC", + Output: "time", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pastDate(f), nil + }, + }) + + AddFuncLookup("futuredate", Info{ + Display: "FutureDate", + Category: "time", + Description: "Date that has occurred after the current moment in time", + Example: "2107-01-24 13:00:35.820738079 +0000 UTC", + Output: "time", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return futureDate(f), nil + }, + }) + + AddFuncLookup("nanosecond", Info{ + Display: "Nanosecond", + Category: "time", + Description: "Unit of time equal to One billionth (10^-9) of a second", + Example: "196446360", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nanoSecond(f), nil + }, + }) + + AddFuncLookup("second", Info{ + Display: "Second", + Category: "time", + Description: "Unit of time equal to 1/60th of a minute", + Example: "43", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return second(f), nil + }, + }) + + AddFuncLookup("minute", Info{ + Display: "Minute", + Category: "time", + Description: "Unit of time equal to 60 seconds", + Example: "34", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return minute(f), nil + }, + }) + + AddFuncLookup("hour", Info{ + Display: "Hour", + Category: "time", + Description: "Unit of time equal to 60 minutes", + Example: "8", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return hour(f), nil + }, + }) + + AddFuncLookup("day", Info{ + Display: "Day", + Category: "time", + Description: "24-hour period equivalent to one rotation of Earth on its axis", + Example: "12", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return day(f), nil + }, + }) + + AddFuncLookup("weekday", Info{ + Display: "Weekday", + Category: "time", + Description: "Day of the week excluding the weekend", + Example: "Friday", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return weekDay(f), nil + }, + }) + + AddFuncLookup("month", Info{ + Display: "Month", + Category: "time", + Description: "Division of the year, typically 30 or 31 days long", + Example: "1", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return month(f), nil + }, + }) + + AddFuncLookup("monthstring", Info{ + Display: "Month String", + Category: "time", + Description: "String Representation of a month name", + Example: "September", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return monthString(f), nil + }, + }) + + AddFuncLookup("year", Info{ + Display: "Year", + Category: "time", + Description: "Period of 365 days, the time Earth takes to orbit the Sun", + Example: "1900", + Output: "int", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return year(f), nil + }, + }) + + AddFuncLookup("timezone", Info{ + Display: "Timezone", + Category: "time", + Description: "Region where the same standard time is used, based on longitudinal divisions of the Earth", + Example: "Kaliningrad Standard Time", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return timeZone(f), nil + }, + }) + + AddFuncLookup("timezoneabv", Info{ + Display: "Timezone Abbreviation", + Category: "time", + Description: "Abbreviated 3-letter word of a timezone", + Example: "KST", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return timeZoneAbv(f), nil + }, + }) + + AddFuncLookup("timezonefull", Info{ + Display: "Timezone Full", + Category: "time", + Description: "Full name of a timezone", + Example: "(UTC+03:00) Kaliningrad, Minsk", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return timeZoneFull(f), nil + }, + }) + + AddFuncLookup("timezoneoffset", Info{ + Display: "Timezone Offset", + Category: "time", + Description: "The difference in hours from Coordinated Universal Time (UTC) for a specific region", + Example: "3", + Output: "float32", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return timeZoneOffset(f), nil + }, + }) + + AddFuncLookup("timezoneregion", Info{ + Display: "Timezone Region", + Category: "time", + Description: "Geographic area sharing the same standard time", + Example: "America/Alaska", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return timeZoneRegion(f), nil + }, + }) + +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/weighted.go b/vendor/github.com/brianvoe/gofakeit/v7/weighted.go new file mode 100644 index 0000000000..cedfe42d05 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/weighted.go @@ -0,0 +1,106 @@ +package gofakeit + +import ( + "errors" +) + +// Weighted will take in an array of options and weights and return a random selection based upon its indexed weight +func Weighted(options []any, weights []float32) (any, error) { + return weighted(GlobalFaker, options, weights) +} + +// Weighted will take in an array of options and weights and return a random selection based upon its indexed weight +func (f *Faker) Weighted(options []any, weights []float32) (any, error) { + return weighted(f, options, weights) +} + +// Weighted will take in an array of options and weights and return a random selection based upon its indexed weight +func weighted(f *Faker, options []any, weights []float32) (any, error) { + ol := len(options) + wl := len(weights) + + // If options length is 1 just return it back + if ol == 1 { + return options[0], nil + } + + // Make sure they are passing in options + if ol == 0 { + return nil, errors.New("didnt pass options") + } + + // Make sure they are passing in weights + if wl == 0 { + return nil, errors.New("didnt pass weights") + } + + // Make sure they are passing in the same length + if ol != wl { + return nil, errors.New("options and weights need to be the same length") + } + + // Compute the discrete cumulative density from the sum of the weights + cdf := make([]float32, wl) + var sumOfWeights float32 = 0.0 + for i, weight := range weights { + if i > 0 { + cdf[i] = cdf[i-1] + weight + sumOfWeights += weight + continue + } + + cdf[i] = weight + sumOfWeights += weight + } + + // Get rand value from a multple of sumOfWeights + randSumOfWeights := f.Float32() * sumOfWeights + + var l int = 0 + var h int = wl - 1 + for l <= h { + m := l + (h-l)/2 + if randSumOfWeights <= cdf[m] { + if m == 0 || (m > 0 && randSumOfWeights > cdf[m-1]) { + return options[m], nil + } + h = m - 1 + } else { + l = m + 1 + } + } + + return nil, errors.New("end of function") +} + +func addWeightedLookup() { + AddFuncLookup("weighted", Info{ + Display: "Weighted", + Category: "misc", + Description: "Randomly select a given option based upon an equal amount of weights", + Example: "[hello, 2, 6.9],[1, 2, 3] => 6.9", + Output: "any", + Params: []Param{ + {Field: "options", Display: "Options", Type: "[]string", Description: "Array of any values"}, + {Field: "weights", Display: "Weights", Type: "[]float", Description: "Array of weights"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + options, err := info.GetStringArray(m, "options") + if err != nil { + return nil, err + } + + weights, err := info.GetFloat32Array(m, "weights") + if err != nil { + return nil, err + } + + optionsInterface := make([]any, len(options)) + for i, o := range options { + optionsInterface[i] = o + } + + return weighted(f, optionsInterface, weights) + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_adjective.go b/vendor/github.com/brianvoe/gofakeit/v7/word_adjective.go new file mode 100644 index 0000000000..01efb032ba --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_adjective.go @@ -0,0 +1,180 @@ +package gofakeit + +// Adjective will generate a random adjective +func Adjective() string { return adjective(GlobalFaker) } + +// Adjective will generate a random adjective +func (f *Faker) Adjective() string { return adjective(f) } + +func adjective(f *Faker) string { + var adjType = map[int]string{ + 0: "adjective_descriptive", + 1: "adjective_quantitative", + 2: "adjective_proper", + 3: "adjective_demonstrative", + 4: "adjective_possessive", + 5: "adjective_interrogative", + 6: "adjective_indefinite", + } + return getRandValue(f, []string{"word", adjType[number(f, 0, 6)]}) +} + +// AdjectiveDescriptive will generate a random descriptive adjective +func AdjectiveDescriptive() string { return adjectiveDescriptive(GlobalFaker) } + +// AdjectiveDescriptive will generate a random descriptive adjective +func (f *Faker) AdjectiveDescriptive() string { return adjectiveDescriptive(f) } + +func adjectiveDescriptive(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_descriptive"}) +} + +// AdjectiveQuantitative will generate a random quantitative adjective +func AdjectiveQuantitative() string { return adjectiveQuantitative(GlobalFaker) } + +// AdjectiveQuantitative will generate a random quantitative adjective +func (f *Faker) AdjectiveQuantitative() string { return adjectiveQuantitative(f) } + +func adjectiveQuantitative(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_quantitative"}) +} + +// AdjectiveProper will generate a random proper adjective +func AdjectiveProper() string { return adjectiveProper(GlobalFaker) } + +// AdjectiveProper will generate a random proper adjective +func (f *Faker) AdjectiveProper() string { return adjectiveProper(f) } + +func adjectiveProper(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_proper"}) +} + +// AdjectiveDemonstrative will generate a random demonstrative adjective +func AdjectiveDemonstrative() string { return adjectiveDemonstrative(GlobalFaker) } + +// AdjectiveDemonstrative will generate a random demonstrative adjective +func (f *Faker) AdjectiveDemonstrative() string { return adjectiveDemonstrative(f) } + +func adjectiveDemonstrative(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_demonstrative"}) +} + +// AdjectivePossessive will generate a random possessive adjective +func AdjectivePossessive() string { return adjectivePossessive(GlobalFaker) } + +// AdjectivePossessive will generate a random possessive adjective +func (f *Faker) AdjectivePossessive() string { return adjectivePossessive(f) } + +func adjectivePossessive(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_possessive"}) +} + +// AdjectiveInterrogative will generate a random interrogative adjective +func AdjectiveInterrogative() string { return adjectiveInterrogative(GlobalFaker) } + +// AdjectiveInterrogative will generate a random interrogative adjective +func (f *Faker) AdjectiveInterrogative() string { return adjectiveInterrogative(f) } + +func adjectiveInterrogative(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_interrogative"}) +} + +// AdjectiveIndefinite will generate a random indefinite adjective +func AdjectiveIndefinite() string { return adjectiveIndefinite(GlobalFaker) } + +// AdjectiveIndefinite will generate a random indefinite adjective +func (f *Faker) AdjectiveIndefinite() string { return adjectiveIndefinite(f) } + +func adjectiveIndefinite(f *Faker) string { + return getRandValue(f, []string{"word", "adjective_indefinite"}) +} + +func addWordAdjectiveLookup() { + AddFuncLookup("adjective", Info{ + Display: "Adjective", + Category: "word", + Description: "Word describing or modifying a noun", + Example: "genuine", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjective(f), nil + }, + }) + + AddFuncLookup("adjectivedescriptive", Info{ + Display: "Descriptive Adjective", + Category: "word", + Description: "Adjective that provides detailed characteristics about a noun", + Example: "brave", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectiveDescriptive(f), nil + }, + }) + + AddFuncLookup("adjectivequantitative", Info{ + Display: "Quantitative Adjective", + Category: "word", + Description: "Adjective that indicates the quantity or amount of something", + Example: "a little", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectiveQuantitative(f), nil + }, + }) + + AddFuncLookup("adjectiveproper", Info{ + Display: "Proper Adjective", + Category: "word", + Description: "Adjective derived from a proper noun, often used to describe nationality or origin", + Example: "Afghan", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectiveProper(f), nil + }, + }) + + AddFuncLookup("adjectivedemonstrative", Info{ + Display: "Demonstrative Adjective", + Category: "word", + Description: "Adjective used to point out specific things", + Example: "this", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectiveDemonstrative(f), nil + }, + }) + + AddFuncLookup("adjectivepossessive", Info{ + Display: "Possessive Adjective", + Category: "word", + Description: "Adjective indicating ownership or possession", + Example: "my", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectivePossessive(f), nil + }, + }) + + AddFuncLookup("adjectiveinterrogative", Info{ + Display: "Interrogative Adjective", + Category: "word", + Description: "Adjective used to ask questions", + Example: "what", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectiveInterrogative(f), nil + }, + }) + + AddFuncLookup("adjectiveindefinite", Info{ + Display: "Indefinite Adjective", + Category: "word", + Description: "Adjective describing a non-specific noun", + Example: "few", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adjectiveIndefinite(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_adverb.go b/vendor/github.com/brianvoe/gofakeit/v7/word_adverb.go new file mode 100644 index 0000000000..4cafb8a840 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_adverb.go @@ -0,0 +1,174 @@ +package gofakeit + +// Adverb will generate a random adverb +func Adverb() string { return adverb(GlobalFaker) } + +// Adverb will generate a random adverb +func (f *Faker) Adverb() string { return adverb(f) } + +func adverb(f *Faker) string { + var adverbType = map[int]string{ + 0: "adverb_manner", + 1: "adverb_degree", + 2: "adverb_place", + 3: "adverb_time_definite", + 4: "adverb_time_indefinite", + 5: "adverb_frequency_definite", + 6: "adverb_frequency_indefinite", + } + return getRandValue(f, []string{"word", adverbType[number(f, 0, 6)]}) +} + +// AdverbManner will generate a random manner adverb +func AdverbManner() string { return adverbManner(GlobalFaker) } + +// AdverbManner will generate a random manner adverb +func (f *Faker) AdverbManner() string { return adverbManner(f) } + +func adverbManner(f *Faker) string { return getRandValue(f, []string{"word", "adverb_manner"}) } + +// AdverbDegree will generate a random degree adverb +func AdverbDegree() string { return adverbDegree(GlobalFaker) } + +// AdverbDegree will generate a random degree adverb +func (f *Faker) AdverbDegree() string { return adverbDegree(f) } + +func adverbDegree(f *Faker) string { return getRandValue(f, []string{"word", "adverb_degree"}) } + +// AdverbPlace will generate a random place adverb +func AdverbPlace() string { return adverbPlace(GlobalFaker) } + +// AdverbPlace will generate a random place adverb +func (f *Faker) AdverbPlace() string { return adverbPlace(f) } + +func adverbPlace(f *Faker) string { return getRandValue(f, []string{"word", "adverb_place"}) } + +// AdverbTimeDefinite will generate a random time definite adverb +func AdverbTimeDefinite() string { return adverbTimeDefinite(GlobalFaker) } + +// AdverbTimeDefinite will generate a random time definite adverb +func (f *Faker) AdverbTimeDefinite() string { return adverbTimeDefinite(f) } + +func adverbTimeDefinite(f *Faker) string { + return getRandValue(f, []string{"word", "adverb_time_definite"}) +} + +// AdverbTimeIndefinite will generate a random time indefinite adverb +func AdverbTimeIndefinite() string { return adverbTimeIndefinite(GlobalFaker) } + +// AdverbTimeIndefinite will generate a random time indefinite adverb +func (f *Faker) AdverbTimeIndefinite() string { return adverbTimeIndefinite(f) } + +func adverbTimeIndefinite(f *Faker) string { + return getRandValue(f, []string{"word", "adverb_time_indefinite"}) +} + +// AdverbFrequencyDefinite will generate a random frequency definite adverb +func AdverbFrequencyDefinite() string { return adverbFrequencyDefinite(GlobalFaker) } + +// AdverbFrequencyDefinite will generate a random frequency definite adverb +func (f *Faker) AdverbFrequencyDefinite() string { return adverbFrequencyDefinite(f) } + +func adverbFrequencyDefinite(f *Faker) string { + return getRandValue(f, []string{"word", "adverb_frequency_definite"}) +} + +// AdverbFrequencyIndefinite will generate a random frequency indefinite adverb +func AdverbFrequencyIndefinite() string { return adverbFrequencyIndefinite(GlobalFaker) } + +// AdverbFrequencyIndefinite will generate a random frequency indefinite adverb +func (f *Faker) AdverbFrequencyIndefinite() string { return adverbFrequencyIndefinite(f) } + +func adverbFrequencyIndefinite(f *Faker) string { + return getRandValue(f, []string{"word", "adverb_frequency_indefinite"}) +} + +func addWordAdverbLookup() { + AddFuncLookup("adverb", Info{ + Display: "Adverb", + Category: "word", + Description: "Word that modifies verbs, adjectives, or other adverbs", + Example: "smoothly", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverb(f), nil + }, + }) + + AddFuncLookup("adverbmanner", Info{ + Display: "Adverb Manner", + Category: "word", + Description: "Adverb that describes how an action is performed", + Example: "stupidly", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbManner(f), nil + }, + }) + + AddFuncLookup("adverbdegree", Info{ + Display: "Adverb Degree", + Category: "word", + Description: "Adverb that indicates the degree or intensity of an action or adjective", + Example: "intensely", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbDegree(f), nil + }, + }) + + AddFuncLookup("adverbplace", Info{ + Display: "Adverb Place", + Category: "word", + Description: "Adverb that indicates the location or direction of an action", + Example: "east", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbPlace(f), nil + }, + }) + + AddFuncLookup("adverbtimedefinite", Info{ + Display: "Adverb Time Definite", + Category: "word", + Description: "Adverb that specifies the exact time an action occurs", + Example: "now", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbTimeDefinite(f), nil + }, + }) + + AddFuncLookup("adverbtimeindefinite", Info{ + Display: "Adverb Time Indefinite", + Category: "word", + Description: "Adverb that gives a general or unspecified time frame", + Example: "already", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbTimeIndefinite(f), nil + }, + }) + + AddFuncLookup("adverbfrequencydefinite", Info{ + Display: "Adverb Frequency Definite", + Category: "word", + Description: "Adverb that specifies how often an action occurs with a clear frequency", + Example: "hourly", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbFrequencyDefinite(f), nil + }, + }) + + AddFuncLookup("adverbfrequencyindefinite", Info{ + Display: "Adverb Frequency Indefinite", + Category: "word", + Description: "Adverb that specifies how often an action occurs without specifying a particular frequency", + Example: "occasionally", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return adverbFrequencyIndefinite(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_comment.go b/vendor/github.com/brianvoe/gofakeit/v7/word_comment.go new file mode 100644 index 0000000000..f73d1f0356 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_comment.go @@ -0,0 +1,72 @@ +package gofakeit + +import ( + "strings" +) + +// Comment will generate a random statement or remark expressing an opinion, observation, or reaction +func Comment() string { return comment(GlobalFaker) } + +// Comment will generate a random statement or remark expressing an opinion, observation, or reaction +func (f *Faker) Comment() string { return comment(f) } + +func comment(f *Faker) string { + structures := [][]string{ + {"interjection", "adjective", "noun", "verb", "adverb"}, + {"noun", "verb", "preposition", "determiner", "adjective", "noun"}, + {"noun", "verb", "adverb"}, + {"adjective", "noun", "verb"}, + {"noun", "verb", "preposition", "noun"}, + } + + // Randomly select a structure + structure := structures[number(f, 0, len(structures)-1)] + + // Build the sentence + var commentParts []string + for _, wordType := range structure { + switch wordType { + case "noun": + commentParts = append(commentParts, noun(f)) + case "verb": + commentParts = append(commentParts, verb(f)) + case "adjective": + commentParts = append(commentParts, adjective(f)) + case "adverb": + commentParts = append(commentParts, adverb(f)) + case "interjection": + commentParts = append(commentParts, interjection(f)) + case "preposition": + commentParts = append(commentParts, preposition(f)) + case "determiner": + commentParts = append(commentParts, nounDeterminer(f)) + default: + // Should never hit + panic("Invalid word type") + } + } + + // Combine the words into a sentence + sentence := strings.Join(commentParts, " ") + + // Capitalize the first letter + sentence = title(sentence) + + // Add a period to the end of the sentence + sentence = sentence + "." + + return sentence +} + +func addWordCommentLookup() { + AddFuncLookup("comment", Info{ + Display: "Comment", + Category: "word", + Description: "Statement or remark expressing an opinion, observation, or reaction", + Example: "wow", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return interjection(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_connective.go b/vendor/github.com/brianvoe/gofakeit/v7/word_connective.go new file mode 100644 index 0000000000..92dc025f54 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_connective.go @@ -0,0 +1,159 @@ +package gofakeit + +// Connective will generate a random connective +func Connective() string { return connective(GlobalFaker) } + +// Connective will generate a random connective +func (f *Faker) Connective() string { return connective(f) } + +func connective(f *Faker) string { + var connectiveType = map[int]string{ + 0: "connective_time", + 1: "connective_comparative", + 2: "connective_complaint", + 3: "connective_listing", + 4: "connective_casual", + 5: "connective_examplify", + } + return getRandValue(f, []string{"word", connectiveType[number(f, 0, 5)]}) +} + +// ConnectiveTime will generate a random connective time +func ConnectiveTime() string { return connectiveTime(GlobalFaker) } + +// ConnectiveTime will generate a random connective time + +func (f *Faker) ConnectiveTime() string { return connectiveTime(f) } + +func connectiveTime(f *Faker) string { + return getRandValue(f, []string{"word", "connective_time"}) +} + +// ConnectiveComparative will generate a random comparative connective +func ConnectiveComparative() string { return connectiveComparative(GlobalFaker) } + +// ConnectiveComparative will generate a random comparative connective +func (f *Faker) ConnectiveComparative() string { return connectiveComparative(f) } + +func connectiveComparative(f *Faker) string { + return getRandValue(f, []string{"word", "connective_comparative"}) +} + +// ConnectiveComplaint will generate a random complaint connective +func ConnectiveComplaint() string { return connectiveComplaint(GlobalFaker) } + +// ConnectiveComplaint will generate a random complaint connective +func (f *Faker) ConnectiveComplaint() string { return connectiveComplaint(f) } + +func connectiveComplaint(f *Faker) string { + return getRandValue(f, []string{"word", "connective_complaint"}) +} + +// ConnectiveListing will generate a random listing connective +func ConnectiveListing() string { return connectiveListing(GlobalFaker) } + +// ConnectiveListing will generate a random listing connective +func (f *Faker) ConnectiveListing() string { return connectiveListing(f) } + +func connectiveListing(f *Faker) string { + return getRandValue(f, []string{"word", "connective_listing"}) +} + +// ConnectiveCasual will generate a random casual connective +func ConnectiveCasual() string { return connectiveCasual(GlobalFaker) } + +// ConnectiveCasual will generate a random casual connective +func (f *Faker) ConnectiveCasual() string { return connectiveCasual(f) } + +func connectiveCasual(f *Faker) string { + return getRandValue(f, []string{"word", "connective_casual"}) +} + +// ConnectiveExamplify will generate a random examplify connective +func ConnectiveExamplify() string { return connectiveExamplify(GlobalFaker) } + +// ConnectiveExamplify will generate a random examplify connective +func (f *Faker) ConnectiveExamplify() string { return connectiveExamplify(f) } + +func connectiveExamplify(f *Faker) string { + return getRandValue(f, []string{"word", "connective_examplify"}) +} + +func addWordConnectiveLookup() { + AddFuncLookup("connective", Info{ + Display: "Connective", + Category: "word", + Description: "Word used to connect words or sentences", + Example: "such as", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connective(f), nil + }, + }) + + AddFuncLookup("connectivetime", Info{ + Display: "Connective Time", + Category: "word", + Description: "Connective word used to indicate a temporal relationship between events or actions", + Example: "finally", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connectiveTime(f), nil + }, + }) + + AddFuncLookup("connectivecomparative", Info{ + Display: "Connective Comparitive", + Category: "word", + Description: "Connective word used to indicate a comparison between two or more things", + Example: "in addition", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connectiveComparative(f), nil + }, + }) + + AddFuncLookup("connectivecomplaint", Info{ + Display: "Connective Complaint", + Category: "word", + Description: "Connective word used to express dissatisfaction or complaints about a situation", + Example: "besides", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connectiveComplaint(f), nil + }, + }) + + AddFuncLookup("connectivelisting", Info{ + Display: "Connective Listing", + Category: "word", + Description: "Connective word used to list or enumerate items or examples", + Example: "firstly", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connectiveListing(f), nil + }, + }) + + AddFuncLookup("connectivecasual", Info{ + Display: "Connective Casual", + Category: "word", + Description: "Connective word used to indicate a cause-and-effect relationship between events or actions", + Example: "an outcome of", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connectiveCasual(f), nil + }, + }) + + AddFuncLookup("connectiveexamplify", Info{ + Display: "Connective Examplify", + Category: "word", + Description: "Connective word used to provide examples or illustrations of a concept or idea", + Example: "then", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return connectiveExamplify(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_general.go b/vendor/github.com/brianvoe/gofakeit/v7/word_general.go new file mode 100644 index 0000000000..548ef12510 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_general.go @@ -0,0 +1,37 @@ +package gofakeit + +import ( + "strings" + + "github.com/brianvoe/gofakeit/v7/data" +) + +// Word will generate a random word +func Word() string { return word(GlobalFaker) } + +// Word will generate a random word +func (f *Faker) Word() string { return word(f) } + +func word(f *Faker) string { + word := getRandValue(f, []string{"word", randomString(f, data.WordKeys)}) + + // Word may return a couple of words, if so we will split on space and return a random word + if strings.Contains(word, " ") { + return randomString(f, strings.Split(word, " ")) + } + + return word +} + +func addWordGeneralLookup() { + AddFuncLookup("word", Info{ + Display: "Word", + Category: "word", + Description: "Basic unit of language representing a concept or thing, consisting of letters and having meaning", + Example: "man", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return word(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_grammar.go b/vendor/github.com/brianvoe/gofakeit/v7/word_grammar.go new file mode 100644 index 0000000000..b3690beef4 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_grammar.go @@ -0,0 +1,34 @@ +package gofakeit + +import ( + "unicode" +) + +// SentenceSimple will generate a random simple sentence +func SentenceSimple() string { return sentenceSimple(GlobalFaker) } + +// SentenceSimple will generate a random simple sentence +func (f *Faker) SentenceSimple() string { return sentenceSimple(f) } + +func sentenceSimple(f *Faker) string { + // simple sentence consists of a noun phrase and a verb phrase + str := phraseNoun(f) + " " + phraseVerb(f) + "." + + // capitalize the first letter + strR := []rune(str) + strR[0] = unicode.ToUpper(strR[0]) + return string(strR) +} + +func addWordGrammerLookup() { + AddFuncLookup("sentencesimple", Info{ + Display: "Simple Sentence", + Category: "word", + Description: "Group of words that expresses a complete thought", + Example: "A tribe fly the lemony kitchen.", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return sentenceSimple(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_helper.go b/vendor/github.com/brianvoe/gofakeit/v7/word_helper.go new file mode 100644 index 0000000000..a1655ff59b --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_helper.go @@ -0,0 +1,45 @@ +package gofakeit + +import ( + "strings" +) + +// This will look at a few things to determine what kind of article to use for the word +func getArticle(word string) string { + // If nothing is passed return empty + if word == "" { + return "" + } + + word = strings.ToLower(word) + letters := strings.Split(word, "") + firstLetter := "" + secondLetter := "" + if len(letters) > 0 { + firstLetter = letters[0] + } + if len(letters) > 1 { + secondLetter = letters[1] + } + + // If the word starts with a, e, i, o, use an article + if firstLetter == "a" || firstLetter == "e" || firstLetter == "i" || firstLetter == "o" { + return "an" + } + + // If the word starts with a u and n or l, use an article + if firstLetter == "u" { + if secondLetter == "n" || secondLetter == "l" { + return "an" + } + } + + // If the word starts with a vowel, use an article + if firstLetter == "h" { + if secondLetter == "i" { + return "an" + } + } + + return "a" +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_misc.go b/vendor/github.com/brianvoe/gofakeit/v7/word_misc.go new file mode 100644 index 0000000000..58c8799b5a --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_misc.go @@ -0,0 +1,22 @@ +package gofakeit + +// Interjection will generate a random word expressing emotion +func Interjection() string { return interjection(GlobalFaker) } + +// Interjection will generate a random word expressing emotion +func (f *Faker) Interjection() string { return interjection(f) } + +func interjection(f *Faker) string { return getRandValue(f, []string{"word", "interjection"}) } + +func addWordMiscLookup() { + AddFuncLookup("interjection", Info{ + Display: "Interjection", + Category: "word", + Description: "Word expressing emotion", + Example: "wow", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return interjection(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_noun.go b/vendor/github.com/brianvoe/gofakeit/v7/word_noun.go new file mode 100644 index 0000000000..ad7d388cdc --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_noun.go @@ -0,0 +1,242 @@ +package gofakeit + +// Noun will generate a random noun +func Noun() string { return noun(GlobalFaker) } + +// Noun will generate a random noun +func (f *Faker) Noun() string { return noun(f) } + +func noun(f *Faker) string { + var nounType = map[int]string{ + 0: "noun_common", + 1: "noun_concrete", + 2: "noun_abstract", + 3: "noun_collective_people", + 4: "noun_collective_animal", + 5: "noun_collective_thing", + 6: "noun_countable", + 7: "noun_uncountable", + } + return getRandValue(f, []string{"word", nounType[number(f, 0, 7)]}) +} + +// NounCommon will generate a random common noun +func NounCommon() string { return nounCommon(GlobalFaker) } + +// NounCommon will generate a random common noun +func (f *Faker) NounCommon() string { return nounCommon(f) } + +func nounCommon(f *Faker) string { return getRandValue(f, []string{"word", "noun_common"}) } + +// NounConcrete will generate a random concrete noun +func NounConcrete() string { return nounConcrete(GlobalFaker) } + +// NounConcrete will generate a random concrete noun +func (f *Faker) NounConcrete() string { return nounConcrete(f) } + +func nounConcrete(f *Faker) string { return getRandValue(f, []string{"word", "noun_concrete"}) } + +// NounAbstract will generate a random abstract noun +func NounAbstract() string { return nounAbstract(GlobalFaker) } + +// NounAbstract will generate a random abstract noun +func (f *Faker) NounAbstract() string { return nounAbstract(f) } + +func nounAbstract(f *Faker) string { return getRandValue(f, []string{"word", "noun_abstract"}) } + +// NounCollectivePeople will generate a random collective noun person +func NounCollectivePeople() string { return nounCollectivePeople(GlobalFaker) } + +// NounCollectivePeople will generate a random collective noun person +func (f *Faker) NounCollectivePeople() string { return nounCollectivePeople(f) } + +func nounCollectivePeople(f *Faker) string { + return getRandValue(f, []string{"word", "noun_collective_people"}) +} + +// NounCollectiveAnimal will generate a random collective noun animal +func NounCollectiveAnimal() string { return nounCollectiveAnimal(GlobalFaker) } + +// NounCollectiveAnimal will generate a random collective noun animal +func (f *Faker) NounCollectiveAnimal() string { return nounCollectiveAnimal(f) } + +func nounCollectiveAnimal(f *Faker) string { + return getRandValue(f, []string{"word", "noun_collective_animal"}) +} + +// NounCollectiveThing will generate a random collective noun thing +func NounCollectiveThing() string { return nounCollectiveThing(GlobalFaker) } + +// NounCollectiveThing will generate a random collective noun thing +func (f *Faker) NounCollectiveThing() string { return nounCollectiveThing(f) } + +func nounCollectiveThing(f *Faker) string { + return getRandValue(f, []string{"word", "noun_collective_thing"}) +} + +// NounCountable will generate a random countable noun +func NounCountable() string { return nounCountable(GlobalFaker) } + +// NounCountable will generate a random countable noun +func (f *Faker) NounCountable() string { return nounCountable(f) } + +func nounCountable(f *Faker) string { return getRandValue(f, []string{"word", "noun_countable"}) } + +// NounUncountable will generate a random uncountable noun +func NounUncountable() string { return nounUncountable(GlobalFaker) } + +// NounUncountable will generate a random uncountable noun +func (f *Faker) NounUncountable() string { return nounUncountable(f) } + +func nounUncountable(f *Faker) string { + return getRandValue(f, []string{"word", "noun_uncountable"}) +} + +// NounProper will generate a random proper noun +func NounProper() string { return nounProper(GlobalFaker) } + +// NounProper will generate a random proper noun +func (f *Faker) NounProper() string { return nounProper(f) } + +func nounProper(f *Faker) string { + switch randInt := randIntRange(f, 1, 3); randInt { + case 1: + return getRandValue(f, []string{"celebrity", "actor"}) + case 2: + genStr, _ := generate(f, getRandValue(f, []string{"address", "city"})) + return genStr + } + + return getRandValue(f, []string{"person", "first"}) +} + +// NounDeterminer will generate a random noun determiner +func NounDeterminer() string { return nounDeterminer(GlobalFaker) } + +// NounDeterminer will generate a random noun determiner +func (f *Faker) NounDeterminer() string { return nounDeterminer(f) } + +func nounDeterminer(f *Faker) string { return getRandValue(f, []string{"word", "noun_determiner"}) } + +func addWordNounLookup() { + AddFuncLookup("noun", Info{ + Display: "Noun", + Category: "word", + Description: "Person, place, thing, or idea, named or referred to in a sentence", + Example: "aunt", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return noun(f), nil + }, + }) + + AddFuncLookup("nouncommon", Info{ + Display: "Noun Common", + Category: "word", + Description: "General name for people, places, or things, not specific or unique", + Example: "part", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounCommon(f), nil + }, + }) + + AddFuncLookup("nounconcrete", Info{ + Display: "Noun Concrete", + Category: "word", + Description: "Names for physical entities experienced through senses like sight, touch, smell, or taste", + Example: "snowman", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounConcrete(f), nil + }, + }) + + AddFuncLookup("nounabstract", Info{ + Display: "Noun Abstract", + Category: "word", + Description: "Ideas, qualities, or states that cannot be perceived with the five senses", + Example: "confusion", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounAbstract(f), nil + }, + }) + + AddFuncLookup("nouncollectivepeople", Info{ + Display: "Noun Collective People", + Category: "word", + Description: "Group of people or things regarded as a unit", + Example: "body", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounCollectivePeople(f), nil + }, + }) + + AddFuncLookup("nouncollectiveanimal", Info{ + Display: "Noun Collective Animal", + Category: "word", + Description: "Group of animals, like a 'pack' of wolves or a 'flock' of birds", + Example: "party", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounCollectiveAnimal(f), nil + }, + }) + + AddFuncLookup("nouncollectivething", Info{ + Display: "Noun Collective Thing", + Category: "word", + Description: "Group of objects or items, such as a 'bundle' of sticks or a 'cluster' of grapes", + Example: "hand", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounCollectiveThing(f), nil + }, + }) + + AddFuncLookup("nouncountable", Info{ + Display: "Noun Countable", + Category: "word", + Description: "Items that can be counted individually", + Example: "neck", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounCountable(f), nil + }, + }) + + AddFuncLookup("noununcountable", Info{ + Display: "Noun Uncountable", + Category: "word", + Description: "Items that can't be counted individually", + Example: "seafood", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounUncountable(f), nil + }, + }) + + AddFuncLookup("nounproper", Info{ + Display: "Noun Proper", + Category: "word", + Description: "Specific name for a particular person, place, or organization", + Example: "John", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounProper(f), nil + }, + }) + + AddFuncLookup("noundeterminer", Info{ + Display: "Noun Determiner", + Category: "word", + Description: "Word that introduces a noun and identifies it as a noun", + Example: "your", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return nounDeterminer(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_phrase.go b/vendor/github.com/brianvoe/gofakeit/v7/word_phrase.go new file mode 100644 index 0000000000..68ff015a40 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_phrase.go @@ -0,0 +1,162 @@ +package gofakeit + +import ( + "strings" +) + +// Phrase will return a random phrase +func Phrase() string { return phrase(GlobalFaker) } + +// Phrase will return a random phrase +func (f *Faker) Phrase() string { return phrase(f) } + +func phrase(f *Faker) string { return getRandValue(f, []string{"sentence", "phrase"}) } + +// PhraseNoun will return a random noun phrase +func PhraseNoun() string { return phraseNoun(GlobalFaker) } + +// PhraseNoun will return a random noun phrase +func (f *Faker) PhraseNoun() string { return phraseNoun(f) } + +func phraseNoun(f *Faker) string { + str := "" + + // You may also want to add an adjective to describe the noun + if boolFunc(f) { + str = adjectiveDescriptive(f) + " " + noun(f) + } else { + str = noun(f) + } + + // Add determiner from weighted list + prob, _ := weighted(f, []any{1, 2, 3}, []float32{2, 1.5, 1}) + if prob == 1 { + str = getArticle(str) + " " + str + } else if prob == 2 { + str = "the " + str + } + + return str +} + +// PhraseVerb will return a random preposition phrase +func PhraseVerb() string { return phraseVerb(GlobalFaker) } + +// PhraseVerb will return a random preposition phrase +func (f *Faker) PhraseVerb() string { return phraseVerb(f) } + +func phraseVerb(f *Faker) string { + // Put together a string builder + sb := []string{} + + // You may have an adverb phrase + if boolFunc(f) { + sb = append(sb, phraseAdverb(f)) + } + + // Lets add the primary verb + sb = append(sb, verbAction(f)) + + // You may have a noun phrase + if boolFunc(f) { + sb = append(sb, phraseNoun(f)) + } + + // You may have an adverb phrase + if boolFunc(f) { + sb = append(sb, phraseAdverb(f)) + + // You may also have a preposition phrase + if boolFunc(f) { + sb = append(sb, phrasePreposition(f)) + } + + // You may also hae an adverb phrase + if boolFunc(f) { + sb = append(sb, phraseAdverb(f)) + } + } + + return strings.Join(sb, " ") +} + +// PhraseAdverb will return a random adverb phrase +func PhraseAdverb() string { return phraseAdverb(GlobalFaker) } + +// PhraseAdverb will return a random adverb phrase +func (f *Faker) PhraseAdverb() string { return phraseAdverb(f) } + +func phraseAdverb(f *Faker) string { + if boolFunc(f) { + return adverbDegree(f) + " " + adverbManner(f) + } + + return adverbManner(f) +} + +// PhrasePreposition will return a random preposition phrase +func PhrasePreposition() string { return phrasePreposition(GlobalFaker) } + +// PhrasePreposition will return a random preposition phrase +func (f *Faker) PhrasePreposition() string { return phrasePreposition(f) } + +func phrasePreposition(f *Faker) string { + return prepositionSimple(f) + " " + phraseNoun(f) +} + +func addWordPhraseLookup() { + AddFuncLookup("phrase", Info{ + Display: "Phrase", + Category: "word", + Description: "A small group of words standing together", + Example: "time will tell", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phrase(f), nil + }, + }) + + AddFuncLookup("phrasenoun", Info{ + Display: "Noun Phrase", + Category: "word", + Description: "Phrase with a noun as its head, functions within sentence like a noun", + Example: "a tribe", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phraseNoun(f), nil + }, + }) + + AddFuncLookup("phraseverb", Info{ + Display: "Verb Phrase", + Category: "word", + Description: "Phrase that Consists of a verb and its modifiers, expressing an action or state", + Example: "a tribe", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phraseVerb(f), nil + }, + }) + + AddFuncLookup("phraseadverb", Info{ + Display: "Adverb Phrase", + Category: "word", + Description: "Phrase that modifies a verb, adjective, or another adverb, providing additional information.", + Example: "fully gladly", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phraseAdverb(f), nil + }, + }) + + AddFuncLookup("phrasepreposition", Info{ + Display: "Preposition Phrase", + Category: "word", + Description: "Phrase starting with a preposition, showing relation between elements in a sentence.", + Example: "out the black thing", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return phrasePreposition(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_preposition.go b/vendor/github.com/brianvoe/gofakeit/v7/word_preposition.go new file mode 100644 index 0000000000..17902dc619 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_preposition.go @@ -0,0 +1,92 @@ +package gofakeit + +// Preposition will generate a random preposition +func Preposition() string { return preposition(GlobalFaker) } + +// Preposition will generate a random preposition +func (f *Faker) Preposition() string { return preposition(f) } + +func preposition(f *Faker) string { + var prepType = map[int]string{ + 0: "preposition_simple", + 1: "preposition_double", + 2: "preposition_compound", + } + return getRandValue(f, []string{"word", prepType[number(f, 0, 2)]}) +} + +// PrepositionSimple will generate a random simple preposition +func PrepositionSimple() string { return prepositionSimple(GlobalFaker) } + +// PrepositionSimple will generate a random simple preposition +func (f *Faker) PrepositionSimple() string { return prepositionSimple(f) } + +func prepositionSimple(f *Faker) string { + return getRandValue(f, []string{"word", "preposition_simple"}) +} + +// PrepositionDouble will generate a random double preposition +func PrepositionDouble() string { return prepositionDouble(GlobalFaker) } + +// PrepositionDouble will generate a random double preposition +func (f *Faker) PrepositionDouble() string { return prepositionDouble(f) } + +func prepositionDouble(f *Faker) string { + return getRandValue(f, []string{"word", "preposition_double"}) +} + +// PrepositionCompound will generate a random compound preposition +func PrepositionCompound() string { return prepositionCompound(GlobalFaker) } + +// PrepositionCompound will generate a random compound preposition +func (f *Faker) PrepositionCompound() string { return prepositionCompound(f) } + +func prepositionCompound(f *Faker) string { + return getRandValue(f, []string{"word", "preposition_compound"}) +} + +func addWordPrepositionLookup() { + AddFuncLookup("preposition", Info{ + Display: "Preposition", + Category: "word", + Description: "Words used to express the relationship of a noun or pronoun to other words in a sentence", + Example: "other than", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return preposition(f), nil + }, + }) + + AddFuncLookup("prepositionsimple", Info{ + Display: "Preposition Simple", + Category: "word", + Description: "Single-word preposition showing relationships between 2 parts of a sentence", + Example: "out", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return prepositionSimple(f), nil + }, + }) + + AddFuncLookup("prepositiondouble", Info{ + Display: "Preposition Double", + Category: "word", + Description: "Two-word combination preposition, indicating a complex relation", + Example: "before", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return prepositionDouble(f), nil + }, + }) + + AddFuncLookup("prepositioncompound", Info{ + Display: "Preposition Compound", + Category: "word", + Description: "Preposition that can be formed by combining two or more prepositions", + Example: "according to", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return prepositionCompound(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_pronoun.go b/vendor/github.com/brianvoe/gofakeit/v7/word_pronoun.go new file mode 100644 index 0000000000..f511f7d756 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_pronoun.go @@ -0,0 +1,202 @@ +package gofakeit + +// Pronoun will generate a random pronoun +func Pronoun() string { return pronoun(GlobalFaker) } + +// Pronoun will generate a random pronoun +func (f *Faker) Pronoun() string { return pronoun(f) } + +func pronoun(f *Faker) string { + var pronounType = map[int]string{ + 0: "pronoun_personal", + 1: "pronoun_object", + 2: "pronoun_possessive", + 3: "pronoun_reflective", + 4: "pronoun_indefinite", + 5: "pronoun_demonstrative", + 6: "pronoun_interrogative", + 7: "pronoun_relative", + } + return getRandValue(f, []string{"word", pronounType[number(f, 0, 7)]}) +} + +// PronounPersonal will generate a random personal pronoun +func PronounPersonal() string { return pronounPersonal(GlobalFaker) } + +// PronounPersonal will generate a random personal pronoun +func (f *Faker) PronounPersonal() string { return pronounPersonal(f) } + +func pronounPersonal(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_personal"}) +} + +// PronounObject will generate a random object pronoun +func PronounObject() string { return pronounObject(GlobalFaker) } + +// PronounObject will generate a random object pronoun +func (f *Faker) PronounObject() string { return pronounObject(f) } + +func pronounObject(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_object"}) +} + +// PronounPossessive will generate a random possessive pronoun +func PronounPossessive() string { return pronounPossessive(GlobalFaker) } + +// PronounPossessive will generate a random possessive pronoun +func (f *Faker) PronounPossessive() string { return pronounPossessive(f) } + +func pronounPossessive(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_possessive"}) +} + +// PronounReflective will generate a random reflective pronoun +func PronounReflective() string { return pronounReflective(GlobalFaker) } + +// PronounReflective will generate a random reflective pronoun +func (f *Faker) PronounReflective() string { return pronounReflective(f) } + +func pronounReflective(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_reflective"}) +} + +// PronounIndefinite will generate a random indefinite pronoun +func PronounIndefinite() string { return pronounIndefinite(GlobalFaker) } + +// PronounIndefinite will generate a random indefinite pronoun +func (f *Faker) PronounIndefinite() string { return pronounIndefinite(f) } + +func pronounIndefinite(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_indefinite"}) +} + +// PronounDemonstrative will generate a random demonstrative pronoun +func PronounDemonstrative() string { return pronounDemonstrative(GlobalFaker) } + +// PronounDemonstrative will generate a random demonstrative pronoun +func (f *Faker) PronounDemonstrative() string { return pronounDemonstrative(f) } + +func pronounDemonstrative(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_demonstrative"}) +} + +// PronounInterrogative will generate a random interrogative pronoun +func PronounInterrogative() string { return pronounInterrogative(GlobalFaker) } + +// PronounInterrogative will generate a random interrogative pronoun +func (f *Faker) PronounInterrogative() string { return pronounInterrogative(f) } + +func pronounInterrogative(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_interrogative"}) +} + +// PronounRelative will generate a random relative pronoun +func PronounRelative() string { return pronounRelative(GlobalFaker) } + +// PronounRelative will generate a random relative pronoun +func (f *Faker) PronounRelative() string { return pronounRelative(f) } + +func pronounRelative(f *Faker) string { + return getRandValue(f, []string{"word", "pronoun_relative"}) +} + +func addWordPronounLookup() { + AddFuncLookup("pronoun", Info{ + Display: "Pronoun", + Category: "word", + Description: "Word used in place of a noun to avoid repetition", + Example: "me", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronoun(f), nil + }, + }) + + AddFuncLookup("pronounpersonal", Info{ + Display: "Pronoun Personal", + Category: "word", + Description: "Pronoun referring to a specific persons or things", + Example: "it", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounPersonal(f), nil + }, + }) + + AddFuncLookup("pronounobject", Info{ + Display: "Pronoun Object", + Category: "word", + Description: "Pronoun used as the object of a verb or preposition", + Example: "it", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounObject(f), nil + }, + }) + + AddFuncLookup("pronounpossessive", Info{ + Display: "Pronoun Possessive", + Category: "word", + Description: "Pronoun indicating ownership or belonging", + Example: "mine", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounPossessive(f), nil + }, + }) + + AddFuncLookup("pronounreflective", Info{ + Display: "Pronoun Reflective", + Category: "word", + Description: "Pronoun referring back to the subject of the sentence", + Example: "myself", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounReflective(f), nil + }, + }) + + AddFuncLookup("pronounindefinite", Info{ + Display: "Pronoun Indefinite", + Category: "word", + Description: "Pronoun that does not refer to a specific person or thing", + Example: "few", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounIndefinite(f), nil + }, + }) + + AddFuncLookup("pronoundemonstrative", Info{ + Display: "Pronoun Demonstrative", + Category: "word", + Description: "Pronoun that points out specific people or things", + Example: "this", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounDemonstrative(f), nil + }, + }) + + AddFuncLookup("pronouninterrogative", Info{ + Display: "Pronoun Interrogative", + Category: "word", + Description: "Pronoun used to ask questions", + Example: "what", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounInterrogative(f), nil + }, + }) + + AddFuncLookup("pronounrelative", Info{ + Display: "Pronoun Relative", + Category: "word", + Description: "Pronoun that introduces a clause, referring back to a noun or pronoun", + Example: "as", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return pronounRelative(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_sentence.go b/vendor/github.com/brianvoe/gofakeit/v7/word_sentence.go new file mode 100644 index 0000000000..1cbc874e93 --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_sentence.go @@ -0,0 +1,212 @@ +package gofakeit + +import ( + "bytes" + "errors" + "strings" + "unicode" +) + +type paragrapOptions struct { + paragraphCount int + sentenceCount int + wordCount int + separator string +} + +const bytesPerWordEstimation = 6 + +type sentenceGenerator func(f *Faker, wordCount int) string +type wordGenerator func(f *Faker) string + +// Sentence will generate a random sentence +func Sentence(wordCount int) string { return sentence(GlobalFaker, wordCount) } + +// Sentence will generate a random sentence +func (f *Faker) Sentence(wordCount int) string { return sentence(f, wordCount) } + +func sentence(f *Faker, wordCount int) string { + return sentenceGen(f, wordCount, word) +} + +// Paragraph will generate a random paragraphGenerator +func Paragraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return paragraph(GlobalFaker, paragraphCount, sentenceCount, wordCount, separator) +} + +// Paragraph will generate a random paragraphGenerator +func (f *Faker) Paragraph(paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return paragraph(f, paragraphCount, sentenceCount, wordCount, separator) +} + +func paragraph(f *Faker, paragraphCount int, sentenceCount int, wordCount int, separator string) string { + return paragraphGen(f, paragrapOptions{paragraphCount, sentenceCount, wordCount, separator}, sentence) +} + +func sentenceGen(f *Faker, wordCount int, word wordGenerator) string { + if wordCount <= 0 { + return "" + } + + wordSeparator := ' ' + sentence := bytes.Buffer{} + sentence.Grow(wordCount * bytesPerWordEstimation) + + for i := 0; i < wordCount; i++ { + word := word(f) + if i == 0 { + runes := []rune(word) + runes[0] = unicode.ToTitle(runes[0]) + word = string(runes) + } + sentence.WriteString(word) + if i < wordCount-1 { + sentence.WriteRune(wordSeparator) + } + } + sentence.WriteRune('.') + return sentence.String() +} + +func paragraphGen(f *Faker, opts paragrapOptions, sentecer sentenceGenerator) string { + if opts.paragraphCount <= 0 || opts.sentenceCount <= 0 || opts.wordCount <= 0 { + return "" + } + + //to avoid making Go 1.10 dependency, we cannot use strings.Builder + paragraphs := bytes.Buffer{} + //we presume the length + paragraphs.Grow(opts.paragraphCount * opts.sentenceCount * opts.wordCount * bytesPerWordEstimation) + wordSeparator := ' ' + + for i := 0; i < opts.paragraphCount; i++ { + for e := 0; e < opts.sentenceCount; e++ { + paragraphs.WriteString(sentecer(f, opts.wordCount)) + if e < opts.sentenceCount-1 { + paragraphs.WriteRune(wordSeparator) + } + } + + if i < opts.paragraphCount-1 { + paragraphs.WriteString(opts.separator) + } + } + + return paragraphs.String() +} + +// Question will return a random question +func Question() string { + return question(GlobalFaker) +} + +// Question will return a random question +func (f *Faker) Question() string { + return question(f) +} + +func question(f *Faker) string { + return strings.Replace(hipsterSentence(f, number(f, 3, 10)), ".", "?", 1) +} + +// Quote will return a random quote from a random person +func Quote() string { return quote(GlobalFaker) } + +// Quote will return a random quote from a random person +func (f *Faker) Quote() string { return quote(f) } + +func quote(f *Faker) string { + return `"` + hipsterSentence(f, number(f, 3, 10)) + `" - ` + firstName(f) + " " + lastName(f) +} + +func addWordSentenceLookup() { + AddFuncLookup("sentence", Info{ + Display: "Sentence", + Category: "word", + Description: "Set of words expressing a statement, question, exclamation, or command", + Example: "Interpret context record river mind.", + Output: "string", + Params: []Param{ + {Field: "wordcount", Display: "Word Count", Type: "int", Default: "5", Description: "Number of words in a sentence"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + wordCount, err := info.GetInt(m, "wordcount") + if err != nil { + return nil, err + } + if wordCount <= 0 || wordCount > 50 { + return nil, errors.New("invalid word count, must be greater than 0, less than 50") + } + + return sentence(f, wordCount), nil + }, + }) + + AddFuncLookup("paragraph", Info{ + Display: "Paragraph", + Category: "word", + Description: "Distinct section of writing covering a single theme, composed of multiple sentences", + Example: "Interpret context record river mind press self should compare property outcome divide. Combine approach sustain consult discover explanation direct address church husband seek army. Begin own act welfare replace press suspect stay link place manchester specialist. Arrive price satisfy sign force application hair train provide basis right pay. Close mark teacher strengthen information attempt head touch aim iron tv take.", + Output: "string", + Params: []Param{ + {Field: "paragraphcount", Display: "Paragraph Count", Type: "int", Default: "2", Description: "Number of paragraphs"}, + {Field: "sentencecount", Display: "Sentence Count", Type: "int", Default: "2", Description: "Number of sentences in a paragraph"}, + {Field: "wordcount", Display: "Word Count", Type: "int", Default: "5", Description: "Number of words in a sentence"}, + {Field: "paragraphseparator", Display: "Paragraph Separator", Type: "string", Default: "
", Description: "String value to add between paragraphs"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + paragraphCount, err := info.GetInt(m, "paragraphcount") + if err != nil { + return nil, err + } + if paragraphCount <= 0 || paragraphCount > 20 { + return nil, errors.New("invalid paragraph count, must be greater than 0, less than 20") + } + + sentenceCount, err := info.GetInt(m, "sentencecount") + if err != nil { + return nil, err + } + if sentenceCount <= 0 || sentenceCount > 20 { + return nil, errors.New("invalid sentence count, must be greater than 0, less than 20") + } + + wordCount, err := info.GetInt(m, "wordcount") + if err != nil { + return nil, err + } + if wordCount <= 0 || wordCount > 50 { + return nil, errors.New("invalid word count, must be greater than 0, less than 50") + } + + paragraphSeparator, err := info.GetString(m, "paragraphseparator") + if err != nil { + return nil, err + } + + return paragraph(f, paragraphCount, sentenceCount, wordCount, paragraphSeparator), nil + }, + }) + + AddFuncLookup("question", Info{ + Display: "Question", + Category: "word", + Description: "Statement formulated to inquire or seek clarification", + Example: "Roof chia echo?", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return question(f), nil + }, + }) + + AddFuncLookup("quote", Info{ + Display: "Quote", + Category: "word", + Description: "Direct repetition of someone else's words", + Example: `"Roof chia echo." - Lura Lockman`, + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return quote(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/word_verb.go b/vendor/github.com/brianvoe/gofakeit/v7/word_verb.go new file mode 100644 index 0000000000..d268784b3a --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/word_verb.go @@ -0,0 +1,126 @@ +package gofakeit + +// Verb will generate a random verb +func Verb() string { return verb(GlobalFaker) } + +// Verb will generate a random verb +func (f *Faker) Verb() string { return verb(f) } + +func verb(f *Faker) string { + var verbType = map[int]string{ + 0: "verb_action", + 1: "verb_linking", + 2: "verb_helping", + } + return getRandValue(f, []string{"word", verbType[number(f, 0, 2)]}) +} + +// VerbAction will generate a random action verb +func VerbAction() string { return verbAction(GlobalFaker) } + +// VerbAction will generate a random action verb +func (f *Faker) VerbAction() string { return verbAction(f) } + +func verbAction(f *Faker) string { return getRandValue(f, []string{"word", "verb_action"}) } + +// VerbTransitive will generate a random transitive verb +func VerbTransitive() string { return verbTransitive(GlobalFaker) } + +// VerbTransitive will generate a random transitive verb +func (f *Faker) VerbTransitive() string { return verbTransitive(f) } + +func verbTransitive(f *Faker) string { return getRandValue(f, []string{"word", "verb_transitive"}) } + +// VerbIntransitive will generate a random intransitive verb +func VerbIntransitive() string { return verbIntransitive(GlobalFaker) } + +// VerbIntransitive will generate a random intransitive verb +func (f *Faker) VerbIntransitive() string { return verbIntransitive(f) } + +func verbIntransitive(f *Faker) string { + return getRandValue(f, []string{"word", "verb_intransitive"}) +} + +// VerbLinking will generate a random linking verb +func VerbLinking() string { return verbLinking(GlobalFaker) } + +// VerbLinking will generate a random linking verb +func (f *Faker) VerbLinking() string { return verbLinking(f) } + +func verbLinking(f *Faker) string { return getRandValue(f, []string{"word", "verb_linking"}) } + +// VerbHelping will generate a random helping verb +func VerbHelping() string { return verbHelping(GlobalFaker) } + +// VerbHelping will generate a random helping verb +func (f *Faker) VerbHelping() string { return verbHelping(f) } + +func verbHelping(f *Faker) string { return getRandValue(f, []string{"word", "verb_helping"}) } + +func addWordVerbLookup() { + AddFuncLookup("verb", Info{ + Display: "Verb", + Category: "word", + Description: "Word expressing an action, event or state", + Example: "release", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return verb(f), nil + }, + }) + + AddFuncLookup("verbaction", Info{ + Display: "Action Verb", + Category: "word", + Description: "Verb Indicating a physical or mental action", + Example: "close", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return verbAction(f), nil + }, + }) + + AddFuncLookup("verbtransitive", Info{ + Display: "Transitive Verb", + Category: "word", + Description: "Verb that requires a direct object to complete its meaning", + Example: "follow", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return verbTransitive(f), nil + }, + }) + + AddFuncLookup("verbintransitive", Info{ + Display: "Intransitive Verb", + Category: "word", + Description: "Verb that does not require a direct object to complete its meaning", + Example: "laugh", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return verbIntransitive(f), nil + }, + }) + + AddFuncLookup("verblinking", Info{ + Display: "Linking Verb", + Category: "word", + Description: "Verb that Connects the subject of a sentence to a subject complement", + Example: "was", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return verbLinking(f), nil + }, + }) + + AddFuncLookup("verbhelping", Info{ + Display: "Helping Verb", + Category: "word", + Description: "Auxiliary verb that helps the main verb complete the sentence", + Example: "be", + Output: "string", + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + return verbHelping(f), nil + }, + }) +} diff --git a/vendor/github.com/brianvoe/gofakeit/v7/xml.go b/vendor/github.com/brianvoe/gofakeit/v7/xml.go new file mode 100644 index 0000000000..da4670371d --- /dev/null +++ b/vendor/github.com/brianvoe/gofakeit/v7/xml.go @@ -0,0 +1,349 @@ +package gofakeit + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "reflect" +) + +// XMLOptions defines values needed for json generation +type XMLOptions struct { + Type string `json:"type" xml:"type" fake:"{randomstring:[array,single]}"` // single or array + RootElement string `json:"root_element" xml:"root_element"` + RecordElement string `json:"record_element" xml:"record_element"` + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` + Indent bool `json:"indent" xml:"indent"` + Fields []Field `json:"fields" xml:"fields" fake:"{fields}"` +} + +type xmlArray struct { + XMLName xml.Name + Array []xmlMap +} + +type xmlMap struct { + XMLName xml.Name + KeyOrder []string + Map map[string]any `xml:",chardata"` +} + +type xmlEntry struct { + XMLName xml.Name + Value any `xml:",chardata"` +} + +func (m xmlMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if len(m.Map) == 0 { + return nil + } + + start.Name = m.XMLName + + err := e.EncodeToken(start) + if err != nil { + return err + } + + err = xmlMapLoop(e, &m) + if err != nil { + return err + } + + return e.EncodeToken(start.End()) +} + +func xmlMapLoop(e *xml.Encoder, m *xmlMap) error { + var err error + + // Check if xmlmap has key order if not create it + // Get key order by order of fields array + if m.KeyOrder == nil { + m.KeyOrder = make([]string, len(m.Map)) + for k := range m.Map { + m.KeyOrder = append(m.KeyOrder, k) + } + } + + for _, key := range m.KeyOrder { + v := reflect.ValueOf(m.Map[key]) + + // Always get underlyning Value of value + if v.Kind() == reflect.Ptr { + v = reflect.Indirect(v) + } + + switch v.Kind() { + case reflect.Bool, + reflect.String, + reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + err = e.Encode(xmlEntry{XMLName: xml.Name{Local: key}, Value: m.Map[key]}) + if err != nil { + return err + } + case reflect.Slice: + e.EncodeToken(xml.StartElement{Name: xml.Name{Local: key}}) + for i := 0; i < v.Len(); i++ { + err = e.Encode(xmlEntry{XMLName: xml.Name{Local: "value"}, Value: v.Index(i).String()}) + if err != nil { + return err + } + } + e.EncodeToken(xml.EndElement{Name: xml.Name{Local: key}}) + case reflect.Map: + err = e.Encode(xmlMap{ + XMLName: xml.Name{Local: key}, + Map: m.Map[key].(map[string]any), + }) + if err != nil { + return err + } + case reflect.Struct: + // Convert struct to map[string]any + // So we can rewrap element + var inInterface map[string]any + inrec, _ := json.Marshal(m.Map[key]) + json.Unmarshal(inrec, &inInterface) + + err = e.Encode(xmlMap{ + XMLName: xml.Name{Local: key}, + Map: inInterface, + }) + if err != nil { + return err + } + default: + err = e.Encode(m.Map[key]) + if err != nil { + return err + } + } + } + + return nil +} + +// XML generates an object or an array of objects in json format +// A nil XMLOptions returns a randomly structured XML. +func XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(GlobalFaker, xo) } + +// XML generates an object or an array of objects in json format +// A nil XMLOptions returns a randomly structured XML. +func (f *Faker) XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(f, xo) } + +func xmlFunc(f *Faker, xo *XMLOptions) ([]byte, error) { + if xo == nil { + // We didn't get a XMLOptions, so create a new random one + err := f.Struct(&xo) + if err != nil { + return nil, err + } + } + + // Check to make sure they passed in a type + if xo.Type != "single" && xo.Type != "array" { + return nil, errors.New("invalid type, must be array or object") + } + + // Check fields length + if xo.Fields == nil || len(xo.Fields) <= 0 { + return nil, errors.New("must pass fields in order to build json object(s)") + } + + // Check root element string + if xo.RootElement == "" { + xo.RecordElement = "xml" + } + + // Check record element string + if xo.RecordElement == "" { + xo.RecordElement = "record" + } + + // Get key order by order of fields array + keyOrder := make([]string, 0, len(xo.Fields)) + for _, f := range xo.Fields { + keyOrder = append(keyOrder, f.Name) + } + + if xo.Type == "single" { + v := xmlMap{ + XMLName: xml.Name{Local: xo.RootElement}, + KeyOrder: keyOrder, + Map: make(map[string]any), + } + + // Loop through fields and add to them to map[string]any + for _, field := range xo.Fields { + // Get function info + funcInfo := GetFuncLookup(field.Function) + if funcInfo == nil { + return nil, errors.New("invalid function, " + field.Function + " does not exist") + } + + value, err := funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return nil, err + } + + v.Map[field.Name] = value + } + + // Marshal into bytes + var b bytes.Buffer + x := xml.NewEncoder(&b) + if xo.Indent { + x.Indent("", " ") + } + err := x.Encode(v) + if err != nil { + return nil, err + } + + return b.Bytes(), nil + } + + if xo.Type == "array" { + // Make sure you set a row count + if xo.RowCount <= 0 { + return nil, errors.New("must have row count") + } + + xa := xmlArray{ + XMLName: xml.Name{Local: xo.RootElement}, + Array: make([]xmlMap, xo.RowCount), + } + + for i := 1; i <= int(xo.RowCount); i++ { + v := xmlMap{ + XMLName: xml.Name{Local: xo.RecordElement}, + KeyOrder: keyOrder, + Map: make(map[string]any), + } + + // Loop through fields and add to them to map[string]any + for _, field := range xo.Fields { + if field.Function == "autoincrement" { + v.Map[field.Name] = i + continue + } + + // Get function info + funcInfo := GetFuncLookup(field.Function) + if funcInfo == nil { + return nil, errors.New("invalid function, " + field.Function + " does not exist") + } + + value, err := funcInfo.Generate(f, &field.Params, funcInfo) + if err != nil { + return nil, err + } + + v.Map[field.Name] = value + } + + xa.Array = append(xa.Array, v) + } + + // Marshal into bytes + var b bytes.Buffer + x := xml.NewEncoder(&b) + if xo.Indent { + x.Indent("", " ") + } + err := x.Encode(xa) + if err != nil { + return nil, err + } + + return b.Bytes(), nil + } + + return nil, errors.New("invalid type, must be array or object") +} + +func addFileXMLLookup() { + AddFuncLookup("xml", Info{ + Display: "XML", + Category: "file", + Description: "Generates an single or an array of elements in xml format", + Example: ` + + Markus + Moen + Dc0VYXjkWABx + + + Osborne + Hilll + XPJ9OVNbs5lm + +`, + Output: "[]byte", + ContentType: "application/xml", + Params: []Param{ + {Field: "type", Display: "Type", Type: "string", Default: "single", Options: []string{"single", "array"}, Description: "Type of XML, single or array"}, + {Field: "rootelement", Display: "Root Element", Type: "string", Default: "xml", Description: "Root element wrapper name"}, + {Field: "recordelement", Display: "Record Element", Type: "string", Default: "record", Description: "Record element for each record row"}, + {Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows in JSON array"}, + {Field: "indent", Display: "Indent", Type: "bool", Default: "false", Description: "Whether or not to add indents and newlines"}, + {Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"}, + }, + Generate: func(f *Faker, m *MapParams, info *Info) (any, error) { + xo := XMLOptions{} + + typ, err := info.GetString(m, "type") + if err != nil { + return nil, err + } + xo.Type = typ + + rootElement, err := info.GetString(m, "rootelement") + if err != nil { + return nil, err + } + xo.RootElement = rootElement + + recordElement, err := info.GetString(m, "recordelement") + if err != nil { + return nil, err + } + xo.RecordElement = recordElement + + rowcount, err := info.GetInt(m, "rowcount") + if err != nil { + return nil, err + } + xo.RowCount = rowcount + + fieldsStr, err := info.GetStringArray(m, "fields") + if err != nil { + return nil, err + } + + indent, err := info.GetBool(m, "indent") + if err != nil { + return nil, err + } + xo.Indent = indent + + // Check to make sure fields has length + if len(fieldsStr) > 0 { + xo.Fields = make([]Field, len(fieldsStr)) + + for i, f := range fieldsStr { + // Unmarshal fields string into fields array + err = json.Unmarshal([]byte(f), &xo.Fields[i]) + if err != nil { + return nil, errors.New("unable to decode json string") + } + } + } + + return xmlFunc(f, &xo) + }, + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/internal/debug/flags.go b/vendor/github.com/ethereum/go-ethereum/internal/debug/flags.go index 2082d60df5..26cfa0593d 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/debug/flags.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/debug/flags.go @@ -28,14 +28,11 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics/exp" - "github.com/fjl/memsize/memsizeui" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" ) -var Memsize memsizeui.Handler - var ( verbosityFlag = &cli.IntFlag{ Name: "verbosity", @@ -203,7 +200,6 @@ func StartPProf(address string, withMetrics bool) { if withMetrics { exp.Exp(metrics.DefaultRegistry) } - http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) go func() { if err := http.ListenAndServe(address, nil); err != nil { diff --git a/vendor/github.com/fjl/memsize/.travis.yml b/vendor/github.com/fjl/memsize/.travis.yml deleted file mode 100644 index 2d7d4fa602..0000000000 --- a/vendor/github.com/fjl/memsize/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - "1.10.x" - - "1.11.x" - - "1.12.x" -env: - - GOARCH=i386 - - GOARCH=amd64 -script: go test -v ./... diff --git a/vendor/github.com/fjl/memsize/LICENSE b/vendor/github.com/fjl/memsize/LICENSE deleted file mode 100644 index 8b80456419..0000000000 --- a/vendor/github.com/fjl/memsize/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Felix Lange - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/fjl/memsize/bitmap.go b/vendor/github.com/fjl/memsize/bitmap.go deleted file mode 100644 index c3894a2464..0000000000 --- a/vendor/github.com/fjl/memsize/bitmap.go +++ /dev/null @@ -1,119 +0,0 @@ -package memsize - -import ( - "math/bits" -) - -const ( - uintptrBits = 32 << (uint64(^uintptr(0)) >> 63) - uintptrBytes = uintptrBits / 8 - bmBlockRange = 1 * 1024 * 1024 // bytes covered by bmBlock - bmBlockWords = bmBlockRange / uintptrBits -) - -// bitmap is a sparse bitmap. -type bitmap struct { - blocks map[uintptr]*bmBlock -} - -func newBitmap() *bitmap { - return &bitmap{make(map[uintptr]*bmBlock)} -} - -// markRange sets n consecutive bits starting at addr. -func (b *bitmap) markRange(addr, n uintptr) { - for end := addr + n; addr < end; { - block, baddr := b.block(addr) - for i := baddr; i < bmBlockRange && addr < end; i++ { - block.mark(i) - addr++ - } - } -} - -// isMarked returns the value of the bit at the given address. -func (b *bitmap) isMarked(addr uintptr) bool { - block, baddr := b.block(addr) - return block.isMarked(baddr) -} - -// countRange returns the number of set bits in the range [addr, addr+n]. -func (b *bitmap) countRange(addr, n uintptr) uintptr { - c := uintptr(0) - for end := addr + n; addr < end; { - block, baddr := b.block(addr) - bend := uintptr(bmBlockRange - 1) - if baddr+(end-addr) < bmBlockRange { - bend = baddr + (end - addr) - } - c += uintptr(block.count(baddr, bend)) - // Move addr to next block. - addr += bmBlockRange - baddr - } - return c -} - -// block finds the block corresponding to the given memory address. -// It also returns the block's starting address. -func (b *bitmap) block(addr uintptr) (*bmBlock, uintptr) { - index := addr / bmBlockRange - block := b.blocks[index] - if block == nil { - block = new(bmBlock) - b.blocks[index] = block - } - return block, addr % bmBlockRange -} - -// size returns the sum of the byte sizes of all blocks. -func (b *bitmap) size() uintptr { - return uintptr(len(b.blocks)) * bmBlockWords * uintptrBytes -} - -// utilization returns the mean percentage of one bits across all blocks. -func (b *bitmap) utilization() float32 { - var avg float32 - for _, block := range b.blocks { - avg += float32(block.count(0, bmBlockRange-1)) / float32(bmBlockRange) - } - return avg / float32(len(b.blocks)) -} - -// bmBlock is a bitmap block. -type bmBlock [bmBlockWords]uintptr - -// mark sets the i'th bit to one. -func (b *bmBlock) mark(i uintptr) { - b[i/uintptrBits] |= 1 << (i % uintptrBits) -} - -// isMarked returns the value of the i'th bit. -func (b *bmBlock) isMarked(i uintptr) bool { - return (b[i/uintptrBits] & (1 << (i % uintptrBits))) != 0 -} - -// count returns the number of set bits in the range [start, end]. -func (b *bmBlock) count(start, end uintptr) (count int) { - br := b[start/uintptrBits : end/uintptrBits+1] - for i, w := range br { - if i == 0 { - w &= blockmask(start) - } - if i == len(br)-1 { - w &^= blockmask(end) - } - count += onesCountPtr(w) - } - return count -} - -func blockmask(x uintptr) uintptr { - return ^uintptr(0) << (x % uintptrBits) -} - -func onesCountPtr(x uintptr) int { - if uintptrBits == 64 { - return bits.OnesCount64(uint64(x)) - } - return bits.OnesCount32(uint32(x)) -} diff --git a/vendor/github.com/fjl/memsize/doc.go b/vendor/github.com/fjl/memsize/doc.go deleted file mode 100644 index 640cfba5eb..0000000000 --- a/vendor/github.com/fjl/memsize/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -/* -Package memsize computes the size of your object graph. - -So you made a spiffy algorithm and it works really well, but geez it's using -way too much memory. Where did it all go? memsize to the rescue! - -To get started, find a value that references all your objects and scan it. -This traverses the graph, counting sizes per type. - - sizes := memsize.Scan(myValue) - fmt.Println(sizes.Total) - -memsize can handle cycles just fine and tracks both private and public struct fields. -Unfortunately function closures cannot be inspected in any way. -*/ -package memsize diff --git a/vendor/github.com/fjl/memsize/mapiter_go12.go b/vendor/github.com/fjl/memsize/mapiter_go12.go deleted file mode 100644 index fcdb0c3479..0000000000 --- a/vendor/github.com/fjl/memsize/mapiter_go12.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build go1.12 - -package memsize - -import "reflect" - -func iterateMap(m reflect.Value, fn func(k, v reflect.Value)) { - it := m.MapRange() - for it.Next() { - fn(it.Key(), it.Value()) - } -} diff --git a/vendor/github.com/fjl/memsize/mapiter_old.go b/vendor/github.com/fjl/memsize/mapiter_old.go deleted file mode 100644 index 4999589659..0000000000 --- a/vendor/github.com/fjl/memsize/mapiter_old.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !go1.12 - -package memsize - -import "reflect" - -func iterateMap(m reflect.Value, fn func(k, v reflect.Value)) { - for _, k := range m.MapKeys() { - fn(k, m.MapIndex(k)) - } -} diff --git a/vendor/github.com/fjl/memsize/memsize.go b/vendor/github.com/fjl/memsize/memsize.go deleted file mode 100644 index 107b79b210..0000000000 --- a/vendor/github.com/fjl/memsize/memsize.go +++ /dev/null @@ -1,246 +0,0 @@ -package memsize - -import ( - "bytes" - "fmt" - "reflect" - "sort" - "strings" - "text/tabwriter" - "unsafe" -) - -// Scan traverses all objects reachable from v and counts how much memory -// is used per type. The value must be a non-nil pointer to any value. -func Scan(v interface{}) Sizes { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() { - panic("value to scan must be non-nil pointer") - } - - stopTheWorld("memsize scan") - defer startTheWorld() - - ctx := newContext() - ctx.scan(invalidAddr, rv, false) - ctx.s.BitmapSize = ctx.seen.size() - ctx.s.BitmapUtilization = ctx.seen.utilization() - return *ctx.s -} - -// Sizes is the result of a scan. -type Sizes struct { - Total uintptr - ByType map[reflect.Type]*TypeSize - // Internal stats (for debugging) - BitmapSize uintptr - BitmapUtilization float32 -} - -type TypeSize struct { - Total uintptr - Count uintptr -} - -func newSizes() *Sizes { - return &Sizes{ByType: make(map[reflect.Type]*TypeSize)} -} - -// Report returns a human-readable report. -func (s Sizes) Report() string { - type typLine struct { - name string - count uintptr - total uintptr - } - tab := []typLine{{"ALL", 0, s.Total}} - for _, typ := range s.ByType { - tab[0].count += typ.Count - } - maxname := 0 - for typ, s := range s.ByType { - line := typLine{typ.String(), s.Count, s.Total} - tab = append(tab, line) - if len(line.name) > maxname { - maxname = len(line.name) - } - } - sort.Slice(tab, func(i, j int) bool { return tab[i].total > tab[j].total }) - - buf := new(bytes.Buffer) - w := tabwriter.NewWriter(buf, 0, 0, 0, ' ', tabwriter.AlignRight) - for _, line := range tab { - namespace := strings.Repeat(" ", maxname-len(line.name)) - fmt.Fprintf(w, "%s%s\t %v\t %s\t\n", line.name, namespace, line.count, HumanSize(line.total)) - } - w.Flush() - return buf.String() -} - -// addValue is called during scan and adds the memory of given object. -func (s *Sizes) addValue(v reflect.Value, size uintptr) { - s.Total += size - rs := s.ByType[v.Type()] - if rs == nil { - rs = new(TypeSize) - s.ByType[v.Type()] = rs - } - rs.Total += size - rs.Count++ -} - -type context struct { - // We track previously scanned objects to prevent infinite loops - // when scanning cycles and to prevent counting objects more than once. - seen *bitmap - tc typCache - s *Sizes -} - -func newContext() *context { - return &context{seen: newBitmap(), tc: make(typCache), s: newSizes()} -} - -// scan walks all objects below v, determining their size. It returns the size of the -// previously unscanned parts of the object. -func (c *context) scan(addr address, v reflect.Value, add bool) (extraSize uintptr) { - size := v.Type().Size() - var marked uintptr - if addr.valid() { - marked = c.seen.countRange(uintptr(addr), size) - if marked == size { - return 0 // Skip if we have already seen the whole object. - } - c.seen.markRange(uintptr(addr), size) - } - // fmt.Printf("%v: %v ⮑ (marked %d)\n", addr, v.Type(), marked) - if c.tc.needScan(v.Type()) { - extraSize = c.scanContent(addr, v) - } - size -= marked - size += extraSize - // fmt.Printf("%v: %v %d (add %v, size %d, marked %d, extra %d)\n", addr, v.Type(), size+extraSize, add, v.Type().Size(), marked, extraSize) - if add { - c.s.addValue(v, size) - } - return size -} - -// scanContent and all other scan* functions below return the amount of 'extra' memory -// (e.g. slice data) that is referenced by the object. -func (c *context) scanContent(addr address, v reflect.Value) uintptr { - switch v.Kind() { - case reflect.Array: - return c.scanArray(addr, v) - case reflect.Chan: - return c.scanChan(v) - case reflect.Func: - // can't do anything here - return 0 - case reflect.Interface: - return c.scanInterface(v) - case reflect.Map: - return c.scanMap(v) - case reflect.Ptr: - if !v.IsNil() { - c.scan(address(v.Pointer()), v.Elem(), true) - } - return 0 - case reflect.Slice: - return c.scanSlice(v) - case reflect.String: - return uintptr(v.Len()) - case reflect.Struct: - return c.scanStruct(addr, v) - default: - unhandledKind(v.Kind()) - return 0 - } -} - -func (c *context) scanChan(v reflect.Value) uintptr { - etyp := v.Type().Elem() - extra := uintptr(0) - if c.tc.needScan(etyp) { - // Scan the channel buffer. This is unsafe but doesn't race because - // the world is stopped during scan. - hchan := unsafe.Pointer(v.Pointer()) - for i := uint(0); i < uint(v.Cap()); i++ { - addr := chanbuf(hchan, i) - elem := reflect.NewAt(etyp, addr).Elem() - extra += c.scanContent(address(addr), elem) - } - } - return uintptr(v.Cap())*etyp.Size() + extra -} - -func (c *context) scanStruct(base address, v reflect.Value) uintptr { - extra := uintptr(0) - for i := 0; i < v.NumField(); i++ { - f := v.Type().Field(i) - if c.tc.needScan(f.Type) { - addr := base.addOffset(f.Offset) - extra += c.scanContent(addr, v.Field(i)) - } - } - return extra -} - -func (c *context) scanArray(addr address, v reflect.Value) uintptr { - esize := v.Type().Elem().Size() - extra := uintptr(0) - for i := 0; i < v.Len(); i++ { - extra += c.scanContent(addr, v.Index(i)) - addr = addr.addOffset(esize) - } - return extra -} - -func (c *context) scanSlice(v reflect.Value) uintptr { - slice := v.Slice(0, v.Cap()) - esize := slice.Type().Elem().Size() - base := slice.Pointer() - // Add size of the unscanned portion of the backing array to extra. - blen := uintptr(slice.Len()) * esize - marked := c.seen.countRange(base, blen) - extra := blen - marked - c.seen.markRange(uintptr(base), blen) - if c.tc.needScan(slice.Type().Elem()) { - // Elements may contain pointers, scan them individually. - addr := address(base) - for i := 0; i < slice.Len(); i++ { - extra += c.scanContent(addr, slice.Index(i)) - addr = addr.addOffset(esize) - } - } - return extra -} - -func (c *context) scanMap(v reflect.Value) uintptr { - var ( - typ = v.Type() - len = uintptr(v.Len()) - extra = uintptr(0) - ) - if c.tc.needScan(typ.Key()) || c.tc.needScan(typ.Elem()) { - iterateMap(v, func(k, v reflect.Value) { - extra += c.scan(invalidAddr, k, false) - extra += c.scan(invalidAddr, v, false) - }) - } else { - extra = len*typ.Key().Size() + len*typ.Elem().Size() - } - return extra -} - -func (c *context) scanInterface(v reflect.Value) uintptr { - elem := v.Elem() - if !elem.IsValid() { - return 0 // nil interface - } - extra := c.scan(invalidAddr, elem, false) - if elem.Type().Kind() == reflect.Ptr { - extra -= uintptrBytes - } - return extra -} diff --git a/vendor/github.com/fjl/memsize/memsizeui/template.go b/vendor/github.com/fjl/memsize/memsizeui/template.go deleted file mode 100644 index b60fe6ba54..0000000000 --- a/vendor/github.com/fjl/memsize/memsizeui/template.go +++ /dev/null @@ -1,106 +0,0 @@ -package memsizeui - -import ( - "html/template" - "strconv" - "sync" - - "github.com/fjl/memsize" -) - -var ( - base *template.Template // the "base" template - baseInitOnce sync.Once -) - -func baseInit() { - base = template.Must(template.New("base").Parse(` - - - - memsize - - - - {{template "content" .}} - -`)) - - base.Funcs(template.FuncMap{ - "quote": strconv.Quote, - "humansize": memsize.HumanSize, - }) - - template.Must(base.New("rootbuttons").Parse(` -Overview -{{- range $root := .Roots -}} -
- -
-{{- end -}}`)) -} - -func contentTemplate(source string) *template.Template { - baseInitOnce.Do(baseInit) - t := template.Must(base.Clone()) - template.Must(t.New("content").Parse(source)) - return t -} - -var rootTemplate = contentTemplate(` -

Memsize

-{{template "rootbuttons" .}} -
-

Reports

- -`) - -var notFoundTemplate = contentTemplate(` -

{{.Data}}

-{{template "rootbuttons" .}} -`) - -var reportTemplate = contentTemplate(` -{{- $report := .Data -}} -

Memsize Report {{$report.ID}}

-
- Overview - -
-
-Root: {{quote $report.RootName}}
-Date: {{$report.Date}}
-Duration: {{$report.Duration}}
-Bitmap Size: {{$report.Sizes.BitmapSize | humansize}}
-Bitmap Utilization: {{$report.Sizes.BitmapUtilization}}
-
-
-
-{{$report.Sizes.Report}}
-
-`) diff --git a/vendor/github.com/fjl/memsize/memsizeui/ui.go b/vendor/github.com/fjl/memsize/memsizeui/ui.go deleted file mode 100644 index c48fc53f7f..0000000000 --- a/vendor/github.com/fjl/memsize/memsizeui/ui.go +++ /dev/null @@ -1,153 +0,0 @@ -package memsizeui - -import ( - "bytes" - "fmt" - "html/template" - "net/http" - "reflect" - "sort" - "strings" - "sync" - "time" - - "github.com/fjl/memsize" -) - -type Handler struct { - init sync.Once - mux http.ServeMux - mu sync.Mutex - reports map[int]Report - roots map[string]interface{} - reportID int -} - -type Report struct { - ID int - Date time.Time - Duration time.Duration - RootName string - Sizes memsize.Sizes -} - -type templateInfo struct { - Roots []string - Reports map[int]Report - PathDepth int - Data interface{} -} - -func (ti *templateInfo) Link(path ...string) string { - prefix := strings.Repeat("../", ti.PathDepth) - return prefix + strings.Join(path, "") -} - -func (h *Handler) Add(name string, v interface{}) { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() { - panic("root must be non-nil pointer") - } - h.mu.Lock() - if h.roots == nil { - h.roots = make(map[string]interface{}) - } - h.roots[name] = v - h.mu.Unlock() -} - -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h.init.Do(func() { - h.reports = make(map[int]Report) - h.mux.HandleFunc("/", h.handleRoot) - h.mux.HandleFunc("/scan", h.handleScan) - h.mux.HandleFunc("/report/", h.handleReport) - }) - h.mux.ServeHTTP(w, r) -} - -func (h *Handler) templateInfo(r *http.Request, data interface{}) *templateInfo { - h.mu.Lock() - roots := make([]string, 0, len(h.roots)) - for name := range h.roots { - roots = append(roots, name) - } - h.mu.Unlock() - sort.Strings(roots) - - return &templateInfo{ - Roots: roots, - Reports: h.reports, - PathDepth: strings.Count(r.URL.Path, "/") - 1, - Data: data, - } -} - -func (h *Handler) handleRoot(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/" { - http.NotFound(w, r) - return - } - serveHTML(w, rootTemplate, http.StatusOK, h.templateInfo(r, nil)) -} - -func (h *Handler) handleScan(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "invalid HTTP method, want POST", http.StatusMethodNotAllowed) - return - } - ti := h.templateInfo(r, "Unknown root") - id, ok := h.scan(r.URL.Query().Get("root")) - if !ok { - serveHTML(w, notFoundTemplate, http.StatusNotFound, ti) - return - } - w.Header().Add("Location", ti.Link(fmt.Sprintf("report/%d", id))) - w.WriteHeader(http.StatusSeeOther) -} - -func (h *Handler) handleReport(w http.ResponseWriter, r *http.Request) { - var id int - fmt.Sscan(strings.TrimPrefix(r.URL.Path, "/report/"), &id) - h.mu.Lock() - report, ok := h.reports[id] - h.mu.Unlock() - - if !ok { - serveHTML(w, notFoundTemplate, http.StatusNotFound, h.templateInfo(r, "Report not found")) - } else { - serveHTML(w, reportTemplate, http.StatusOK, h.templateInfo(r, report)) - } -} - -func (h *Handler) scan(root string) (int, bool) { - h.mu.Lock() - defer h.mu.Unlock() - - val, ok := h.roots[root] - if !ok { - return 0, false - } - id := h.reportID - start := time.Now() - sizes := memsize.Scan(val) - h.reports[id] = Report{ - ID: id, - RootName: root, - Date: start.Truncate(1 * time.Second), - Duration: time.Since(start), - Sizes: sizes, - } - h.reportID++ - return id, true -} - -func serveHTML(w http.ResponseWriter, tpl *template.Template, status int, ti *templateInfo) { - w.Header().Set("content-type", "text/html") - var buf bytes.Buffer - if err := tpl.Execute(&buf, ti); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - buf.WriteTo(w) -} diff --git a/vendor/github.com/fjl/memsize/runtimefunc.go b/vendor/github.com/fjl/memsize/runtimefunc.go deleted file mode 100644 index 912a3e768d..0000000000 --- a/vendor/github.com/fjl/memsize/runtimefunc.go +++ /dev/null @@ -1,14 +0,0 @@ -package memsize - -import "unsafe" - -var _ = unsafe.Pointer(nil) - -//go:linkname stopTheWorld runtime.stopTheWorld -func stopTheWorld(reason string) - -//go:linkname startTheWorld runtime.startTheWorld -func startTheWorld() - -//go:linkname chanbuf runtime.chanbuf -func chanbuf(ch unsafe.Pointer, i uint) unsafe.Pointer diff --git a/vendor/github.com/fjl/memsize/runtimefunc.s b/vendor/github.com/fjl/memsize/runtimefunc.s deleted file mode 100644 index a091e2fa72..0000000000 --- a/vendor/github.com/fjl/memsize/runtimefunc.s +++ /dev/null @@ -1 +0,0 @@ -// This file is required to make stub function declarations work. diff --git a/vendor/github.com/fjl/memsize/type.go b/vendor/github.com/fjl/memsize/type.go deleted file mode 100644 index 5d6f59e9ff..0000000000 --- a/vendor/github.com/fjl/memsize/type.go +++ /dev/null @@ -1,119 +0,0 @@ -package memsize - -import ( - "fmt" - "reflect" -) - -// address is a memory location. -// -// Code dealing with uintptr is oblivious to the zero address. -// Code dealing with address is not: it treats the zero address -// as invalid. Offsetting an invalid address doesn't do anything. -// -// This distinction is useful because there are objects that we can't -// get the pointer to. -type address uintptr - -const invalidAddr = address(0) - -func (a address) valid() bool { - return a != 0 -} - -func (a address) addOffset(off uintptr) address { - if !a.valid() { - return invalidAddr - } - return a + address(off) -} - -func (a address) String() string { - if uintptrBits == 32 { - return fmt.Sprintf("%#0.8x", uintptr(a)) - } - return fmt.Sprintf("%#0.16x", uintptr(a)) -} - -type typCache map[reflect.Type]typInfo - -type typInfo struct { - isPointer bool - needScan bool -} - -// isPointer returns true for pointer-ish values. The notion of -// pointer includes everything but plain values, i.e. slices, maps -// channels, interfaces are 'pointer', too. -func (tc *typCache) isPointer(typ reflect.Type) bool { - return tc.info(typ).isPointer -} - -// needScan reports whether a value of the type needs to be scanned -// recursively because it may contain pointers. -func (tc *typCache) needScan(typ reflect.Type) bool { - return tc.info(typ).needScan -} - -func (tc *typCache) info(typ reflect.Type) typInfo { - info, found := (*tc)[typ] - switch { - case found: - return info - case isPointer(typ): - info = typInfo{true, true} - default: - info = typInfo{false, tc.checkNeedScan(typ)} - } - (*tc)[typ] = info - return info -} - -func (tc *typCache) checkNeedScan(typ reflect.Type) bool { - switch k := typ.Kind(); k { - case reflect.Struct: - // Structs don't need scan if none of their fields need it. - for i := 0; i < typ.NumField(); i++ { - if tc.needScan(typ.Field(i).Type) { - return true - } - } - case reflect.Array: - // Arrays don't need scan if their element type doesn't. - return tc.needScan(typ.Elem()) - } - return false -} - -func isPointer(typ reflect.Type) bool { - k := typ.Kind() - switch { - case k <= reflect.Complex128: - return false - case k == reflect.Array: - return false - case k >= reflect.Chan && k <= reflect.String: - return true - case k == reflect.Struct || k == reflect.UnsafePointer: - return false - default: - unhandledKind(k) - return false - } -} - -func unhandledKind(k reflect.Kind) { - panic("unhandled kind " + k.String()) -} - -// HumanSize formats the given number of bytes as a readable string. -func HumanSize(bytes uintptr) string { - switch { - case bytes < 1024: - return fmt.Sprintf("%d B", bytes) - case bytes < 1024*1024: - return fmt.Sprintf("%.3f KB", float64(bytes)/1024) - default: - return fmt.Sprintf("%.3f MB", float64(bytes)/1024/1024) - } -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go deleted file mode 100644 index 85f9f57365..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ptypes - -import ( - "fmt" - "strings" - - "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - - anypb "github.com/golang/protobuf/ptypes/any" -) - -const urlPrefix = "type.googleapis.com/" - -// AnyMessageName returns the message name contained in an anypb.Any message. -// Most type assertions should use the Is function instead. -// -// Deprecated: Call the any.MessageName method instead. -func AnyMessageName(any *anypb.Any) (string, error) { - name, err := anyMessageName(any) - return string(name), err -} -func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) { - if any == nil { - return "", fmt.Errorf("message is nil") - } - name := protoreflect.FullName(any.TypeUrl) - if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 { - name = name[i+len("/"):] - } - if !name.IsValid() { - return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl) - } - return name, nil -} - -// MarshalAny marshals the given message m into an anypb.Any message. -// -// Deprecated: Call the anypb.New function instead. -func MarshalAny(m proto.Message) (*anypb.Any, error) { - switch dm := m.(type) { - case DynamicAny: - m = dm.Message - case *DynamicAny: - if dm == nil { - return nil, proto.ErrNil - } - m = dm.Message - } - b, err := proto.Marshal(m) - if err != nil { - return nil, err - } - return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil -} - -// Empty returns a new message of the type specified in an anypb.Any message. -// It returns protoregistry.NotFound if the corresponding message type could not -// be resolved in the global registry. -// -// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead -// to resolve the message name and create a new instance of it. -func Empty(any *anypb.Any) (proto.Message, error) { - name, err := anyMessageName(any) - if err != nil { - return nil, err - } - mt, err := protoregistry.GlobalTypes.FindMessageByName(name) - if err != nil { - return nil, err - } - return proto.MessageV1(mt.New().Interface()), nil -} - -// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message -// into the provided message m. It returns an error if the target message -// does not match the type in the Any message or if an unmarshal error occurs. -// -// The target message m may be a *DynamicAny message. If the underlying message -// type could not be resolved, then this returns protoregistry.NotFound. -// -// Deprecated: Call the any.UnmarshalTo method instead. -func UnmarshalAny(any *anypb.Any, m proto.Message) error { - if dm, ok := m.(*DynamicAny); ok { - if dm.Message == nil { - var err error - dm.Message, err = Empty(any) - if err != nil { - return err - } - } - m = dm.Message - } - - anyName, err := AnyMessageName(any) - if err != nil { - return err - } - msgName := proto.MessageName(m) - if anyName != msgName { - return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName) - } - return proto.Unmarshal(any.Value, m) -} - -// Is reports whether the Any message contains a message of the specified type. -// -// Deprecated: Call the any.MessageIs method instead. -func Is(any *anypb.Any, m proto.Message) bool { - if any == nil || m == nil { - return false - } - name := proto.MessageName(m) - if !strings.HasSuffix(any.TypeUrl, name) { - return false - } - return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/' -} - -// DynamicAny is a value that can be passed to UnmarshalAny to automatically -// allocate a proto.Message for the type specified in an anypb.Any message. -// The allocated message is stored in the embedded proto.Message. -// -// Example: -// var x ptypes.DynamicAny -// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } -// fmt.Printf("unmarshaled message: %v", x.Message) -// -// Deprecated: Use the any.UnmarshalNew method instead to unmarshal -// the any message contents into a new instance of the underlying message. -type DynamicAny struct{ proto.Message } - -func (m DynamicAny) String() string { - if m.Message == nil { - return "" - } - return m.Message.String() -} -func (m DynamicAny) Reset() { - if m.Message == nil { - return - } - m.Message.Reset() -} -func (m DynamicAny) ProtoMessage() { - return -} -func (m DynamicAny) ProtoReflect() protoreflect.Message { - if m.Message == nil { - return nil - } - return dynamicAny{proto.MessageReflect(m.Message)} -} - -type dynamicAny struct{ protoreflect.Message } - -func (m dynamicAny) Type() protoreflect.MessageType { - return dynamicAnyType{m.Message.Type()} -} -func (m dynamicAny) New() protoreflect.Message { - return dynamicAnyType{m.Message.Type()}.New() -} -func (m dynamicAny) Interface() protoreflect.ProtoMessage { - return DynamicAny{proto.MessageV1(m.Message.Interface())} -} - -type dynamicAnyType struct{ protoreflect.MessageType } - -func (t dynamicAnyType) New() protoreflect.Message { - return dynamicAny{t.MessageType.New()} -} -func (t dynamicAnyType) Zero() protoreflect.Message { - return dynamicAny{t.MessageType.Zero()} -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go deleted file mode 100644 index 0ef27d33de..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go +++ /dev/null @@ -1,62 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/ptypes/any/any.proto - -package any - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - anypb "google.golang.org/protobuf/types/known/anypb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/any.proto. - -type Any = anypb.Any - -var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{ - 0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, - 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, -} - -var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() } -func file_github_com_golang_protobuf_ptypes_any_any_proto_init() { - if File_github_com_golang_protobuf_ptypes_any_any_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_ptypes_any_any_proto = out.File - file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil - file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil - file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go deleted file mode 100644 index d3c33259d2..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package ptypes provides functionality for interacting with well-known types. -// -// Deprecated: Well-known types have specialized functionality directly -// injected into the generated packages for each message type. -// See the deprecation notice for each function for the suggested alternative. -package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go deleted file mode 100644 index b2b55dd851..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ptypes - -import ( - "errors" - "fmt" - "time" - - durationpb "github.com/golang/protobuf/ptypes/duration" -) - -// Range of google.protobuf.Duration as specified in duration.proto. -// This is about 10,000 years in seconds. -const ( - maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) - minSeconds = -maxSeconds -) - -// Duration converts a durationpb.Duration to a time.Duration. -// Duration returns an error if dur is invalid or overflows a time.Duration. -// -// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead. -func Duration(dur *durationpb.Duration) (time.Duration, error) { - if err := validateDuration(dur); err != nil { - return 0, err - } - d := time.Duration(dur.Seconds) * time.Second - if int64(d/time.Second) != dur.Seconds { - return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) - } - if dur.Nanos != 0 { - d += time.Duration(dur.Nanos) * time.Nanosecond - if (d < 0) != (dur.Nanos < 0) { - return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) - } - } - return d, nil -} - -// DurationProto converts a time.Duration to a durationpb.Duration. -// -// Deprecated: Call the durationpb.New function instead. -func DurationProto(d time.Duration) *durationpb.Duration { - nanos := d.Nanoseconds() - secs := nanos / 1e9 - nanos -= secs * 1e9 - return &durationpb.Duration{ - Seconds: int64(secs), - Nanos: int32(nanos), - } -} - -// validateDuration determines whether the durationpb.Duration is valid -// according to the definition in google/protobuf/duration.proto. -// A valid durpb.Duration may still be too large to fit into a time.Duration -// Note that the range of durationpb.Duration is about 10,000 years, -// while the range of time.Duration is about 290 years. -func validateDuration(dur *durationpb.Duration) error { - if dur == nil { - return errors.New("duration: nil Duration") - } - if dur.Seconds < minSeconds || dur.Seconds > maxSeconds { - return fmt.Errorf("duration: %v: seconds out of range", dur) - } - if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 { - return fmt.Errorf("duration: %v: nanos out of range", dur) - } - // Seconds and Nanos must have the same sign, unless d.Nanos is zero. - if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) { - return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur) - } - return nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go deleted file mode 100644 index d0079ee3ef..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/ptypes/duration/duration.proto - -package duration - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - durationpb "google.golang.org/protobuf/types/known/durationpb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/duration.proto. - -type Duration = durationpb.Duration - -var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{ - 0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() } -func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() { - if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File - file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil - file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil - file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go deleted file mode 100644 index 8368a3f70d..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ptypes - -import ( - "errors" - "fmt" - "time" - - timestamppb "github.com/golang/protobuf/ptypes/timestamp" -) - -// Range of google.protobuf.Duration as specified in timestamp.proto. -const ( - // Seconds field of the earliest valid Timestamp. - // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - minValidSeconds = -62135596800 - // Seconds field just after the latest valid Timestamp. - // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - maxValidSeconds = 253402300800 -) - -// Timestamp converts a timestamppb.Timestamp to a time.Time. -// It returns an error if the argument is invalid. -// -// Unlike most Go functions, if Timestamp returns an error, the first return -// value is not the zero time.Time. Instead, it is the value obtained from the -// time.Unix function when passed the contents of the Timestamp, in the UTC -// locale. This may or may not be a meaningful time; many invalid Timestamps -// do map to valid time.Times. -// -// A nil Timestamp returns an error. The first return value in that case is -// undefined. -// -// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead. -func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) { - // Don't return the zero value on error, because corresponds to a valid - // timestamp. Instead return whatever time.Unix gives us. - var t time.Time - if ts == nil { - t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp - } else { - t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() - } - return t, validateTimestamp(ts) -} - -// TimestampNow returns a google.protobuf.Timestamp for the current time. -// -// Deprecated: Call the timestamppb.Now function instead. -func TimestampNow() *timestamppb.Timestamp { - ts, err := TimestampProto(time.Now()) - if err != nil { - panic("ptypes: time.Now() out of Timestamp range") - } - return ts -} - -// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. -// It returns an error if the resulting Timestamp is invalid. -// -// Deprecated: Call the timestamppb.New function instead. -func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) { - ts := ×tamppb.Timestamp{ - Seconds: t.Unix(), - Nanos: int32(t.Nanosecond()), - } - if err := validateTimestamp(ts); err != nil { - return nil, err - } - return ts, nil -} - -// TimestampString returns the RFC 3339 string for valid Timestamps. -// For invalid Timestamps, it returns an error message in parentheses. -// -// Deprecated: Call the ts.AsTime method instead, -// followed by a call to the Format method on the time.Time value. -func TimestampString(ts *timestamppb.Timestamp) string { - t, err := Timestamp(ts) - if err != nil { - return fmt.Sprintf("(%v)", err) - } - return t.Format(time.RFC3339Nano) -} - -// validateTimestamp determines whether a Timestamp is valid. -// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01) -// and has a Nanos field in the range [0, 1e9). -// -// If the Timestamp is valid, validateTimestamp returns nil. -// Otherwise, it returns an error that describes the problem. -// -// Every valid Timestamp can be represented by a time.Time, -// but the converse is not true. -func validateTimestamp(ts *timestamppb.Timestamp) error { - if ts == nil { - return errors.New("timestamp: nil Timestamp") - } - if ts.Seconds < minValidSeconds { - return fmt.Errorf("timestamp: %v before 0001-01-01", ts) - } - if ts.Seconds >= maxValidSeconds { - return fmt.Errorf("timestamp: %v after 10000-01-01", ts) - } - if ts.Nanos < 0 || ts.Nanos >= 1e9 { - return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts) - } - return nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go deleted file mode 100644 index a76f807600..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go +++ /dev/null @@ -1,64 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/ptypes/timestamp/timestamp.proto - -package timestamp - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/timestamp.proto. - -type Timestamp = timestamppb.Timestamp - -var File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = []byte{ - 0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37, - 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() } -func file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() { - if File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto = out.File - file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = nil - file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = nil - file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = nil -} diff --git a/vendor/github.com/okzk/sdnotify/LICENSE b/vendor/github.com/okzk/sdnotify/LICENSE deleted file mode 100644 index 46547518e8..0000000000 --- a/vendor/github.com/okzk/sdnotify/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 okzk - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/okzk/sdnotify/README.md b/vendor/github.com/okzk/sdnotify/README.md deleted file mode 100644 index ee85e0520f..0000000000 --- a/vendor/github.com/okzk/sdnotify/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# sdnotify - -sd_notify utility for golang. - -## Installation - - go get github.com/okzk/sdnotify - -## Example - -see [sample/main.go](sample/main.go) - -## License - -MIT \ No newline at end of file diff --git a/vendor/github.com/okzk/sdnotify/notify.go b/vendor/github.com/okzk/sdnotify/notify.go deleted file mode 100644 index f7d70e0dd9..0000000000 --- a/vendor/github.com/okzk/sdnotify/notify.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !linux - -package sdnotify - -// SdNotify sends a specified string to the systemd notification socket. -func SdNotify(state string) error { - // do nothing - return nil -} diff --git a/vendor/github.com/okzk/sdnotify/notify_linux.go b/vendor/github.com/okzk/sdnotify/notify_linux.go deleted file mode 100644 index 91d1efac41..0000000000 --- a/vendor/github.com/okzk/sdnotify/notify_linux.go +++ /dev/null @@ -1,23 +0,0 @@ -package sdnotify - -import ( - "net" - "os" -) - -// SdNotify sends a specified string to the systemd notification socket. -func SdNotify(state string) error { - name := os.Getenv("NOTIFY_SOCKET") - if name == "" { - return ErrSdNotifyNoSocket - } - - conn, err := net.DialUnix("unixgram", nil, &net.UnixAddr{Name: name, Net: "unixgram"}) - if err != nil { - return err - } - defer conn.Close() - - _, err = conn.Write([]byte(state)) - return err -} diff --git a/vendor/github.com/okzk/sdnotify/util.go b/vendor/github.com/okzk/sdnotify/util.go deleted file mode 100644 index 71e1e928bc..0000000000 --- a/vendor/github.com/okzk/sdnotify/util.go +++ /dev/null @@ -1,39 +0,0 @@ -package sdnotify - -import ( - "errors" - "fmt" -) - -// ErrSdNotifyNoSocket is the error returned when the NOTIFY_SOCKET does not exist. -var ErrSdNotifyNoSocket = errors.New("No socket") - -// Ready sends READY=1 to the systemd notify socket. -func Ready() error { - return SdNotify("READY=1") -} - -// Stopping sends STOPPING=1 to the systemd notify socket. -func Stopping() error { - return SdNotify("STOPPING=1") -} - -// Reloading sends RELOADING=1 to the systemd notify socket. -func Reloading() error { - return SdNotify("RELOADING=1") -} - -// Errno sends ERRNO=? to the systemd notify socket. -func Errno(errno int) error { - return SdNotify(fmt.Sprintf("ERRNO=%d", errno)) -} - -// Status sends STATUS=? to the systemd notify socket. -func Status(status string) error { - return SdNotify("STATUS=" + status) -} - -// Watchdog sends WATCHDOG=1 to the systemd notify socket. -func Watchdog() error { - return SdNotify("WATCHDOG=1") -} diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/.gitignore b/vendor/github.com/siphiuel/lc-proxy-wrapper/.gitignore deleted file mode 100644 index c1d44eae55..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -config.toml -lc-proxy-wrapper diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile b/vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile deleted file mode 100644 index 0c9b5f4336..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -include Makefile.vars - -build-verif-proxy-wrapper: - CGO_CFLAGS="$(CGO_CFLAGS)" go build -x -v -ldflags $(LDFLAGS) - -build-verif-proxy-wrapper-exe: - CGO_CFLAGS="$(CGO_CFLAGS)" go build -x -v -ldflags $(LDFLAGS) -o verif-proxy-wrapper ./main - -.PHONY: clean - -clean: - rm -rf nimcache libcb.a verif-proxy-wrapper - diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile.vars b/vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile.vars deleted file mode 100644 index 6d2972a902..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/Makefile.vars +++ /dev/null @@ -1,15 +0,0 @@ -NIMBUS_ETH1_PATH ?= $(CURDIR)/../nimbus-eth1 -NIMBASE_H_PATH ?= $(NIMBUS_ETH1_PATH)/vendor/nimbus-build-system/vendor/Nim-csources-v1/c_code/ -VERIF_PROXY_OUT_PATH ?= $(NIMBUS_ETH1_PATH)/build/libverifproxy - -CGO_CFLAGS += -I$(VERIF_PROXY_OUT_PATH) -I$(NIMBASE_H_PATH) - -EXTLDFLAGS=-lverifproxy -L$(VERIF_PROXY_OUT_PATH) - -ifeq (, $(findstring darwin, $(OS))) - EXTLDFLAGS += -framework Security -endif - -LDFLAGS ?= '-v "-extldflags=$(EXTLDFLAGS)"' - - diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/README.md b/vendor/github.com/siphiuel/lc-proxy-wrapper/README.md deleted file mode 100644 index f676cf4eb3..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Build Nim -nim c --app:staticlib --header:cb.h --noMain:on --nimcache:$HOME/c/lc-proxy-wrapper/nimcache cb.nim - -# Build go -go build -./lc-proxy-wrapper diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/cb.nim b/vendor/github.com/siphiuel/lc-proxy-wrapper/cb.nim deleted file mode 100644 index 4d56727c1f..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/cb.nim +++ /dev/null @@ -1,27 +0,0 @@ -{.pragma: some, header: "cb.h".} - -type - OnHeaderCallback = proc (s: cstring) {.cdecl.} - -proc callbackFn(json: string) {.exportc, cdecl.} = - echo "callbackFn", json - -# callbackFn "some" - -proc HelloFromNim(): cstring {.exportc.} = - return "Hello, World From Nim\n" - -var headerCallback: OnHeaderCallback - -proc setHeaderCallback*(cb: OnHeaderCallback) {.exportc.} = - headerCallback = cb - -proc invokeHeaderCallback*() {.exportc.} = - headerCallback("inside Nim 2222") - -proc testEcho*() {.exportc.} = - echo "in testEcho" - - - - diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/cfuncs.go b/vendor/github.com/siphiuel/lc-proxy-wrapper/cfuncs.go deleted file mode 100644 index afd85cd438..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/cfuncs.go +++ /dev/null @@ -1,12 +0,0 @@ -package proxy - -/* -#include - -void goCallback_cgo(char * json) { - printf("inside goCallback_cgo\n"); - void goCallback(char *); - goCallback(json); -} -*/ -import "C" diff --git a/vendor/github.com/siphiuel/lc-proxy-wrapper/proxy.go b/vendor/github.com/siphiuel/lc-proxy-wrapper/proxy.go deleted file mode 100644 index 9947d838af..0000000000 --- a/vendor/github.com/siphiuel/lc-proxy-wrapper/proxy.go +++ /dev/null @@ -1,104 +0,0 @@ -package proxy - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "os" - "runtime" - "unsafe" - - "github.com/BurntSushi/toml" -) - -/* -#include -#include "verifproxy.h" - -typedef void (*callback_type)(char *); -void goCallback_cgo(char *); - -*/ -import "C" - -type Web3UrlType struct { - Kind string `toml:"kind"` - Web3Url string `toml:"web3Url"` -} -type Config struct { - Eth2Network string `toml:"network"` - TrustedBlockRoot string `toml:"trusted-block-root"` - // Web3Url Web3UrlType `toml:"web3-url"` - Web3Url string `toml:"web3-url"` - RpcAddress string `toml:"rpc-address"` - RpcPort uint16 `toml:"rpc-port"` - LogLevel string `toml:"log-level"` -} - -type BeaconBlockHeader struct { - Slot uint64 `json:"slot"` - ProposerIndex uint64 `json:"proposer_index"` - ParentRoot string `json:"parent_root"` - StateRoot string `json:"state_root"` -} - -//export goCallback -func goCallback(json *C.char) { - goStr := C.GoString(json) - //C.free(unsafe.Pointer(json)) - fmt.Println("### goCallback " + goStr) - // var hdr BeaconBlockHeader - // err := json.NewDecoder([]byte(goStr)).Decode(&hdr) - // if err != nil { - // fmt.Println("### goCallback json parse error: " + err) - // } - // fmt.Println("Unmarshal result: " + hdr) -} -func createTomlFile(cfg *Config) string { - var buffer bytes.Buffer - err := toml.NewEncoder(&buffer).Encode(cfg) - if err != nil { - return "" - } - tomlFileName := "config.toml" - f, err := os.Create(tomlFileName) - if err != nil { - return "" - } - defer f.Close() - f.WriteString(buffer.String()) - - return tomlFileName -} - -func StartLightClient(ctx context.Context, cfg *Config) { - fmt.Println("vim-go") - cb := (C.callback_type)(unsafe.Pointer(C.goCallback_cgo)) - C.setOptimisticHeaderCallback(cb) - C.setFinalizedHeaderCallback(cb) - fmt.Println("vim-go 2") - - go func() { - runtime.LockOSThread() - // tomlFileName := createTomlFile(cfg) - // configCStr := C.CString(tomlFileName) - // C.startLc(configCStr) - defer runtime.UnlockOSThread() - jsonBytes, _ := json.Marshal(cfg) - jsonStr := string(jsonBytes) - fmt.Println("### jsonStr: ", jsonStr) - configCStr := C.CString(jsonStr) - C.startProxyViaJson(configCStr) - fmt.Println("inside go-func after startLcViaJson") - }() - go func() { - fmt.Println("Before range ctx.Done()") - for range ctx.Done() { - fmt.Println("inside go-func ctx.Done()") - C.quit() - } - }() - fmt.Println("vim-go 3") - -} diff --git a/vendor/github.com/status-im/extkeys/.golangci.yml b/vendor/github.com/status-im/extkeys/.golangci.yml new file mode 100644 index 0000000000..2c5a7a7d68 --- /dev/null +++ b/vendor/github.com/status-im/extkeys/.golangci.yml @@ -0,0 +1,44 @@ +run: + timeout: 5m + + build-tags: [] + exclude-dirs: + - .git/ + include: + - "*.go" + packages: + - "." + allow-parallel-runners: false + +linters: + disable-all: true + enable: + - errcheck + - gosec + - goimports + - govet + - ineffassign + - misspell + - goconst + +linters-settings: + errcheck: + check-type-assertions: false + check-blank: false + govet: + disable: + - shadow + goconst: + min-len: 3 + min-occurrences: 2 + gosec: + excludes: + - G115 + +issues: + exclude-rules: + - path: _test\.go + linters: + - goconst + max-issues-per-linter: 0 + max-same-issues: 0 \ No newline at end of file diff --git a/vendor/github.com/status-im/extkeys/hdkey.go b/vendor/github.com/status-im/extkeys/hdkey.go index 92621b1d16..b9750697ec 100644 --- a/vendor/github.com/status-im/extkeys/hdkey.go +++ b/vendor/github.com/status-im/extkeys/hdkey.go @@ -14,6 +14,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/base58" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) // Implementation of the following BIPs: @@ -219,7 +220,7 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) { parentKeyBigInt := new(big.Int).SetBytes(k.KeyData) keyBigInt := new(big.Int).SetBytes(secretKey) keyBigInt.Add(keyBigInt, parentKeyBigInt) - keyBigInt.Mod(keyBigInt, btcec.S256().N) + keyBigInt.Mod(keyBigInt, secp256k1.S256().N) // Make sure that child.KeyData is 32 bytes of data even if the value is represented with less bytes. // When we derive a child of this key, we call splitHMAC that does a sha512 of a seed that is: @@ -242,7 +243,7 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) { // Case #3: childKey = serP(point(parse256(IL)) + parentKey) // Calculate the corresponding intermediate public key for intermediate private key. - keyx, keyy := btcec.S256().ScalarBaseMult(secretKey) + keyx, keyy := secp256k1.S256().ScalarBaseMult(secretKey) if keyx.Sign() == 0 || keyy.Sign() == 0 { return nil, ErrInvalidKey } @@ -255,8 +256,8 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) { } // childKey = serP(point(parse256(IL)) + parentKey) - childX, childY := btcec.S256().Add(keyx, keyy, pubKey.X, pubKey.Y) - pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY} + childX, childY := secp256k1.S256().Add(keyx, keyy, pubKey.X, pubKey.Y) + pk := btcec.PublicKey{Curve: secp256k1.S256(), X: childX, Y: childY} child.KeyData = pk.SerializeCompressed() child.Version = PublicKeyVersion } @@ -414,14 +415,14 @@ func (k *ExtendedKey) pubKeyBytes() []byte { return k.KeyData } - pkx, pky := btcec.S256().ScalarBaseMult(k.KeyData) - pubKey := btcec.PublicKey{Curve: btcec.S256(), X: pkx, Y: pky} + pkx, pky := secp256k1.S256().ScalarBaseMult(k.KeyData) + pubKey := btcec.PublicKey{Curve: secp256k1.S256(), X: pkx, Y: pky} return pubKey.SerializeCompressed() } // ToECDSA returns the key data as ecdsa.PrivateKey func (k *ExtendedKey) ToECDSA() *ecdsa.PrivateKey { - privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), k.KeyData) + privKey, _ := btcec.PrivKeyFromBytes(secp256k1.S256(), k.KeyData) return privKey.ToECDSA() } @@ -467,7 +468,7 @@ func NewKeyFromString(key string) (*ExtendedKey, error) { // of the order of the secp256k1 curve and not be 0. keyData = keyData[1:] keyNum := new(big.Int).SetBytes(keyData) - if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 { + if keyNum.Cmp(secp256k1.S256().N) >= 0 || keyNum.Sign() == 0 { return nil, ErrInvalidSeed } } else { diff --git a/vendor/github.com/status-im/extkeys/utils.go b/vendor/github.com/status-im/extkeys/utils.go index a96b8da714..894d6a1cb3 100644 --- a/vendor/github.com/status-im/extkeys/utils.go +++ b/vendor/github.com/status-im/extkeys/utils.go @@ -6,7 +6,7 @@ import ( "errors" "math/big" - "github.com/btcsuite/btcd/btcec" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) // errors @@ -33,7 +33,7 @@ func splitHMAC(seed, salt []byte) (secretKey, chainCode []byte, err error) { // There's tiny possibility (<1 in 2^127) this invariant is violated: // error is returned in that case, and simple resolution is to request another child with i incremented. keyBigInt := new(big.Int).SetBytes(secretKey) - if keyBigInt.Cmp(btcec.S256().N) >= 0 || keyBigInt.Sign() == 0 { + if keyBigInt.Cmp(secp256k1.S256().N) >= 0 || keyBigInt.Sign() == 0 { err = ErrInvalidSecretKey } diff --git a/vendor/github.com/status-im/migrate/v4/database/postgres/README.md b/vendor/github.com/status-im/migrate/v4/database/postgres/README.md deleted file mode 100644 index f6312392b0..0000000000 --- a/vendor/github.com/status-im/migrate/v4/database/postgres/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# postgres - -`postgres://user:password@host:port/dbname?query` (`postgresql://` works, too) - -| URL Query | WithInstance Config | Description | -|------------|---------------------|-------------| -| `x-migrations-table` | `MigrationsTable` | Name of the migrations table | -| `dbname` | `DatabaseName` | The name of the database to connect to | -| `search_path` | | This variable specifies the order in which schemas are searched when an object is referenced by a simple name with no schema specified. | -| `user` | | The user to sign in as | -| `password` | | The user's password | -| `host` | | The host to connect to. Values that start with / are for unix domain sockets. (default is localhost) | -| `port` | | The port to bind to. (default is 5432) | -| `fallback_application_name` | | An application_name to fall back to if one isn't provided. | -| `connect_timeout` | | Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely. | -| `sslcert` | | Cert file location. The file must contain PEM encoded data. | -| `sslkey` | | Key file location. The file must contain PEM encoded data. | -| `sslrootcert` | | The location of the root certificate file. The file must contain PEM encoded data. | -| `sslmode` | | Whether or not to use SSL (disable\|require\|verify-ca\|verify-full) | - - -## Upgrading from v1 - -1. Write down the current migration version from schema_migrations -1. `DROP TABLE schema_migrations` -2. Wrap your existing migrations in transactions ([BEGIN/COMMIT](https://www.postgresql.org/docs/current/static/transaction-iso.html)) if you use multiple statements within one migration. -3. Download and install the latest migrate version. -4. Force the current migration version with `migrate force `. diff --git a/vendor/github.com/status-im/migrate/v4/database/postgres/TUTORIAL.md b/vendor/github.com/status-im/migrate/v4/database/postgres/TUTORIAL.md deleted file mode 100644 index 8b06a48642..0000000000 --- a/vendor/github.com/status-im/migrate/v4/database/postgres/TUTORIAL.md +++ /dev/null @@ -1,148 +0,0 @@ -# PostgreSQL tutorial for beginners - -## Create/configure database - -For the purpose of this tutorial let's create PostgreSQL database called `example`. -Our user here is `postgres`, password `password`, and host is `localhost`. -``` -psql -h localhost -U postgres -w -c "create database example;" -``` -When using Migrate CLI we need to pass to database URL. Let's export it to a variable for convienience: -``` -export POSTGRESQL_URL=postgres://postgres:password@localhost:5432/example?sslmode=disable -``` -`sslmode=disable` means that the connection with our database will not be encrypted. Enabling it is left as an exercise. - -You can find further description of database URLs [here](README.md#database-urls). - -## Create migrations -Let's create table called `users`: -``` -migrate create -ext sql -dir db/migrations -seq create_users_table -``` -If there were no errors, we should have two files available under `db/migrations` folder: -- 000001_create_users_table.down.sql -- 000001_create_users_table.up.sql - -Note the `sql` extension that we provided. - -In the `.up.sql` file let's create the table: -``` -CREATE TABLE IF NOT EXISTS users( - user_id serial PRIMARY KEY, - username VARCHAR (50) UNIQUE NOT NULL, - password VARCHAR (50) NOT NULL, - email VARCHAR (300) UNIQUE NOT NULL -); -``` -And in the `.down.sql` let's delete it: -``` -DROP TABLE IF EXISTS users; -``` -By adding `IF EXISTS/IF NOT EXISTS` we are making migrations idempotent - you can read more about idempotency in [getting started](GETTING_STARTED.md#create-migrations) - -## Run migrations -``` -migrate -database ${POSTGRESQL_URL} -path db/migrations up -``` -Let's check if the table was created properly by running `psql example -c "\d users"`. -The output you are supposed to see: -``` - Table "public.users" - Column | Type | Modifiers -----------+------------------------+--------------------------------------------------------- - user_id | integer | not null default nextval('users_user_id_seq'::regclass) - username | character varying(50) | not null - password | character varying(50) | not null - email | character varying(300) | not null -Indexes: - "users_pkey" PRIMARY KEY, btree (user_id) - "users_email_key" UNIQUE CONSTRAINT, btree (email) - "users_username_key" UNIQUE CONSTRAINT, btree (username) -``` -Great! Now let's check if running reverse migration also works: -``` -migrate -database ${POSTGRESQL_URL} -path db/migrations down -``` -Make sure to check if your database changed as expected in this case as well. - -## Database transactions - -To show database transactions usage, let's create another set of migrations by running: -``` -migrate create -ext sql -dir db/migrations -seq add_mood_to_users -``` -Again, it should create for us two migrations files: -- 000002_add_mood_to_users.down.sql -- 000002_add_mood_to_users.up.sql - -In Postgres, when we want our queries to be done in a transaction, we need to wrap it with `BEGIN` and `COMMIT` commands. -In our example, we are going to add a column to our database that can only accept enumerable values or NULL. -Migration up: -``` -BEGIN; - -CREATE TYPE enum_mood AS ENUM ( - 'happy', - 'sad', - 'neutral' -); -ALTER TABLE users ADD COLUMN mood enum_mood; - -COMMIT; -``` -Migration down: -``` -BEGIN; - -ALTER TABLE users DROP COLUMN mood; -DROP TYPE enum_mood; - -COMMIT; -``` - -Now we can run our new migration and check the database: -``` -migrate -database ${POSTGRESQL_URL} -path db/migrations up -psql example -c "\d users" -``` -Expected output: -``` - Table "public.users" - Column | Type | Modifiers -----------+------------------------+--------------------------------------------------------- - user_id | integer | not null default nextval('users_user_id_seq'::regclass) - username | character varying(50) | not null - password | character varying(50) | not null - email | character varying(300) | not null - mood | enum_mood | -Indexes: - "users_pkey" PRIMARY KEY, btree (user_id) - "users_email_key" UNIQUE CONSTRAINT, btree (email) - "users_username_key" UNIQUE CONSTRAINT, btree (username) -``` - -## Optional: Run migrations within your Go app -Here is a very simple app running migrations for the above configuration: -``` -import ( - "log" - - "github.com/golang-migrate/migrate/v4" - _ "github.com/golang-migrate/migrate/v4/database/postgres" - _ "github.com/golang-migrate/migrate/v4/source/file" -) - -func main() { - m, err := migrate.New( - "file://db/migrations", - "postgres://postgres:postgres@localhost:5432/example?sslmode=disable") - if err != nil { - log.Fatal(err) - } - if err := m.Up(); err != nil { - log.Fatal(err) - } -} -``` -You can find details [here](README.md#use-in-your-go-project) \ No newline at end of file diff --git a/vendor/github.com/status-im/migrate/v4/database/postgres/postgres.go b/vendor/github.com/status-im/migrate/v4/database/postgres/postgres.go deleted file mode 100644 index 7c334921aa..0000000000 --- a/vendor/github.com/status-im/migrate/v4/database/postgres/postgres.go +++ /dev/null @@ -1,362 +0,0 @@ -// +build go1.9 - -package postgres - -import ( - "context" - "database/sql" - "fmt" - "io" - "io/ioutil" - nurl "net/url" - "strconv" - "strings" - - "github.com/golang-migrate/migrate/v4" - "github.com/golang-migrate/migrate/v4/database" - multierror "github.com/hashicorp/go-multierror" - "github.com/lib/pq" -) - -func init() { - db := Postgres{} - database.Register("postgres", &db) - database.Register("postgresql", &db) -} - -var DefaultMigrationsTable = "schema_migrations" - -var ( - ErrNilConfig = fmt.Errorf("no config") - ErrNoDatabaseName = fmt.Errorf("no database name") - ErrNoSchema = fmt.Errorf("no schema") - ErrDatabaseDirty = fmt.Errorf("database is dirty") -) - -type Config struct { - MigrationsTable string - DatabaseName string - SchemaName string -} - -type Postgres struct { - // Locking and unlocking need to use the same connection - conn *sql.Conn - db *sql.DB - isLocked bool - - // Open and WithInstance need to guarantee that config is never nil - config *Config -} - -func WithInstance(instance *sql.DB, config *Config) (database.Driver, error) { - if config == nil { - return nil, ErrNilConfig - } - - if err := instance.Ping(); err != nil { - return nil, err - } - - query := `SELECT CURRENT_DATABASE()` - var databaseName string - if err := instance.QueryRow(query).Scan(&databaseName); err != nil { - return nil, &database.Error{OrigErr: err, Query: []byte(query)} - } - - if len(databaseName) == 0 { - return nil, ErrNoDatabaseName - } - - config.DatabaseName = databaseName - - query = `SELECT CURRENT_SCHEMA()` - var schemaName string - if err := instance.QueryRow(query).Scan(&schemaName); err != nil { - return nil, &database.Error{OrigErr: err, Query: []byte(query)} - } - - if len(schemaName) == 0 { - return nil, ErrNoSchema - } - - config.SchemaName = schemaName - - if len(config.MigrationsTable) == 0 { - config.MigrationsTable = DefaultMigrationsTable - } - - conn, err := instance.Conn(context.Background()) - - if err != nil { - return nil, err - } - - px := &Postgres{ - conn: conn, - db: instance, - config: config, - } - - if err := px.ensureVersionTable(); err != nil { - return nil, err - } - - return px, nil -} - -func (p *Postgres) Open(url string) (database.Driver, error) { - purl, err := nurl.Parse(url) - if err != nil { - return nil, err - } - - db, err := sql.Open("postgres", migrate.FilterCustomQuery(purl).String()) - if err != nil { - return nil, err - } - - migrationsTable := purl.Query().Get("x-migrations-table") - - px, err := WithInstance(db, &Config{ - DatabaseName: purl.Path, - MigrationsTable: migrationsTable, - }) - - if err != nil { - return nil, err - } - - return px, nil -} - -func (p *Postgres) Close() error { - connErr := p.conn.Close() - dbErr := p.db.Close() - if connErr != nil || dbErr != nil { - return fmt.Errorf("conn: %v, db: %v", connErr, dbErr) - } - return nil -} - -// https://www.postgresql.org/docs/9.6/static/explicit-locking.html#ADVISORY-LOCKS -func (p *Postgres) Lock() error { - if p.isLocked { - return database.ErrLocked - } - - aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.SchemaName) - if err != nil { - return err - } - - // This will wait indefinitely until the lock can be acquired. - query := `SELECT pg_advisory_lock($1)` - if _, err := p.conn.ExecContext(context.Background(), query, aid); err != nil { - return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)} - } - - p.isLocked = true - return nil -} - -func (p *Postgres) Unlock() error { - if !p.isLocked { - return nil - } - - aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.SchemaName) - if err != nil { - return err - } - - query := `SELECT pg_advisory_unlock($1)` - if _, err := p.conn.ExecContext(context.Background(), query, aid); err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - p.isLocked = false - return nil -} - -func (p *Postgres) Run(migration io.Reader) error { - migr, err := ioutil.ReadAll(migration) - if err != nil { - return err - } - - // run migration - query := string(migr[:]) - if _, err := p.conn.ExecContext(context.Background(), query); err != nil { - if pgErr, ok := err.(*pq.Error); ok { - var line uint - var col uint - var lineColOK bool - if pgErr.Position != "" { - if pos, err := strconv.ParseUint(pgErr.Position, 10, 64); err == nil { - line, col, lineColOK = computeLineFromPos(query, int(pos)) - } - } - message := fmt.Sprintf("migration failed: %s", pgErr.Message) - if lineColOK { - message = fmt.Sprintf("%s (column %d)", message, col) - } - if pgErr.Detail != "" { - message = fmt.Sprintf("%s, %s", message, pgErr.Detail) - } - return database.Error{OrigErr: err, Err: message, Query: migr, Line: line} - } - return database.Error{OrigErr: err, Err: "migration failed", Query: migr} - } - - return nil -} - -func computeLineFromPos(s string, pos int) (line uint, col uint, ok bool) { - // replace crlf with lf - s = strings.Replace(s, "\r\n", "\n", -1) - // pg docs: pos uses index 1 for the first character, and positions are measured in characters not bytes - runes := []rune(s) - if pos > len(runes) { - return 0, 0, false - } - sel := runes[:pos] - line = uint(runesCount(sel, newLine) + 1) - col = uint(pos - 1 - runesLastIndex(sel, newLine)) - return line, col, true -} - -const newLine = '\n' - -func runesCount(input []rune, target rune) int { - var count int - for _, r := range input { - if r == target { - count++ - } - } - return count -} - -func runesLastIndex(input []rune, target rune) int { - for i := len(input) - 1; i >= 0; i-- { - if input[i] == target { - return i - } - } - return -1 -} - -func (p *Postgres) SetVersion(version int, dirty bool) error { - tx, err := p.conn.BeginTx(context.Background(), &sql.TxOptions{}) - if err != nil { - return &database.Error{OrigErr: err, Err: "transaction start failed"} - } - - query := `TRUNCATE ` + pq.QuoteIdentifier(p.config.MigrationsTable) - if _, err := tx.Exec(query); err != nil { - if errRollback := tx.Rollback(); errRollback != nil { - err = multierror.Append(err, errRollback) - } - return &database.Error{OrigErr: err, Query: []byte(query)} - } - - if version >= 0 { - query = `INSERT INTO ` + pq.QuoteIdentifier(p.config.MigrationsTable) + ` (version, dirty) VALUES ($1, $2)` - if _, err := tx.Exec(query, version, dirty); err != nil { - if errRollback := tx.Rollback(); errRollback != nil { - err = multierror.Append(err, errRollback) - } - return &database.Error{OrigErr: err, Query: []byte(query)} - } - } - - if err := tx.Commit(); err != nil { - return &database.Error{OrigErr: err, Err: "transaction commit failed"} - } - - return nil -} - -func (p *Postgres) Version() (version int, dirty bool, err error) { - query := `SELECT version, dirty FROM ` + pq.QuoteIdentifier(p.config.MigrationsTable) + ` LIMIT 1` - err = p.conn.QueryRowContext(context.Background(), query).Scan(&version, &dirty) - switch { - case err == sql.ErrNoRows: - return database.NilVersion, false, nil - - case err != nil: - if e, ok := err.(*pq.Error); ok { - if e.Code.Name() == "undefined_table" { - return database.NilVersion, false, nil - } - } - return 0, false, &database.Error{OrigErr: err, Query: []byte(query)} - - default: - return version, dirty, nil - } -} - -func (p *Postgres) Drop() (err error) { - // select all tables in current schema - query := `SELECT table_name FROM information_schema.tables WHERE table_schema=(SELECT current_schema()) AND table_type='BASE TABLE'` - tables, err := p.conn.QueryContext(context.Background(), query) - if err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - defer func() { - if errClose := tables.Close(); errClose != nil { - err = multierror.Append(err, errClose) - } - }() - - // delete one table after another - tableNames := make([]string, 0) - for tables.Next() { - var tableName string - if err := tables.Scan(&tableName); err != nil { - return err - } - if len(tableName) > 0 { - tableNames = append(tableNames, tableName) - } - } - - if len(tableNames) > 0 { - // delete one by one ... - for _, t := range tableNames { - query = `DROP TABLE IF EXISTS ` + pq.QuoteIdentifier(t) + ` CASCADE` - if _, err := p.conn.ExecContext(context.Background(), query); err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - } - } - - return nil -} - -// ensureVersionTable checks if versions table exists and, if not, creates it. -// Note that this function locks the database, which deviates from the usual -// convention of "caller locks" in the Postgres type. -func (p *Postgres) ensureVersionTable() (err error) { - if err = p.Lock(); err != nil { - return err - } - - defer func() { - if e := p.Unlock(); e != nil { - if err == nil { - err = e - } else { - err = multierror.Append(err, e) - } - } - }() - - query := `CREATE TABLE IF NOT EXISTS ` + pq.QuoteIdentifier(p.config.MigrationsTable) + ` (version bigint not null primary key, dirty boolean not null)` - if _, err = p.conn.ExecContext(context.Background(), query); err != nil { - return &database.Error{OrigErr: err, Query: []byte(query)} - } - - return nil -} diff --git a/vendor/github.com/waku-org/waku-go-bindings/waku/common/config.go b/vendor/github.com/waku-org/waku-go-bindings/waku/common/config.go index 5026ab00a6..a40fb747f4 100644 --- a/vendor/github.com/waku-org/waku-go-bindings/waku/common/config.go +++ b/vendor/github.com/waku-org/waku-go-bindings/waku/common/config.go @@ -33,4 +33,8 @@ type WakuConfig struct { PeerExchangeNode string `json:"peerExchangeNode,omitempty"` TcpPort int `json:"tcpPort,omitempty"` RateLimits RateLimitsConfig `json:"rateLimits,omitempty"` + DnsAddrsNameServers []string `json:"dnsAddrsNameServers,omitempty"` + Discv5EnrAutoUpdate bool `json:"discv5EnrAutoUpdate,omitempty"` + MaxConnections int `json:"maxConnections,omitempty"` + NumShardsInNetwork uint16 `json:"numShardsInNetwork"` } diff --git a/vendor/github.com/waku-org/waku-go-bindings/waku/nwaku.go b/vendor/github.com/waku-org/waku-go-bindings/waku/nwaku.go index d88fe4cae4..fbeb0f0d73 100644 --- a/vendor/github.com/waku-org/waku-go-bindings/waku/nwaku.go +++ b/vendor/github.com/waku-org/waku-go-bindings/waku/nwaku.go @@ -8,17 +8,17 @@ package waku #include #include - extern void globalEventCallback(int ret, char* msg, size_t len, void* userData); + extern void wakuGlobalEventCallback(int ret, char* msg, size_t len, void* userData); typedef struct { int ret; char* msg; size_t len; void* ffiWg; - } Resp; + } WakuResp; static void* allocResp(void* wg) { - Resp* r = calloc(1, sizeof(Resp)); + WakuResp* r = calloc(1, sizeof(WakuResp)); r->ffiWg = wg; return r; } @@ -33,7 +33,7 @@ package waku if (resp == NULL) { return NULL; } - Resp* m = (Resp*) resp; + WakuResp* m = (WakuResp*) resp; return m->msg; } @@ -41,7 +41,7 @@ package waku if (resp == NULL) { return 0; } - Resp* m = (Resp*) resp; + WakuResp* m = (WakuResp*) resp; return m->len; } @@ -49,57 +49,57 @@ package waku if (resp == NULL) { return 0; } - Resp* m = (Resp*) resp; + WakuResp* m = (WakuResp*) resp; return m->ret; } // resp must be set != NULL in case interest on retrieving data from the callback - void GoCallback(int ret, char* msg, size_t len, void* resp); + void WakuGoCallback(int ret, char* msg, size_t len, void* resp); static void* cGoWakuNew(const char* configJson, void* resp) { // We pass NULL because we are not interested in retrieving data from this callback - void* ret = waku_new(configJson, (WakuCallBack) GoCallback, resp); + void* ret = waku_new(configJson, (WakuCallBack) WakuGoCallback, resp); return ret; } static void cGoWakuStart(void* wakuCtx, void* resp) { - waku_start(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_start(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuStop(void* wakuCtx, void* resp) { - waku_stop(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_stop(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuDestroy(void* wakuCtx, void* resp) { - waku_destroy(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_destroy(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuStartDiscV5(void* wakuCtx, void* resp) { - waku_start_discv5(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_start_discv5(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuStopDiscV5(void* wakuCtx, void* resp) { - waku_stop_discv5(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_stop_discv5(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuVersion(void* wakuCtx, void* resp) { - waku_version(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_version(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuSetEventCallback(void* wakuCtx) { - // The 'globalEventCallback' Go function is shared amongst all possible Waku instances. + // The 'wakuGlobalEventCallback' Go function is shared amongst all possible Waku instances. - // Given that the 'globalEventCallback' is shared, we pass again the + // Given that the 'wakuGlobalEventCallback' is shared, we pass again the // wakuCtx instance but in this case is needed to pick up the correct method // that will handle the event. - // In other words, for every call the libwaku makes to globalEventCallback, + // In other words, for every call the libwaku makes to wakuGlobalEventCallback, // the 'userData' parameter will bring the context of the node that registered - // that globalEventCallback. + // that wakuGlobalEventCallback. // This technique is needed because cgo only allows to export Go functions and not methods. - waku_set_event_callback(wakuCtx, (WakuCallBack) globalEventCallback, wakuCtx); + waku_set_event_callback(wakuCtx, (WakuCallBack) wakuGlobalEventCallback, wakuCtx); } static void cGoWakuContentTopic(void* wakuCtx, @@ -114,16 +114,16 @@ package waku appVersion, contentTopicName, encoding, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuPubsubTopic(void* wakuCtx, char* topicName, void* resp) { - waku_pubsub_topic(wakuCtx, topicName, (WakuCallBack) GoCallback, resp); + waku_pubsub_topic(wakuCtx, topicName, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuDefaultPubsubTopic(void* wakuCtx, void* resp) { - waku_default_pubsub_topic(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_default_pubsub_topic(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuRelayPublish(void* wakuCtx, @@ -136,14 +136,14 @@ package waku pubSubTopic, jsonWakuMessage, timeoutMs, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuRelaySubscribe(void* wakuCtx, char* pubSubTopic, void* resp) { waku_relay_subscribe(wakuCtx, pubSubTopic, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -152,7 +152,7 @@ package waku clusterId, shardId, publicKey, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -160,7 +160,7 @@ package waku waku_relay_unsubscribe(wakuCtx, pubSubTopic, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -168,7 +168,7 @@ package waku waku_connect(wakuCtx, peerMultiAddr, timeoutMs, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -182,7 +182,7 @@ package waku peerMultiAddr, protocol, timeoutMs, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -196,59 +196,65 @@ package waku peerId, protocol, timeoutMs, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuDisconnectPeerById(void* wakuCtx, char* peerId, void* resp) { waku_disconnect_peer_by_id(wakuCtx, peerId, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, + resp); + } + + static void cGoWakuDisconnectAllPeers(void* wakuCtx, void* resp) { + waku_disconnect_all_peers(wakuCtx, + (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuListenAddresses(void* wakuCtx, void* resp) { - waku_listen_addresses(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_listen_addresses(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetMyENR(void* ctx, void* resp) { - waku_get_my_enr(ctx, (WakuCallBack) GoCallback, resp); + waku_get_my_enr(ctx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetMyPeerId(void* ctx, void* resp) { - waku_get_my_peerid(ctx, (WakuCallBack) GoCallback, resp); + waku_get_my_peerid(ctx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuPingPeer(void* ctx, char* peerAddr, int timeoutMs, void* resp) { - waku_ping_peer(ctx, peerAddr, timeoutMs, (WakuCallBack) GoCallback, resp); + waku_ping_peer(ctx, peerAddr, timeoutMs, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetPeersInMesh(void* ctx, char* pubSubTopic, void* resp) { - waku_relay_get_peers_in_mesh(ctx, pubSubTopic, (WakuCallBack) GoCallback, resp); + waku_relay_get_peers_in_mesh(ctx, pubSubTopic, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetNumPeersInMesh(void* ctx, char* pubSubTopic, void* resp) { - waku_relay_get_num_peers_in_mesh(ctx, pubSubTopic, (WakuCallBack) GoCallback, resp); + waku_relay_get_num_peers_in_mesh(ctx, pubSubTopic, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetNumConnectedRelayPeers(void* ctx, char* pubSubTopic, void* resp) { - waku_relay_get_num_connected_peers(ctx, pubSubTopic, (WakuCallBack) GoCallback, resp); + waku_relay_get_num_connected_peers(ctx, pubSubTopic, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetConnectedRelayPeers(void* ctx, char* pubSubTopic, void* resp) { - waku_relay_get_connected_peers(ctx, pubSubTopic, (WakuCallBack) GoCallback, resp); + waku_relay_get_connected_peers(ctx, pubSubTopic, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetConnectedPeers(void* wakuCtx, void* resp) { - waku_get_connected_peers(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_get_connected_peers(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetPeerIdsFromPeerStore(void* wakuCtx, void* resp) { - waku_get_peerids_from_peerstore(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_get_peerids_from_peerstore(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuGetConnectedPeersInfo(void* wakuCtx, void* resp) { - waku_get_connected_peers_info(wakuCtx, (WakuCallBack) GoCallback, resp); + waku_get_connected_peers_info(wakuCtx, (WakuCallBack) WakuGoCallback, resp); } static void cGoWakuLightpushPublish(void* wakuCtx, @@ -259,7 +265,7 @@ package waku waku_lightpush_publish(wakuCtx, pubSubTopic, jsonWakuMessage, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -273,7 +279,7 @@ package waku jsonQuery, peerAddr, timeoutMs, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -283,7 +289,7 @@ package waku waku_peer_exchange_request(wakuCtx, numPeers, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -293,7 +299,7 @@ package waku waku_get_peerids_by_protocol(wakuCtx, protocol, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } @@ -307,10 +313,18 @@ package waku entTreeUrl, nameDnsServer, timeoutMs, - (WakuCallBack) GoCallback, + (WakuCallBack) WakuGoCallback, resp); } + static void cGoWakuIsOnline(void* wakuCtx, void* resp) { + waku_is_online(wakuCtx, (WakuCallBack) WakuGoCallback, resp); + } + + static void cGoWakuGetMetrics(void* wakuCtx, void* resp) { + waku_get_metrics(wakuCtx, (WakuCallBack) WakuGoCallback, resp); + } + */ import "C" import ( @@ -342,10 +356,10 @@ const MsgChanBufferSize = 1024 const TopicHealthChanBufferSize = 1024 const ConnectionChangeChanBufferSize = 1024 -//export GoCallback -func GoCallback(ret C.int, msg *C.char, len C.size_t, resp unsafe.Pointer) { +//export WakuGoCallback +func WakuGoCallback(ret C.int, msg *C.char, len C.size_t, resp unsafe.Pointer) { if resp != nil { - m := (*C.Resp)(resp) + m := (*C.WakuResp)(resp) m.ret = ret m.msg = msg m.len = len @@ -384,16 +398,16 @@ func NewWakuNode(config *common.WakuConfig, nodeName string) (*WakuNode, error) defer C.free(unsafe.Pointer(cJsonConfig)) defer C.freeResp(resp) + wg.Add(1) + n.wakuCtx = C.cGoWakuNew(cJsonConfig, resp) + wg.Wait() + if C.getRet(resp) != C.RET_OK { errMsg := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) Error("error wakuNew for %s: %v", nodeName, errMsg) return nil, errors.New(errMsg) } - wg.Add(1) - n.wakuCtx = C.cGoWakuNew(cJsonConfig, resp) - wg.Wait() - n.MsgChan = make(chan common.Envelope, MsgChanBufferSize) n.TopicHealthChan = make(chan topicHealth, TopicHealthChanBufferSize) n.ConnectionChangeChan = make(chan connectionChange, ConnectionChangeChanBufferSize) @@ -428,8 +442,8 @@ func unregisterNode(node *WakuNode) { delete(nodeRegistry, node.wakuCtx) } -//export globalEventCallback -func globalEventCallback(callerRet C.int, msg *C.char, len C.size_t, userData unsafe.Pointer) { +//export wakuGlobalEventCallback +func wakuGlobalEventCallback(callerRet C.int, msg *C.char, len C.size_t, userData unsafe.Pointer) { if callerRet == C.RET_OK { eventStr := C.GoStringN(msg, C.int(len)) node, ok := nodeRegistry[userData] // userData contains node's ctx @@ -439,9 +453,9 @@ func globalEventCallback(callerRet C.int, msg *C.char, len C.size_t, userData un } else { if len != 0 { errMsg := C.GoStringN(msg, C.int(len)) - Error("globalEventCallback retCode not ok, retCode: %v: %v", callerRet, errMsg) + Error("wakuGlobalEventCallback retCode not ok, retCode: %v: %v", callerRet, errMsg) } else { - Error("globalEventCallback retCode not ok, retCode: %v", callerRet) + Error("wakuGlobalEventCallback retCode not ok, retCode: %v", callerRet) } } } @@ -632,6 +646,23 @@ func (n *WakuNode) DisconnectPeerByID(peerID peer.ID) error { return errors.New(errMsg) } +func (n *WakuNode) DisconnectAllPeers() error { + wg := sync.WaitGroup{} + + var resp = C.allocResp(unsafe.Pointer(&wg)) + defer C.freeResp(resp) + + wg.Add(1) + C.cGoWakuDisconnectAllPeers(n.wakuCtx, resp) + wg.Wait() + + if C.getRet(resp) == C.RET_OK { + return nil + } + errMsg := "error DisconnectAllPeers: " + C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + return errors.New(errMsg) +} + func (n *WakuNode) GetConnectedPeers() (peer.IDSlice, error) { if n == nil { err := errors.New("waku node is nil") @@ -1590,3 +1621,73 @@ func (n *WakuNode) DisconnectPeer(target *WakuNode) error { Debug("Successfully disconnected %s from %s", n.nodeName, target.nodeName) return nil } + +func (n *WakuNode) IsOnline() (bool, error) { + if n == nil { + err := errors.New("waku node is nil") + Error("Failed to get online state %v", err) + return false, err + } + + Debug("Querying online state for %v", n.nodeName) + + wg := sync.WaitGroup{} + var resp = C.allocResp(unsafe.Pointer(&wg)) + defer C.freeResp(resp) + + wg.Add(1) + C.cGoWakuIsOnline(n.wakuCtx, resp) + wg.Wait() + + if C.getRet(resp) == C.RET_OK { + onlineStr := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + + if onlineStr == "true" { + return true, nil + } + + return false, nil + + } + + errMsg := "error IsOnline: " + C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + Error("Failed to query online state for %v: %v", n.nodeName, errMsg) + + return false, errors.New(errMsg) +} + +func (n *WakuNode) GetMetrics() (string, error) { + if n == nil { + err := errors.New("waku node is nil") + Error("Failed to get metrics %v", err) + return "", err + } + + Debug("Querying metrics for %v", n.nodeName) + + wg := sync.WaitGroup{} + var resp = C.allocResp(unsafe.Pointer(&wg)) + defer C.freeResp(resp) + + wg.Add(1) + C.cGoWakuGetMetrics(n.wakuCtx, resp) + wg.Wait() + + if C.getRet(resp) == C.RET_OK { + metricsStr := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + + if metricsStr == "" { + errMsg := "received empty metrics response" + Error(errMsg) + return "", errors.New(errMsg) + } + + return metricsStr, nil + + } + + errMsg := "error GetMetrics: " + C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + Error("Failed to query metrics for %v: %v", n.nodeName, errMsg) + + return "", errors.New(errMsg) +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s index 9ae8206c20..f75162e039 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s @@ -1,722 +1,4517 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. +// Code generated by command: go run blake2bAVX2_amd64_asm.go -out ../../blake2bAVX2_amd64.s -pkg blake2b. DO NOT EDIT. //go:build amd64 && gc && !purego #include "textflag.h" -DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 -DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b -DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b -DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1 -GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32 - -DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1 -DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f -DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b -DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179 -GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32 - -DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403 -DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b -DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403 -DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b -GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32 - -DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302 -DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a -DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302 -DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a -GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32 - -DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 -DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b -GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16 - -DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b -DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 -GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16 - -DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1 -DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f -GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16 - -DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b -DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 -GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16 - -DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403 -DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b -GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16 - -DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302 -DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a -GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16 - -#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 -#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 -#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e -#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 -#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 - -#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \ - VPADDQ m0, Y0, Y0; \ - VPADDQ Y1, Y0, Y0; \ - VPXOR Y0, Y3, Y3; \ - VPSHUFD $-79, Y3, Y3; \ - VPADDQ Y3, Y2, Y2; \ - VPXOR Y2, Y1, Y1; \ - VPSHUFB c40, Y1, Y1; \ - VPADDQ m1, Y0, Y0; \ - VPADDQ Y1, Y0, Y0; \ - VPXOR Y0, Y3, Y3; \ - VPSHUFB c48, Y3, Y3; \ - VPADDQ Y3, Y2, Y2; \ - VPXOR Y2, Y1, Y1; \ - VPADDQ Y1, Y1, t; \ - VPSRLQ $63, Y1, Y1; \ - VPXOR t, Y1, Y1; \ - VPERMQ_0x39_Y1_Y1; \ - VPERMQ_0x4E_Y2_Y2; \ - VPERMQ_0x93_Y3_Y3; \ - VPADDQ m2, Y0, Y0; \ - VPADDQ Y1, Y0, Y0; \ - VPXOR Y0, Y3, Y3; \ - VPSHUFD $-79, Y3, Y3; \ - VPADDQ Y3, Y2, Y2; \ - VPXOR Y2, Y1, Y1; \ - VPSHUFB c40, Y1, Y1; \ - VPADDQ m3, Y0, Y0; \ - VPADDQ Y1, Y0, Y0; \ - VPXOR Y0, Y3, Y3; \ - VPSHUFB c48, Y3, Y3; \ - VPADDQ Y3, Y2, Y2; \ - VPXOR Y2, Y1, Y1; \ - VPADDQ Y1, Y1, t; \ - VPSRLQ $63, Y1, Y1; \ - VPXOR t, Y1, Y1; \ - VPERMQ_0x39_Y3_Y3; \ - VPERMQ_0x4E_Y2_Y2; \ - VPERMQ_0x93_Y1_Y1 - -#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E -#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26 -#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E -#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36 -#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E - -#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n -#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n -#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n -#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n -#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n - -#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01 -#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01 -#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01 -#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01 -#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01 - -#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01 -#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01 -#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01 -#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01 -#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01 - -#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8 -#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01 - -// load msg: Y12 = (i0, i1, i2, i3) -// i0, i1, i2, i3 must not be 0 -#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \ - VMOVQ_SI_X12(i0*8); \ - VMOVQ_SI_X11(i2*8); \ - VPINSRQ_1_SI_X12(i1*8); \ - VPINSRQ_1_SI_X11(i3*8); \ - VINSERTI128 $1, X11, Y12, Y12 - -// load msg: Y13 = (i0, i1, i2, i3) -// i0, i1, i2, i3 must not be 0 -#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \ - VMOVQ_SI_X13(i0*8); \ - VMOVQ_SI_X11(i2*8); \ - VPINSRQ_1_SI_X13(i1*8); \ - VPINSRQ_1_SI_X11(i3*8); \ - VINSERTI128 $1, X11, Y13, Y13 - -// load msg: Y14 = (i0, i1, i2, i3) -// i0, i1, i2, i3 must not be 0 -#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \ - VMOVQ_SI_X14(i0*8); \ - VMOVQ_SI_X11(i2*8); \ - VPINSRQ_1_SI_X14(i1*8); \ - VPINSRQ_1_SI_X11(i3*8); \ - VINSERTI128 $1, X11, Y14, Y14 - -// load msg: Y15 = (i0, i1, i2, i3) -// i0, i1, i2, i3 must not be 0 -#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \ - VMOVQ_SI_X15(i0*8); \ - VMOVQ_SI_X11(i2*8); \ - VPINSRQ_1_SI_X15(i1*8); \ - VPINSRQ_1_SI_X11(i3*8); \ - VINSERTI128 $1, X11, Y15, Y15 - -#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \ - VMOVQ_SI_X12_0; \ - VMOVQ_SI_X11(4*8); \ - VPINSRQ_1_SI_X12(2*8); \ - VPINSRQ_1_SI_X11(6*8); \ - VINSERTI128 $1, X11, Y12, Y12; \ - LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \ - LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \ - LOAD_MSG_AVX2_Y15(9, 11, 13, 15) - -#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \ - LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \ - LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \ - VMOVQ_SI_X11(11*8); \ - VPSHUFD $0x4E, 0*8(SI), X14; \ - VPINSRQ_1_SI_X11(5*8); \ - VINSERTI128 $1, X11, Y14, Y14; \ - LOAD_MSG_AVX2_Y15(12, 2, 7, 3) - -#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \ - VMOVQ_SI_X11(5*8); \ - VMOVDQU 11*8(SI), X12; \ - VPINSRQ_1_SI_X11(15*8); \ - VINSERTI128 $1, X11, Y12, Y12; \ - VMOVQ_SI_X13(8*8); \ - VMOVQ_SI_X11(2*8); \ - VPINSRQ_1_SI_X13_0; \ - VPINSRQ_1_SI_X11(13*8); \ - VINSERTI128 $1, X11, Y13, Y13; \ - LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \ - LOAD_MSG_AVX2_Y15(14, 6, 1, 4) - -#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \ - LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \ - LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \ - LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \ - VMOVQ_SI_X15(6*8); \ - VMOVQ_SI_X11_0; \ - VPINSRQ_1_SI_X15(10*8); \ - VPINSRQ_1_SI_X11(8*8); \ - VINSERTI128 $1, X11, Y15, Y15 - -#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \ - LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \ - VMOVQ_SI_X13_0; \ - VMOVQ_SI_X11(4*8); \ - VPINSRQ_1_SI_X13(7*8); \ - VPINSRQ_1_SI_X11(15*8); \ - VINSERTI128 $1, X11, Y13, Y13; \ - LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \ - LOAD_MSG_AVX2_Y15(1, 12, 8, 13) - -#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \ - VMOVQ_SI_X12(2*8); \ - VMOVQ_SI_X11_0; \ - VPINSRQ_1_SI_X12(6*8); \ - VPINSRQ_1_SI_X11(8*8); \ - VINSERTI128 $1, X11, Y12, Y12; \ - LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \ - LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \ - LOAD_MSG_AVX2_Y15(13, 5, 14, 9) - -#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \ - LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \ - LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \ - VMOVQ_SI_X14_0; \ - VPSHUFD $0x4E, 8*8(SI), X11; \ - VPINSRQ_1_SI_X14(6*8); \ - VINSERTI128 $1, X11, Y14, Y14; \ - LOAD_MSG_AVX2_Y15(7, 3, 2, 11) - -#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \ - LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \ - LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \ - LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \ - VMOVQ_SI_X15_0; \ - VMOVQ_SI_X11(6*8); \ - VPINSRQ_1_SI_X15(4*8); \ - VPINSRQ_1_SI_X11(10*8); \ - VINSERTI128 $1, X11, Y15, Y15 - -#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \ - VMOVQ_SI_X12(6*8); \ - VMOVQ_SI_X11(11*8); \ - VPINSRQ_1_SI_X12(14*8); \ - VPINSRQ_1_SI_X11_0; \ - VINSERTI128 $1, X11, Y12, Y12; \ - LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \ - VMOVQ_SI_X11(1*8); \ - VMOVDQU 12*8(SI), X14; \ - VPINSRQ_1_SI_X11(10*8); \ - VINSERTI128 $1, X11, Y14, Y14; \ - VMOVQ_SI_X15(2*8); \ - VMOVDQU 4*8(SI), X11; \ - VPINSRQ_1_SI_X15(7*8); \ - VINSERTI128 $1, X11, Y15, Y15 - -#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \ - LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \ - VMOVQ_SI_X13(2*8); \ - VPSHUFD $0x4E, 5*8(SI), X11; \ - VPINSRQ_1_SI_X13(4*8); \ - VINSERTI128 $1, X11, Y13, Y13; \ - LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \ - VMOVQ_SI_X15(11*8); \ - VMOVQ_SI_X11(12*8); \ - VPINSRQ_1_SI_X15(14*8); \ - VPINSRQ_1_SI_X11_0; \ - VINSERTI128 $1, X11, Y15, Y15 - // func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) -TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment - MOVQ h+0(FP), AX - MOVQ c+8(FP), BX - MOVQ flag+16(FP), CX - MOVQ blocks_base+24(FP), SI - MOVQ blocks_len+32(FP), DI - - MOVQ SP, DX - ADDQ $31, DX - ANDQ $~31, DX - - MOVQ CX, 16(DX) - XORQ CX, CX - MOVQ CX, 24(DX) - - VMOVDQU ·AVX2_c40<>(SB), Y4 - VMOVDQU ·AVX2_c48<>(SB), Y5 - - VMOVDQU 0(AX), Y8 +// Requires: AVX, AVX2 +TEXT ·hashBlocksAVX2(SB), NOSPLIT, $320-48 + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + MOVQ SP, DX + ADDQ $+31, DX + ANDQ $-32, DX + MOVQ CX, 16(DX) + XORQ CX, CX + MOVQ CX, 24(DX) + VMOVDQU ·AVX2_c40<>+0(SB), Y4 + VMOVDQU ·AVX2_c48<>+0(SB), Y5 + VMOVDQU (AX), Y8 VMOVDQU 32(AX), Y9 - VMOVDQU ·AVX2_iv0<>(SB), Y6 - VMOVDQU ·AVX2_iv1<>(SB), Y7 - - MOVQ 0(BX), R8 - MOVQ 8(BX), R9 - MOVQ R9, 8(DX) + VMOVDQU ·AVX2_iv0<>+0(SB), Y6 + VMOVDQU ·AVX2_iv1<>+0(SB), Y7 + MOVQ (BX), R8 + MOVQ 8(BX), R9 + MOVQ R9, 8(DX) loop: - ADDQ $128, R8 - MOVQ R8, 0(DX) - CMPQ R8, $128 + ADDQ $0x80, R8 + MOVQ R8, (DX) + CMPQ R8, $0x80 JGE noinc INCQ R9 MOVQ R9, 8(DX) noinc: - VMOVDQA Y8, Y0 - VMOVDQA Y9, Y1 - VMOVDQA Y6, Y2 - VPXOR 0(DX), Y7, Y3 - - LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() - VMOVDQA Y12, 32(DX) - VMOVDQA Y13, 64(DX) - VMOVDQA Y14, 96(DX) - VMOVDQA Y15, 128(DX) - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() - VMOVDQA Y12, 160(DX) - VMOVDQA Y13, 192(DX) - VMOVDQA Y14, 224(DX) - VMOVDQA Y15, 256(DX) - - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() - ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) - - ROUND_AVX2(32(DX), 64(DX), 96(DX), 128(DX), Y10, Y4, Y5) - ROUND_AVX2(160(DX), 192(DX), 224(DX), 256(DX), Y10, Y4, Y5) - - VPXOR Y0, Y8, Y8 - VPXOR Y1, Y9, Y9 - VPXOR Y2, Y8, Y8 - VPXOR Y3, Y9, Y9 - - LEAQ 128(SI), SI - SUBQ $128, DI - JNE loop - - MOVQ R8, 0(BX) - MOVQ R9, 8(BX) - - VMOVDQU Y8, 0(AX) - VMOVDQU Y9, 32(AX) + VMOVDQA Y8, Y0 + VMOVDQA Y9, Y1 + VMOVDQA Y6, Y2 + VPXOR (DX), Y7, Y3 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x26 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x20 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x10 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x30 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x08 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x28 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x38 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x40 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x60 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x70 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x68 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x58 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x78 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VMOVDQA Y12, 32(DX) + VMOVDQA Y13, 64(DX) + VMOVDQA Y14, 96(DX) + VMOVDQA Y15, 128(DX) + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x48 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x20 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x68 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x50 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x78 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x40 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x30 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x58 + VPSHUFD $0x4e, (SI), X14 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x28 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x38 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x10 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x18 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VMOVDQA Y12, 160(DX) + VMOVDQA Y13, 192(DX) + VMOVDQA Y14, 224(DX) + VMOVDQA Y15, 256(DX) + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x28 + VMOVDQU 88(SI), X12 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x78 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x40 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x10 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x2e + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x68 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x50 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x38 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x48 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x08 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x30 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x20 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x38 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x68 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x58 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x60 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x08 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x70 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x10 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x20 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x78 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x30 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x1e + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x40 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x10 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x50 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x2e + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x20 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x38 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x78 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x30 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x58 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x18 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x08 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x40 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x60 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x68 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x10 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x1e + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x30 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x40 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x58 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x18 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x20 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x78 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x38 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x08 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x68 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x70 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x48 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x70 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x08 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x20 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x28 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x68 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x78 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x50 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x36 + VPSHUFD $0x4e, 64(SI), X11 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x30 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x38 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x10 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x58 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x68 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x60 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x38 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x18 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x58 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x08 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x48 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x28 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x40 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x78 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x10 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x3e + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x30 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x20 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x50 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x30 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x58 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x1e + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x78 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x18 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x48 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x40 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x08 + VMOVDQU 96(SI), X14 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x50 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x10 + VMOVDQU 32(SI), X11 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x38 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x50 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x38 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x40 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x08 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y12, Y12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x10 + VPSHUFD $0x4e, 40(SI), X11 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x20 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y13, Y13 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x78 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x18 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x48 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x5e + BYTE $0x68 + BYTE $0x01 + VINSERTI128 $0x01, X11, Y14, Y14 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x58 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x5e + BYTE $0x60 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0xa1 + BYTE $0x22 + BYTE $0x1e + BYTE $0x01 + VINSERTI128 $0x01, X11, Y15, Y15 + VPADDQ Y12, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y13, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ Y14, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ Y15, Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + VPADDQ 32(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ 64(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ 96(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ 128(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + VPADDQ 160(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ 192(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x93 + VPADDQ 224(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFD $-79, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPSHUFB Y4, Y1, Y1 + VPADDQ 256(DX), Y0, Y0 + VPADDQ Y1, Y0, Y0 + VPXOR Y0, Y3, Y3 + VPSHUFB Y5, Y3, Y3 + VPADDQ Y3, Y2, Y2 + VPXOR Y2, Y1, Y1 + VPADDQ Y1, Y1, Y10 + VPSRLQ $0x3f, Y1, Y1 + VPXOR Y10, Y1, Y1 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xdb + BYTE $0x39 + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xd2 + BYTE $0x4e + BYTE $0xc4 + BYTE $0xe3 + BYTE $0xfd + BYTE $0x00 + BYTE $0xc9 + BYTE $0x93 + VPXOR Y0, Y8, Y8 + VPXOR Y1, Y9, Y9 + VPXOR Y2, Y8, Y8 + VPXOR Y3, Y9, Y9 + LEAQ 128(SI), SI + SUBQ $0x80, DI + JNE loop + MOVQ R8, (BX) + MOVQ R9, 8(BX) + VMOVDQU Y8, (AX) + VMOVDQU Y9, 32(AX) VZEROUPPER - RET -#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA -#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB -#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF -#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD -#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE - -#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7 -#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF -#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7 -#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF -#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7 -#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7 -#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF -#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF - -#define SHUFFLE_AVX() \ - VMOVDQA X6, X13; \ - VMOVDQA X2, X14; \ - VMOVDQA X4, X6; \ - VPUNPCKLQDQ_X13_X13_X15; \ - VMOVDQA X5, X4; \ - VMOVDQA X6, X5; \ - VPUNPCKHQDQ_X15_X7_X6; \ - VPUNPCKLQDQ_X7_X7_X15; \ - VPUNPCKHQDQ_X15_X13_X7; \ - VPUNPCKLQDQ_X3_X3_X15; \ - VPUNPCKHQDQ_X15_X2_X2; \ - VPUNPCKLQDQ_X14_X14_X15; \ - VPUNPCKHQDQ_X15_X3_X3; \ - -#define SHUFFLE_AVX_INV() \ - VMOVDQA X2, X13; \ - VMOVDQA X4, X14; \ - VPUNPCKLQDQ_X2_X2_X15; \ - VMOVDQA X5, X4; \ - VPUNPCKHQDQ_X15_X3_X2; \ - VMOVDQA X14, X5; \ - VPUNPCKLQDQ_X3_X3_X15; \ - VMOVDQA X6, X14; \ - VPUNPCKHQDQ_X15_X13_X3; \ - VPUNPCKLQDQ_X7_X7_X15; \ - VPUNPCKHQDQ_X15_X6_X6; \ - VPUNPCKLQDQ_X14_X14_X15; \ - VPUNPCKHQDQ_X15_X7_X7; \ - -#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ - VPADDQ m0, v0, v0; \ - VPADDQ v2, v0, v0; \ - VPADDQ m1, v1, v1; \ - VPADDQ v3, v1, v1; \ - VPXOR v0, v6, v6; \ - VPXOR v1, v7, v7; \ - VPSHUFD $-79, v6, v6; \ - VPSHUFD $-79, v7, v7; \ - VPADDQ v6, v4, v4; \ - VPADDQ v7, v5, v5; \ - VPXOR v4, v2, v2; \ - VPXOR v5, v3, v3; \ - VPSHUFB c40, v2, v2; \ - VPSHUFB c40, v3, v3; \ - VPADDQ m2, v0, v0; \ - VPADDQ v2, v0, v0; \ - VPADDQ m3, v1, v1; \ - VPADDQ v3, v1, v1; \ - VPXOR v0, v6, v6; \ - VPXOR v1, v7, v7; \ - VPSHUFB c48, v6, v6; \ - VPSHUFB c48, v7, v7; \ - VPADDQ v6, v4, v4; \ - VPADDQ v7, v5, v5; \ - VPXOR v4, v2, v2; \ - VPXOR v5, v3, v3; \ - VPADDQ v2, v2, t0; \ - VPSRLQ $63, v2, v2; \ - VPXOR t0, v2, v2; \ - VPADDQ v3, v3, t0; \ - VPSRLQ $63, v3, v3; \ - VPXOR t0, v3, v3 - -// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7) -// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0 -#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \ - VMOVQ_SI_X12(i0*8); \ - VMOVQ_SI_X13(i2*8); \ - VMOVQ_SI_X14(i4*8); \ - VMOVQ_SI_X15(i6*8); \ - VPINSRQ_1_SI_X12(i1*8); \ - VPINSRQ_1_SI_X13(i3*8); \ - VPINSRQ_1_SI_X14(i5*8); \ - VPINSRQ_1_SI_X15(i7*8) - -// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7) -#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \ - VMOVQ_SI_X12_0; \ - VMOVQ_SI_X13(4*8); \ - VMOVQ_SI_X14(1*8); \ - VMOVQ_SI_X15(5*8); \ - VPINSRQ_1_SI_X12(2*8); \ - VPINSRQ_1_SI_X13(6*8); \ - VPINSRQ_1_SI_X14(3*8); \ - VPINSRQ_1_SI_X15(7*8) - -// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3) -#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \ - VPSHUFD $0x4E, 0*8(SI), X12; \ - VMOVQ_SI_X13(11*8); \ - VMOVQ_SI_X14(12*8); \ - VMOVQ_SI_X15(7*8); \ - VPINSRQ_1_SI_X13(5*8); \ - VPINSRQ_1_SI_X14(2*8); \ - VPINSRQ_1_SI_X15(3*8) - -// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13) -#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \ - VMOVDQU 11*8(SI), X12; \ - VMOVQ_SI_X13(5*8); \ - VMOVQ_SI_X14(8*8); \ - VMOVQ_SI_X15(2*8); \ - VPINSRQ_1_SI_X13(15*8); \ - VPINSRQ_1_SI_X14_0; \ - VPINSRQ_1_SI_X15(13*8) - -// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8) -#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \ - VMOVQ_SI_X12(2*8); \ - VMOVQ_SI_X13(4*8); \ - VMOVQ_SI_X14(6*8); \ - VMOVQ_SI_X15_0; \ - VPINSRQ_1_SI_X12(5*8); \ - VPINSRQ_1_SI_X13(15*8); \ - VPINSRQ_1_SI_X14(10*8); \ - VPINSRQ_1_SI_X15(8*8) +DATA ·AVX2_c40<>+0(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+8(SB)/8, $0x0a09080f0e0d0c0b +DATA ·AVX2_c40<>+16(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+24(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX2_c40<>(SB), RODATA|NOPTR, $32 -// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15) -#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \ - VMOVQ_SI_X12(9*8); \ - VMOVQ_SI_X13(2*8); \ - VMOVQ_SI_X14_0; \ - VMOVQ_SI_X15(4*8); \ - VPINSRQ_1_SI_X12(5*8); \ - VPINSRQ_1_SI_X13(10*8); \ - VPINSRQ_1_SI_X14(7*8); \ - VPINSRQ_1_SI_X15(15*8) +DATA ·AVX2_c48<>+0(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+8(SB)/8, $0x09080f0e0d0c0b0a +DATA ·AVX2_c48<>+16(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+24(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX2_c48<>(SB), RODATA|NOPTR, $32 -// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3) -#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \ - VMOVQ_SI_X12(2*8); \ - VMOVQ_SI_X13_0; \ - VMOVQ_SI_X14(12*8); \ - VMOVQ_SI_X15(11*8); \ - VPINSRQ_1_SI_X12(6*8); \ - VPINSRQ_1_SI_X13(8*8); \ - VPINSRQ_1_SI_X14(10*8); \ - VPINSRQ_1_SI_X15(3*8) +DATA ·AVX2_iv0<>+0(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX2_iv0<>+8(SB)/8, $0xbb67ae8584caa73b +DATA ·AVX2_iv0<>+16(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX2_iv0<>+24(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX2_iv0<>(SB), RODATA|NOPTR, $32 -// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11) -#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \ - MOVQ 0*8(SI), X12; \ - VPSHUFD $0x4E, 8*8(SI), X13; \ - MOVQ 7*8(SI), X14; \ - MOVQ 2*8(SI), X15; \ - VPINSRQ_1_SI_X12(6*8); \ - VPINSRQ_1_SI_X14(3*8); \ - VPINSRQ_1_SI_X15(11*8) - -// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8) -#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \ - MOVQ 6*8(SI), X12; \ - MOVQ 11*8(SI), X13; \ - MOVQ 15*8(SI), X14; \ - MOVQ 3*8(SI), X15; \ - VPINSRQ_1_SI_X12(14*8); \ - VPINSRQ_1_SI_X13_0; \ - VPINSRQ_1_SI_X14(9*8); \ - VPINSRQ_1_SI_X15(8*8) - -// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10) -#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \ - MOVQ 5*8(SI), X12; \ - MOVQ 8*8(SI), X13; \ - MOVQ 0*8(SI), X14; \ - MOVQ 6*8(SI), X15; \ - VPINSRQ_1_SI_X12(15*8); \ - VPINSRQ_1_SI_X13(2*8); \ - VPINSRQ_1_SI_X14(4*8); \ - VPINSRQ_1_SI_X15(10*8) - -// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5) -#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \ - VMOVDQU 12*8(SI), X12; \ - MOVQ 1*8(SI), X13; \ - MOVQ 2*8(SI), X14; \ - VPINSRQ_1_SI_X13(10*8); \ - VPINSRQ_1_SI_X14(7*8); \ - VMOVDQU 4*8(SI), X15 - -// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0) -#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \ - MOVQ 15*8(SI), X12; \ - MOVQ 3*8(SI), X13; \ - MOVQ 11*8(SI), X14; \ - MOVQ 12*8(SI), X15; \ - VPINSRQ_1_SI_X12(9*8); \ - VPINSRQ_1_SI_X13(13*8); \ - VPINSRQ_1_SI_X14(14*8); \ - VPINSRQ_1_SI_X15_0 +DATA ·AVX2_iv1<>+0(SB)/8, $0x510e527fade682d1 +DATA ·AVX2_iv1<>+8(SB)/8, $0x9b05688c2b3e6c1f +DATA ·AVX2_iv1<>+16(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX2_iv1<>+24(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX2_iv1<>(SB), RODATA|NOPTR, $32 // func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) -TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment - MOVQ h+0(FP), AX - MOVQ c+8(FP), BX - MOVQ flag+16(FP), CX - MOVQ blocks_base+24(FP), SI - MOVQ blocks_len+32(FP), DI - - MOVQ SP, R10 - ADDQ $15, R10 - ANDQ $~15, R10 - - VMOVDQU ·AVX_c40<>(SB), X0 - VMOVDQU ·AVX_c48<>(SB), X1 +// Requires: AVX, SSE2 +TEXT ·hashBlocksAVX(SB), NOSPLIT, $288-48 + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + MOVQ SP, R10 + ADDQ $0x0f, R10 + ANDQ $-16, R10 + VMOVDQU ·AVX_c40<>+0(SB), X0 + VMOVDQU ·AVX_c48<>+0(SB), X1 VMOVDQA X0, X8 VMOVDQA X1, X9 - - VMOVDQU ·AVX_iv3<>(SB), X0 - VMOVDQA X0, 0(R10) - XORQ CX, 0(R10) // 0(R10) = ·AVX_iv3 ^ (CX || 0) - - VMOVDQU 0(AX), X10 + VMOVDQU ·AVX_iv3<>+0(SB), X0 + VMOVDQA X0, (R10) + XORQ CX, (R10) + VMOVDQU (AX), X10 VMOVDQU 16(AX), X11 VMOVDQU 32(AX), X2 VMOVDQU 48(AX), X3 - - MOVQ 0(BX), R8 - MOVQ 8(BX), R9 + MOVQ (BX), R8 + MOVQ 8(BX), R9 loop: - ADDQ $128, R8 - CMPQ R8, $128 + ADDQ $0x80, R8 + CMPQ R8, $0x80 JGE noinc INCQ R9 noinc: - VMOVQ_R8_X15 - VPINSRQ_1_R9_X15 - + BYTE $0xc4 + BYTE $0x41 + BYTE $0xf9 + BYTE $0x6e + BYTE $0xf8 + BYTE $0xc4 + BYTE $0x43 + BYTE $0x81 + BYTE $0x22 + BYTE $0xf9 + BYTE $0x01 VMOVDQA X10, X0 VMOVDQA X11, X1 - VMOVDQU ·AVX_iv0<>(SB), X4 - VMOVDQU ·AVX_iv1<>(SB), X5 - VMOVDQU ·AVX_iv2<>(SB), X6 - + VMOVDQU ·AVX_iv0<>+0(SB), X4 + VMOVDQU ·AVX_iv1<>+0(SB), X5 + VMOVDQU ·AVX_iv2<>+0(SB), X6 VPXOR X15, X6, X6 - VMOVDQA 0(R10), X7 - - LOAD_MSG_AVX_0_2_4_6_1_3_5_7() + VMOVDQA (R10), X7 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x26 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x20 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x08 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x28 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x10 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x30 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x38 + BYTE $0x01 VMOVDQA X12, 16(R10) VMOVDQA X13, 32(R10) VMOVDQA X14, 48(R10) VMOVDQA X15, 64(R10) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15) + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x40 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x68 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x58 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x78 + BYTE $0x01 VMOVDQA X12, 80(R10) VMOVDQA X13, 96(R10) VMOVDQA X14, 112(R10) VMOVDQA X15, 128(R10) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6) + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x50 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x78 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x20 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x68 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x40 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x30 + BYTE $0x01 VMOVDQA X12, 144(R10) VMOVDQA X13, 160(R10) VMOVDQA X14, 176(R10) VMOVDQA X15, 192(R10) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX_1_0_11_5_12_2_7_3() + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + VPSHUFD $0x4e, (SI), X12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x58 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x38 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x10 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x18 + BYTE $0x01 VMOVDQA X12, 208(R10) VMOVDQA X13, 224(R10) VMOVDQA X14, 240(R10) VMOVDQA X15, 256(R10) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX_11_12_5_15_8_0_2_13() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX_2_5_4_15_6_10_0_8() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX_9_5_2_10_0_7_4_15() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX_2_6_0_8_12_10_11_3() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX_0_6_9_8_7_3_2_11() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX_5_15_8_2_0_4_6_10() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX_6_14_11_0_15_9_3_8() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX_12_13_1_10_2_7_4_5() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5) - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX() - LOAD_MSG_AVX_15_9_3_13_11_14_12_0() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) - SHUFFLE_AVX_INV() - - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(R10), 32(R10), 48(R10), 64(R10), X15, X8, X9) - SHUFFLE_AVX() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(R10), 96(R10), 112(R10), 128(R10), X15, X8, X9) - SHUFFLE_AVX_INV() - - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(R10), 160(R10), 176(R10), 192(R10), X15, X8, X9) - SHUFFLE_AVX() - HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(R10), 224(R10), 240(R10), 256(R10), X15, X8, X9) - SHUFFLE_AVX_INV() - + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + VMOVDQU 88(SI), X12 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x28 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x40 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x10 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x78 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x36 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x68 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x50 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x38 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x08 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x48 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x30 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x20 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x38 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x68 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x60 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x58 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x08 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x70 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x10 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x20 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x30 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x3e + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x78 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x40 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x48 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x10 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x36 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x20 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x38 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x78 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x30 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x08 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x40 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x58 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x60 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x68 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x10 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x2e + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x58 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x30 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x40 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x18 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x20 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x78 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x68 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x70 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x38 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x08 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x28 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x48 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x70 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x28 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x68 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x08 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x20 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x78 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x50 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + MOVQ (SI), X12 + VPSHUFD $0x4e, 64(SI), X13 + MOVQ 56(SI), X14 + MOVQ 16(SI), X15 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x30 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x58 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x68 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x60 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x58 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x08 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x38 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x18 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x48 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + MOVQ 40(SI), X12 + MOVQ 64(SI), X13 + MOVQ (SI), X14 + MOVQ 48(SI), X15 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x78 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x10 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x20 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x50 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + MOVQ 48(SI), X12 + MOVQ 88(SI), X13 + MOVQ 120(SI), X14 + MOVQ 24(SI), X15 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x2e + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x48 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x40 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + VMOVDQU 96(SI), X12 + MOVQ 8(SI), X13 + MOVQ 16(SI), X14 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x50 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x38 + BYTE $0x01 + VMOVDQU 32(SI), X15 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x66 + BYTE $0x50 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x6e + BYTE $0x38 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x76 + BYTE $0x10 + BYTE $0xc5 + BYTE $0x7a + BYTE $0x7e + BYTE $0x7e + BYTE $0x30 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x40 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x08 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x20 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x7e + BYTE $0x28 + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + MOVQ 120(SI), X12 + MOVQ 24(SI), X13 + MOVQ 88(SI), X14 + MOVQ 96(SI), X15 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x99 + BYTE $0x22 + BYTE $0x66 + BYTE $0x48 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x91 + BYTE $0x22 + BYTE $0x6e + BYTE $0x68 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x89 + BYTE $0x22 + BYTE $0x76 + BYTE $0x70 + BYTE $0x01 + BYTE $0xc4 + BYTE $0x63 + BYTE $0x81 + BYTE $0x22 + BYTE $0x3e + BYTE $0x01 + VPADDQ X12, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X13, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ X14, X0, X0 + VPADDQ X2, X0, X0 + VPADDQ X15, X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + VPADDQ 16(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 32(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ 48(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 64(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + VPADDQ 80(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 96(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ 112(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 128(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff + VPADDQ 144(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 160(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ 176(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 192(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X6, X13 + VMOVDQA X2, X14 + VMOVDQA X4, X6 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x11 + BYTE $0x6c + BYTE $0xfd + VMOVDQA X5, X4 + VMOVDQA X6, X5 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xff + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x69 + BYTE $0x6d + BYTE $0xd7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xdf + VPADDQ 208(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 224(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFD $-79, X6, X6 + VPSHUFD $-79, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPSHUFB X8, X2, X2 + VPSHUFB X8, X3, X3 + VPADDQ 240(R10), X0, X0 + VPADDQ X2, X0, X0 + VPADDQ 256(R10), X1, X1 + VPADDQ X3, X1, X1 + VPXOR X0, X6, X6 + VPXOR X1, X7, X7 + VPSHUFB X9, X6, X6 + VPSHUFB X9, X7, X7 + VPADDQ X6, X4, X4 + VPADDQ X7, X5, X5 + VPXOR X4, X2, X2 + VPXOR X5, X3, X3 + VPADDQ X2, X2, X15 + VPSRLQ $0x3f, X2, X2 + VPXOR X15, X2, X2 + VPADDQ X3, X3, X15 + VPSRLQ $0x3f, X3, X3 + VPXOR X15, X3, X3 + VMOVDQA X2, X13 + VMOVDQA X4, X14 + BYTE $0xc5 + BYTE $0x69 + BYTE $0x6c + BYTE $0xfa + VMOVDQA X5, X4 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x61 + BYTE $0x6d + BYTE $0xd7 + VMOVDQA X14, X5 + BYTE $0xc5 + BYTE $0x61 + BYTE $0x6c + BYTE $0xfb + VMOVDQA X6, X14 + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x11 + BYTE $0x6d + BYTE $0xdf + BYTE $0xc5 + BYTE $0x41 + BYTE $0x6c + BYTE $0xff + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x49 + BYTE $0x6d + BYTE $0xf7 + BYTE $0xc4 + BYTE $0x41 + BYTE $0x09 + BYTE $0x6c + BYTE $0xfe + BYTE $0xc4 + BYTE $0xc1 + BYTE $0x41 + BYTE $0x6d + BYTE $0xff VMOVDQU 32(AX), X14 VMOVDQU 48(AX), X15 VPXOR X0, X10, X10 @@ -729,16 +4524,36 @@ noinc: VPXOR X7, X15, X3 VMOVDQU X2, 32(AX) VMOVDQU X3, 48(AX) + LEAQ 128(SI), SI + SUBQ $0x80, DI + JNE loop + VMOVDQU X10, (AX) + VMOVDQU X11, 16(AX) + MOVQ R8, (BX) + MOVQ R9, 8(BX) + VZEROUPPER + RET - LEAQ 128(SI), SI - SUBQ $128, DI - JNE loop +DATA ·AVX_c40<>+0(SB)/8, $0x0201000706050403 +DATA ·AVX_c40<>+8(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX_c40<>(SB), RODATA|NOPTR, $16 - VMOVDQU X10, 0(AX) - VMOVDQU X11, 16(AX) +DATA ·AVX_c48<>+0(SB)/8, $0x0100070605040302 +DATA ·AVX_c48<>+8(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX_c48<>(SB), RODATA|NOPTR, $16 - MOVQ R8, 0(BX) - MOVQ R9, 8(BX) - VZEROUPPER +DATA ·AVX_iv3<>+0(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX_iv3<>+8(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX_iv3<>(SB), RODATA|NOPTR, $16 - RET +DATA ·AVX_iv0<>+0(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX_iv0<>+8(SB)/8, $0xbb67ae8584caa73b +GLOBL ·AVX_iv0<>(SB), RODATA|NOPTR, $16 + +DATA ·AVX_iv1<>+0(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX_iv1<>+8(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX_iv1<>(SB), RODATA|NOPTR, $16 + +DATA ·AVX_iv2<>+0(SB)/8, $0x510e527fade682d1 +DATA ·AVX_iv2<>+8(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·AVX_iv2<>(SB), RODATA|NOPTR, $16 diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s index adfac00c15..9a0ce21244 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s @@ -1,278 +1,1441 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. +// Code generated by command: go run blake2b_amd64_asm.go -out ../../blake2b_amd64.s -pkg blake2b. DO NOT EDIT. //go:build amd64 && gc && !purego #include "textflag.h" -DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 -DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b -GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16 - -DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b -DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 -GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16 - -DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1 -DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f -GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16 - -DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b -DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 -GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16 - -DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 -DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b -GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 - -DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 -DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a -GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 - -#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ - MOVO v4, t1; \ - MOVO v5, v4; \ - MOVO t1, v5; \ - MOVO v6, t1; \ - PUNPCKLQDQ v6, t2; \ - PUNPCKHQDQ v7, v6; \ - PUNPCKHQDQ t2, v6; \ - PUNPCKLQDQ v7, t2; \ - MOVO t1, v7; \ - MOVO v2, t1; \ - PUNPCKHQDQ t2, v7; \ - PUNPCKLQDQ v3, t2; \ - PUNPCKHQDQ t2, v2; \ - PUNPCKLQDQ t1, t2; \ - PUNPCKHQDQ t2, v3 - -#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ - MOVO v4, t1; \ - MOVO v5, v4; \ - MOVO t1, v5; \ - MOVO v2, t1; \ - PUNPCKLQDQ v2, t2; \ - PUNPCKHQDQ v3, v2; \ - PUNPCKHQDQ t2, v2; \ - PUNPCKLQDQ v3, t2; \ - MOVO t1, v3; \ - MOVO v6, t1; \ - PUNPCKHQDQ t2, v3; \ - PUNPCKLQDQ v7, t2; \ - PUNPCKHQDQ t2, v6; \ - PUNPCKLQDQ t1, t2; \ - PUNPCKHQDQ t2, v7 - -#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ - PADDQ m0, v0; \ - PADDQ m1, v1; \ - PADDQ v2, v0; \ - PADDQ v3, v1; \ - PXOR v0, v6; \ - PXOR v1, v7; \ - PSHUFD $0xB1, v6, v6; \ - PSHUFD $0xB1, v7, v7; \ - PADDQ v6, v4; \ - PADDQ v7, v5; \ - PXOR v4, v2; \ - PXOR v5, v3; \ - PSHUFB c40, v2; \ - PSHUFB c40, v3; \ - PADDQ m2, v0; \ - PADDQ m3, v1; \ - PADDQ v2, v0; \ - PADDQ v3, v1; \ - PXOR v0, v6; \ - PXOR v1, v7; \ - PSHUFB c48, v6; \ - PSHUFB c48, v7; \ - PADDQ v6, v4; \ - PADDQ v7, v5; \ - PXOR v4, v2; \ - PXOR v5, v3; \ - MOVOU v2, t0; \ - PADDQ v2, t0; \ - PSRLQ $63, v2; \ - PXOR t0, v2; \ - MOVOU v3, t0; \ - PADDQ v3, t0; \ - PSRLQ $63, v3; \ - PXOR t0, v3 - -#define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \ - MOVQ i0*8(src), m0; \ - PINSRQ $1, i1*8(src), m0; \ - MOVQ i2*8(src), m1; \ - PINSRQ $1, i3*8(src), m1; \ - MOVQ i4*8(src), m2; \ - PINSRQ $1, i5*8(src), m2; \ - MOVQ i6*8(src), m3; \ - PINSRQ $1, i7*8(src), m3 - // func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) -TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment - MOVQ h+0(FP), AX - MOVQ c+8(FP), BX - MOVQ flag+16(FP), CX - MOVQ blocks_base+24(FP), SI - MOVQ blocks_len+32(FP), DI - - MOVQ SP, R10 - ADDQ $15, R10 - ANDQ $~15, R10 - - MOVOU ·iv3<>(SB), X0 - MOVO X0, 0(R10) - XORQ CX, 0(R10) // 0(R10) = ·iv3 ^ (CX || 0) - - MOVOU ·c40<>(SB), X13 - MOVOU ·c48<>(SB), X14 - - MOVOU 0(AX), X12 +// Requires: SSE2, SSE4.1, SSSE3 +TEXT ·hashBlocksSSE4(SB), NOSPLIT, $288-48 + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + MOVQ SP, R10 + ADDQ $0x0f, R10 + ANDQ $-16, R10 + MOVOU ·iv3<>+0(SB), X0 + MOVO X0, (R10) + XORQ CX, (R10) + MOVOU ·c40<>+0(SB), X13 + MOVOU ·c48<>+0(SB), X14 + MOVOU (AX), X12 MOVOU 16(AX), X15 - - MOVQ 0(BX), R8 - MOVQ 8(BX), R9 + MOVQ (BX), R8 + MOVQ 8(BX), R9 loop: - ADDQ $128, R8 - CMPQ R8, $128 + ADDQ $0x80, R8 + CMPQ R8, $0x80 JGE noinc INCQ R9 noinc: - MOVQ R8, X8 - PINSRQ $1, R9, X8 - - MOVO X12, X0 - MOVO X15, X1 - MOVOU 32(AX), X2 - MOVOU 48(AX), X3 - MOVOU ·iv0<>(SB), X4 - MOVOU ·iv1<>(SB), X5 - MOVOU ·iv2<>(SB), X6 - - PXOR X8, X6 - MOVO 0(R10), X7 - - LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7) - MOVO X8, 16(R10) - MOVO X9, 32(R10) - MOVO X10, 48(R10) - MOVO X11, 64(R10) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15) - MOVO X8, 80(R10) - MOVO X9, 96(R10) - MOVO X10, 112(R10) - MOVO X11, 128(R10) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6) - MOVO X8, 144(R10) - MOVO X9, 160(R10) - MOVO X10, 176(R10) - MOVO X11, 192(R10) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3) - MOVO X8, 208(R10) - MOVO X9, 224(R10) - MOVO X10, 240(R10) - MOVO X11, 256(R10) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) - - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(R10), 32(R10), 48(R10), 64(R10), X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(R10), 96(R10), 112(R10), 128(R10), X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + MOVQ R8, X8 + PINSRQ $0x01, R9, X8 + MOVO X12, X0 + MOVO X15, X1 + MOVOU 32(AX), X2 + MOVOU 48(AX), X3 + MOVOU ·iv0<>+0(SB), X4 + MOVOU ·iv1<>+0(SB), X5 + MOVOU ·iv2<>+0(SB), X6 + PXOR X8, X6 + MOVO (R10), X7 + MOVQ (SI), X8 + PINSRQ $0x01, 16(SI), X8 + MOVQ 32(SI), X9 + PINSRQ $0x01, 48(SI), X9 + MOVQ 8(SI), X10 + PINSRQ $0x01, 24(SI), X10 + MOVQ 40(SI), X11 + PINSRQ $0x01, 56(SI), X11 + MOVO X8, 16(R10) + MOVO X9, 32(R10) + MOVO X10, 48(R10) + MOVO X11, 64(R10) + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 64(SI), X8 + PINSRQ $0x01, 80(SI), X8 + MOVQ 96(SI), X9 + PINSRQ $0x01, 112(SI), X9 + MOVQ 72(SI), X10 + PINSRQ $0x01, 88(SI), X10 + MOVQ 104(SI), X11 + PINSRQ $0x01, 120(SI), X11 + MOVO X8, 80(R10) + MOVO X9, 96(R10) + MOVO X10, 112(R10) + MOVO X11, 128(R10) + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 112(SI), X8 + PINSRQ $0x01, 32(SI), X8 + MOVQ 72(SI), X9 + PINSRQ $0x01, 104(SI), X9 + MOVQ 80(SI), X10 + PINSRQ $0x01, 64(SI), X10 + MOVQ 120(SI), X11 + PINSRQ $0x01, 48(SI), X11 + MOVO X8, 144(R10) + MOVO X9, 160(R10) + MOVO X10, 176(R10) + MOVO X11, 192(R10) + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 8(SI), X8 + PINSRQ $0x01, (SI), X8 + MOVQ 88(SI), X9 + PINSRQ $0x01, 40(SI), X9 + MOVQ 96(SI), X10 + PINSRQ $0x01, 16(SI), X10 + MOVQ 56(SI), X11 + PINSRQ $0x01, 24(SI), X11 + MOVO X8, 208(R10) + MOVO X9, 224(R10) + MOVO X10, 240(R10) + MOVO X11, 256(R10) + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 88(SI), X8 + PINSRQ $0x01, 96(SI), X8 + MOVQ 40(SI), X9 + PINSRQ $0x01, 120(SI), X9 + MOVQ 64(SI), X10 + PINSRQ $0x01, (SI), X10 + MOVQ 16(SI), X11 + PINSRQ $0x01, 104(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 80(SI), X8 + PINSRQ $0x01, 24(SI), X8 + MOVQ 56(SI), X9 + PINSRQ $0x01, 72(SI), X9 + MOVQ 112(SI), X10 + PINSRQ $0x01, 48(SI), X10 + MOVQ 8(SI), X11 + PINSRQ $0x01, 32(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 56(SI), X8 + PINSRQ $0x01, 24(SI), X8 + MOVQ 104(SI), X9 + PINSRQ $0x01, 88(SI), X9 + MOVQ 72(SI), X10 + PINSRQ $0x01, 8(SI), X10 + MOVQ 96(SI), X11 + PINSRQ $0x01, 112(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 16(SI), X8 + PINSRQ $0x01, 40(SI), X8 + MOVQ 32(SI), X9 + PINSRQ $0x01, 120(SI), X9 + MOVQ 48(SI), X10 + PINSRQ $0x01, 80(SI), X10 + MOVQ (SI), X11 + PINSRQ $0x01, 64(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 72(SI), X8 + PINSRQ $0x01, 40(SI), X8 + MOVQ 16(SI), X9 + PINSRQ $0x01, 80(SI), X9 + MOVQ (SI), X10 + PINSRQ $0x01, 56(SI), X10 + MOVQ 32(SI), X11 + PINSRQ $0x01, 120(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 112(SI), X8 + PINSRQ $0x01, 88(SI), X8 + MOVQ 48(SI), X9 + PINSRQ $0x01, 24(SI), X9 + MOVQ 8(SI), X10 + PINSRQ $0x01, 96(SI), X10 + MOVQ 64(SI), X11 + PINSRQ $0x01, 104(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 16(SI), X8 + PINSRQ $0x01, 48(SI), X8 + MOVQ (SI), X9 + PINSRQ $0x01, 64(SI), X9 + MOVQ 96(SI), X10 + PINSRQ $0x01, 80(SI), X10 + MOVQ 88(SI), X11 + PINSRQ $0x01, 24(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 32(SI), X8 + PINSRQ $0x01, 56(SI), X8 + MOVQ 120(SI), X9 + PINSRQ $0x01, 8(SI), X9 + MOVQ 104(SI), X10 + PINSRQ $0x01, 40(SI), X10 + MOVQ 112(SI), X11 + PINSRQ $0x01, 72(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 96(SI), X8 + PINSRQ $0x01, 8(SI), X8 + MOVQ 112(SI), X9 + PINSRQ $0x01, 32(SI), X9 + MOVQ 40(SI), X10 + PINSRQ $0x01, 120(SI), X10 + MOVQ 104(SI), X11 + PINSRQ $0x01, 80(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ (SI), X8 + PINSRQ $0x01, 48(SI), X8 + MOVQ 72(SI), X9 + PINSRQ $0x01, 64(SI), X9 + MOVQ 56(SI), X10 + PINSRQ $0x01, 24(SI), X10 + MOVQ 16(SI), X11 + PINSRQ $0x01, 88(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 104(SI), X8 + PINSRQ $0x01, 56(SI), X8 + MOVQ 96(SI), X9 + PINSRQ $0x01, 24(SI), X9 + MOVQ 88(SI), X10 + PINSRQ $0x01, 112(SI), X10 + MOVQ 8(SI), X11 + PINSRQ $0x01, 72(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 40(SI), X8 + PINSRQ $0x01, 120(SI), X8 + MOVQ 64(SI), X9 + PINSRQ $0x01, 16(SI), X9 + MOVQ (SI), X10 + PINSRQ $0x01, 32(SI), X10 + MOVQ 48(SI), X11 + PINSRQ $0x01, 80(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 48(SI), X8 + PINSRQ $0x01, 112(SI), X8 + MOVQ 88(SI), X9 + PINSRQ $0x01, (SI), X9 + MOVQ 120(SI), X10 + PINSRQ $0x01, 72(SI), X10 + MOVQ 24(SI), X11 + PINSRQ $0x01, 64(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 96(SI), X8 + PINSRQ $0x01, 104(SI), X8 + MOVQ 8(SI), X9 + PINSRQ $0x01, 80(SI), X9 + MOVQ 16(SI), X10 + PINSRQ $0x01, 56(SI), X10 + MOVQ 32(SI), X11 + PINSRQ $0x01, 40(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVQ 80(SI), X8 + PINSRQ $0x01, 64(SI), X8 + MOVQ 56(SI), X9 + PINSRQ $0x01, 8(SI), X9 + MOVQ 16(SI), X10 + PINSRQ $0x01, 32(SI), X10 + MOVQ 48(SI), X11 + PINSRQ $0x01, 40(SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + MOVQ 120(SI), X8 + PINSRQ $0x01, 72(SI), X8 + MOVQ 24(SI), X9 + PINSRQ $0x01, 104(SI), X9 + MOVQ 88(SI), X10 + PINSRQ $0x01, 112(SI), X10 + MOVQ 96(SI), X11 + PINSRQ $0x01, (SI), X11 + PADDQ X8, X0 + PADDQ X9, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ X10, X0 + PADDQ X11, X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + PADDQ 16(R10), X0 + PADDQ 32(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ 48(R10), X0 + PADDQ 64(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + PADDQ 80(R10), X0 + PADDQ 96(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ 112(R10), X0 + PADDQ 128(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + PADDQ 144(R10), X0 + PADDQ 160(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ 176(R10), X0 + PADDQ 192(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X6, X8 + PUNPCKLQDQ X6, X9 + PUNPCKHQDQ X7, X6 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X7, X9 + MOVO X8, X7 + MOVO X2, X8 + PUNPCKHQDQ X9, X7 + PUNPCKLQDQ X3, X9 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X3 + PADDQ 208(R10), X0 + PADDQ 224(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFD $0xb1, X6, X6 + PSHUFD $0xb1, X7, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + PSHUFB X13, X2 + PSHUFB X13, X3 + PADDQ 240(R10), X0 + PADDQ 256(R10), X1 + PADDQ X2, X0 + PADDQ X3, X1 + PXOR X0, X6 + PXOR X1, X7 + PSHUFB X14, X6 + PSHUFB X14, X7 + PADDQ X6, X4 + PADDQ X7, X5 + PXOR X4, X2 + PXOR X5, X3 + MOVOU X2, X11 + PADDQ X2, X11 + PSRLQ $0x3f, X2 + PXOR X11, X2 + MOVOU X3, X11 + PADDQ X3, X11 + PSRLQ $0x3f, X3 + PXOR X11, X3 + MOVO X4, X8 + MOVO X5, X4 + MOVO X8, X5 + MOVO X2, X8 + PUNPCKLQDQ X2, X9 + PUNPCKHQDQ X3, X2 + PUNPCKHQDQ X9, X2 + PUNPCKLQDQ X3, X9 + MOVO X8, X3 + MOVO X6, X8 + PUNPCKHQDQ X9, X3 + PUNPCKLQDQ X7, X9 + PUNPCKHQDQ X9, X6 + PUNPCKLQDQ X8, X9 + PUNPCKHQDQ X9, X7 + MOVOU 32(AX), X10 + MOVOU 48(AX), X11 + PXOR X0, X12 + PXOR X1, X15 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X15 + PXOR X6, X10 + PXOR X7, X11 + MOVOU X10, 32(AX) + MOVOU X11, 48(AX) + LEAQ 128(SI), SI + SUBQ $0x80, DI + JNE loop + MOVOU X12, (AX) + MOVOU X15, 16(AX) + MOVQ R8, (BX) + MOVQ R9, 8(BX) + RET - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(R10), 160(R10), 176(R10), 192(R10), X11, X13, X14) - SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) - HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(R10), 224(R10), 240(R10), 256(R10), X11, X13, X14) - SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) +DATA ·iv3<>+0(SB)/8, $0x1f83d9abfb41bd6b +DATA ·iv3<>+8(SB)/8, $0x5be0cd19137e2179 +GLOBL ·iv3<>(SB), RODATA|NOPTR, $16 - MOVOU 32(AX), X10 - MOVOU 48(AX), X11 - PXOR X0, X12 - PXOR X1, X15 - PXOR X2, X10 - PXOR X3, X11 - PXOR X4, X12 - PXOR X5, X15 - PXOR X6, X10 - PXOR X7, X11 - MOVOU X10, 32(AX) - MOVOU X11, 48(AX) +DATA ·c40<>+0(SB)/8, $0x0201000706050403 +DATA ·c40<>+8(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·c40<>(SB), RODATA|NOPTR, $16 - LEAQ 128(SI), SI - SUBQ $128, DI - JNE loop +DATA ·c48<>+0(SB)/8, $0x0100070605040302 +DATA ·c48<>+8(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·c48<>(SB), RODATA|NOPTR, $16 - MOVOU X12, 0(AX) - MOVOU X15, 16(AX) +DATA ·iv0<>+0(SB)/8, $0x6a09e667f3bcc908 +DATA ·iv0<>+8(SB)/8, $0xbb67ae8584caa73b +GLOBL ·iv0<>(SB), RODATA|NOPTR, $16 - MOVQ R8, 0(BX) - MOVQ R9, 8(BX) +DATA ·iv1<>+0(SB)/8, $0x3c6ef372fe94f82b +DATA ·iv1<>+8(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·iv1<>(SB), RODATA|NOPTR, $16 - RET +DATA ·iv2<>+0(SB)/8, $0x510e527fade682d1 +DATA ·iv2<>+8(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·iv2<>(SB), RODATA|NOPTR, $16 diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s index fe4b818a33..57d510fc08 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s @@ -1,432 +1,2173 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. +// Code generated by command: go run blake2s_amd64_asm.go -out ../blake2s_amd64.s -pkg blake2s. DO NOT EDIT. //go:build amd64 && gc && !purego #include "textflag.h" -DATA iv0<>+0x00(SB)/4, $0x6a09e667 -DATA iv0<>+0x04(SB)/4, $0xbb67ae85 -DATA iv0<>+0x08(SB)/4, $0x3c6ef372 -DATA iv0<>+0x0c(SB)/4, $0xa54ff53a -GLOBL iv0<>(SB), (NOPTR+RODATA), $16 - -DATA iv1<>+0x00(SB)/4, $0x510e527f -DATA iv1<>+0x04(SB)/4, $0x9b05688c -DATA iv1<>+0x08(SB)/4, $0x1f83d9ab -DATA iv1<>+0x0c(SB)/4, $0x5be0cd19 -GLOBL iv1<>(SB), (NOPTR+RODATA), $16 - -DATA rol16<>+0x00(SB)/8, $0x0504070601000302 -DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A -GLOBL rol16<>(SB), (NOPTR+RODATA), $16 - -DATA rol8<>+0x00(SB)/8, $0x0407060500030201 -DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09 -GLOBL rol8<>(SB), (NOPTR+RODATA), $16 - -DATA counter<>+0x00(SB)/8, $0x40 -DATA counter<>+0x08(SB)/8, $0x0 -GLOBL counter<>(SB), (NOPTR+RODATA), $16 - -#define ROTL_SSE2(n, t, v) \ - MOVO v, t; \ - PSLLL $n, t; \ - PSRLL $(32-n), v; \ - PXOR t, v - -#define ROTL_SSSE3(c, v) \ - PSHUFB c, v - -#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \ - PADDL m0, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSE2(16, t, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(20, t, v1); \ - PADDL m1, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSE2(24, t, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(25, t, v1); \ - PSHUFL $0x39, v1, v1; \ - PSHUFL $0x4E, v2, v2; \ - PSHUFL $0x93, v3, v3; \ - PADDL m2, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSE2(16, t, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(20, t, v1); \ - PADDL m3, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSE2(24, t, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(25, t, v1); \ - PSHUFL $0x39, v3, v3; \ - PSHUFL $0x4E, v2, v2; \ - PSHUFL $0x93, v1, v1 - -#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \ - PADDL m0, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSSE3(c16, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(20, t, v1); \ - PADDL m1, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSSE3(c8, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(25, t, v1); \ - PSHUFL $0x39, v1, v1; \ - PSHUFL $0x4E, v2, v2; \ - PSHUFL $0x93, v3, v3; \ - PADDL m2, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSSE3(c16, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(20, t, v1); \ - PADDL m3, v0; \ - PADDL v1, v0; \ - PXOR v0, v3; \ - ROTL_SSSE3(c8, v3); \ - PADDL v3, v2; \ - PXOR v2, v1; \ - ROTL_SSE2(25, t, v1); \ - PSHUFL $0x39, v3, v3; \ - PSHUFL $0x4E, v2, v2; \ - PSHUFL $0x93, v1, v1 - - -#define LOAD_MSG_SSE4(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) \ - MOVL i0*4(src), m0; \ - PINSRD $1, i1*4(src), m0; \ - PINSRD $2, i2*4(src), m0; \ - PINSRD $3, i3*4(src), m0; \ - MOVL i4*4(src), m1; \ - PINSRD $1, i5*4(src), m1; \ - PINSRD $2, i6*4(src), m1; \ - PINSRD $3, i7*4(src), m1; \ - MOVL i8*4(src), m2; \ - PINSRD $1, i9*4(src), m2; \ - PINSRD $2, i10*4(src), m2; \ - PINSRD $3, i11*4(src), m2; \ - MOVL i12*4(src), m3; \ - PINSRD $1, i13*4(src), m3; \ - PINSRD $2, i14*4(src), m3; \ - PINSRD $3, i15*4(src), m3 +// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) +// Requires: SSE2 +TEXT ·hashBlocksSSE2(SB), $672-48 + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVL flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DX + MOVQ SP, BP + ADDQ $0x0f, BP + ANDQ $-16, BP + MOVQ (BX), R9 + MOVQ R9, (BP) + MOVQ CX, 8(BP) + MOVOU (AX), X0 + MOVOU 16(AX), X1 + MOVOU iv0<>+0(SB), X2 + MOVOU iv1<>+0(SB), X3 + MOVOU counter<>+0(SB), X12 + MOVOU rol16<>+0(SB), X13 + MOVOU rol8<>+0(SB), X14 + MOVO (BP), X15 -#define PRECOMPUTE_MSG(dst, off, src, R8, R9, R10, R11, R12, R13, R14, R15) \ - MOVQ 0*4(src), R8; \ - MOVQ 2*4(src), R9; \ - MOVQ 4*4(src), R10; \ - MOVQ 6*4(src), R11; \ - MOVQ 8*4(src), R12; \ - MOVQ 10*4(src), R13; \ - MOVQ 12*4(src), R14; \ - MOVQ 14*4(src), R15; \ - \ - MOVL R8, 0*4+off+0(dst); \ - MOVL R8, 9*4+off+64(dst); \ - MOVL R8, 5*4+off+128(dst); \ - MOVL R8, 14*4+off+192(dst); \ - MOVL R8, 4*4+off+256(dst); \ - MOVL R8, 2*4+off+320(dst); \ - MOVL R8, 8*4+off+384(dst); \ - MOVL R8, 12*4+off+448(dst); \ - MOVL R8, 3*4+off+512(dst); \ - MOVL R8, 15*4+off+576(dst); \ - SHRQ $32, R8; \ - MOVL R8, 4*4+off+0(dst); \ - MOVL R8, 8*4+off+64(dst); \ - MOVL R8, 14*4+off+128(dst); \ - MOVL R8, 5*4+off+192(dst); \ - MOVL R8, 12*4+off+256(dst); \ - MOVL R8, 11*4+off+320(dst); \ - MOVL R8, 1*4+off+384(dst); \ - MOVL R8, 6*4+off+448(dst); \ - MOVL R8, 10*4+off+512(dst); \ - MOVL R8, 3*4+off+576(dst); \ - \ - MOVL R9, 1*4+off+0(dst); \ - MOVL R9, 13*4+off+64(dst); \ - MOVL R9, 6*4+off+128(dst); \ - MOVL R9, 8*4+off+192(dst); \ - MOVL R9, 2*4+off+256(dst); \ - MOVL R9, 0*4+off+320(dst); \ - MOVL R9, 14*4+off+384(dst); \ - MOVL R9, 11*4+off+448(dst); \ - MOVL R9, 12*4+off+512(dst); \ - MOVL R9, 4*4+off+576(dst); \ - SHRQ $32, R9; \ - MOVL R9, 5*4+off+0(dst); \ - MOVL R9, 15*4+off+64(dst); \ - MOVL R9, 9*4+off+128(dst); \ - MOVL R9, 1*4+off+192(dst); \ - MOVL R9, 11*4+off+256(dst); \ - MOVL R9, 7*4+off+320(dst); \ - MOVL R9, 13*4+off+384(dst); \ - MOVL R9, 3*4+off+448(dst); \ - MOVL R9, 6*4+off+512(dst); \ - MOVL R9, 10*4+off+576(dst); \ - \ - MOVL R10, 2*4+off+0(dst); \ - MOVL R10, 1*4+off+64(dst); \ - MOVL R10, 15*4+off+128(dst); \ - MOVL R10, 10*4+off+192(dst); \ - MOVL R10, 6*4+off+256(dst); \ - MOVL R10, 8*4+off+320(dst); \ - MOVL R10, 3*4+off+384(dst); \ - MOVL R10, 13*4+off+448(dst); \ - MOVL R10, 14*4+off+512(dst); \ - MOVL R10, 5*4+off+576(dst); \ - SHRQ $32, R10; \ - MOVL R10, 6*4+off+0(dst); \ - MOVL R10, 11*4+off+64(dst); \ - MOVL R10, 2*4+off+128(dst); \ - MOVL R10, 9*4+off+192(dst); \ - MOVL R10, 1*4+off+256(dst); \ - MOVL R10, 13*4+off+320(dst); \ - MOVL R10, 4*4+off+384(dst); \ - MOVL R10, 8*4+off+448(dst); \ - MOVL R10, 15*4+off+512(dst); \ - MOVL R10, 7*4+off+576(dst); \ - \ - MOVL R11, 3*4+off+0(dst); \ - MOVL R11, 7*4+off+64(dst); \ - MOVL R11, 13*4+off+128(dst); \ - MOVL R11, 12*4+off+192(dst); \ - MOVL R11, 10*4+off+256(dst); \ - MOVL R11, 1*4+off+320(dst); \ - MOVL R11, 9*4+off+384(dst); \ - MOVL R11, 14*4+off+448(dst); \ - MOVL R11, 0*4+off+512(dst); \ - MOVL R11, 6*4+off+576(dst); \ - SHRQ $32, R11; \ - MOVL R11, 7*4+off+0(dst); \ - MOVL R11, 14*4+off+64(dst); \ - MOVL R11, 10*4+off+128(dst); \ - MOVL R11, 0*4+off+192(dst); \ - MOVL R11, 5*4+off+256(dst); \ - MOVL R11, 9*4+off+320(dst); \ - MOVL R11, 12*4+off+384(dst); \ - MOVL R11, 1*4+off+448(dst); \ - MOVL R11, 13*4+off+512(dst); \ - MOVL R11, 2*4+off+576(dst); \ - \ - MOVL R12, 8*4+off+0(dst); \ - MOVL R12, 5*4+off+64(dst); \ - MOVL R12, 4*4+off+128(dst); \ - MOVL R12, 15*4+off+192(dst); \ - MOVL R12, 14*4+off+256(dst); \ - MOVL R12, 3*4+off+320(dst); \ - MOVL R12, 11*4+off+384(dst); \ - MOVL R12, 10*4+off+448(dst); \ - MOVL R12, 7*4+off+512(dst); \ - MOVL R12, 1*4+off+576(dst); \ - SHRQ $32, R12; \ - MOVL R12, 12*4+off+0(dst); \ - MOVL R12, 2*4+off+64(dst); \ - MOVL R12, 11*4+off+128(dst); \ - MOVL R12, 4*4+off+192(dst); \ - MOVL R12, 0*4+off+256(dst); \ - MOVL R12, 15*4+off+320(dst); \ - MOVL R12, 10*4+off+384(dst); \ - MOVL R12, 7*4+off+448(dst); \ - MOVL R12, 5*4+off+512(dst); \ - MOVL R12, 9*4+off+576(dst); \ - \ - MOVL R13, 9*4+off+0(dst); \ - MOVL R13, 4*4+off+64(dst); \ - MOVL R13, 8*4+off+128(dst); \ - MOVL R13, 13*4+off+192(dst); \ - MOVL R13, 3*4+off+256(dst); \ - MOVL R13, 5*4+off+320(dst); \ - MOVL R13, 7*4+off+384(dst); \ - MOVL R13, 15*4+off+448(dst); \ - MOVL R13, 11*4+off+512(dst); \ - MOVL R13, 0*4+off+576(dst); \ - SHRQ $32, R13; \ - MOVL R13, 13*4+off+0(dst); \ - MOVL R13, 10*4+off+64(dst); \ - MOVL R13, 0*4+off+128(dst); \ - MOVL R13, 3*4+off+192(dst); \ - MOVL R13, 9*4+off+256(dst); \ - MOVL R13, 6*4+off+320(dst); \ - MOVL R13, 15*4+off+384(dst); \ - MOVL R13, 4*4+off+448(dst); \ - MOVL R13, 2*4+off+512(dst); \ - MOVL R13, 12*4+off+576(dst); \ - \ - MOVL R14, 10*4+off+0(dst); \ - MOVL R14, 12*4+off+64(dst); \ - MOVL R14, 1*4+off+128(dst); \ - MOVL R14, 6*4+off+192(dst); \ - MOVL R14, 13*4+off+256(dst); \ - MOVL R14, 4*4+off+320(dst); \ - MOVL R14, 0*4+off+384(dst); \ - MOVL R14, 2*4+off+448(dst); \ - MOVL R14, 8*4+off+512(dst); \ - MOVL R14, 14*4+off+576(dst); \ - SHRQ $32, R14; \ - MOVL R14, 14*4+off+0(dst); \ - MOVL R14, 3*4+off+64(dst); \ - MOVL R14, 7*4+off+128(dst); \ - MOVL R14, 2*4+off+192(dst); \ - MOVL R14, 15*4+off+256(dst); \ - MOVL R14, 12*4+off+320(dst); \ - MOVL R14, 6*4+off+384(dst); \ - MOVL R14, 0*4+off+448(dst); \ - MOVL R14, 9*4+off+512(dst); \ - MOVL R14, 11*4+off+576(dst); \ - \ - MOVL R15, 11*4+off+0(dst); \ - MOVL R15, 0*4+off+64(dst); \ - MOVL R15, 12*4+off+128(dst); \ - MOVL R15, 7*4+off+192(dst); \ - MOVL R15, 8*4+off+256(dst); \ - MOVL R15, 14*4+off+320(dst); \ - MOVL R15, 2*4+off+384(dst); \ - MOVL R15, 5*4+off+448(dst); \ - MOVL R15, 1*4+off+512(dst); \ - MOVL R15, 13*4+off+576(dst); \ - SHRQ $32, R15; \ - MOVL R15, 15*4+off+0(dst); \ - MOVL R15, 6*4+off+64(dst); \ - MOVL R15, 3*4+off+128(dst); \ - MOVL R15, 11*4+off+192(dst); \ - MOVL R15, 7*4+off+256(dst); \ - MOVL R15, 10*4+off+320(dst); \ - MOVL R15, 5*4+off+384(dst); \ - MOVL R15, 9*4+off+448(dst); \ - MOVL R15, 4*4+off+512(dst); \ - MOVL R15, 8*4+off+576(dst) +loop: + MOVO X0, X4 + MOVO X1, X5 + MOVO X2, X6 + MOVO X3, X7 + PADDQ X12, X15 + PXOR X15, X7 + MOVQ (SI), R8 + MOVQ 8(SI), R9 + MOVQ 16(SI), R10 + MOVQ 24(SI), R11 + MOVQ 32(SI), R12 + MOVQ 40(SI), R13 + MOVQ 48(SI), R14 + MOVQ 56(SI), R15 + MOVL R8, 16(BP) + MOVL R8, 116(BP) + MOVL R8, 164(BP) + MOVL R8, 264(BP) + MOVL R8, 288(BP) + MOVL R8, 344(BP) + MOVL R8, 432(BP) + MOVL R8, 512(BP) + MOVL R8, 540(BP) + MOVL R8, 652(BP) + SHRQ $0x20, R8 + MOVL R8, 32(BP) + MOVL R8, 112(BP) + MOVL R8, 200(BP) + MOVL R8, 228(BP) + MOVL R8, 320(BP) + MOVL R8, 380(BP) + MOVL R8, 404(BP) + MOVL R8, 488(BP) + MOVL R8, 568(BP) + MOVL R8, 604(BP) + MOVL R9, 20(BP) + MOVL R9, 132(BP) + MOVL R9, 168(BP) + MOVL R9, 240(BP) + MOVL R9, 280(BP) + MOVL R9, 336(BP) + MOVL R9, 456(BP) + MOVL R9, 508(BP) + MOVL R9, 576(BP) + MOVL R9, 608(BP) + SHRQ $0x20, R9 + MOVL R9, 36(BP) + MOVL R9, 140(BP) + MOVL R9, 180(BP) + MOVL R9, 212(BP) + MOVL R9, 316(BP) + MOVL R9, 364(BP) + MOVL R9, 452(BP) + MOVL R9, 476(BP) + MOVL R9, 552(BP) + MOVL R9, 632(BP) + MOVL R10, 24(BP) + MOVL R10, 84(BP) + MOVL R10, 204(BP) + MOVL R10, 248(BP) + MOVL R10, 296(BP) + MOVL R10, 368(BP) + MOVL R10, 412(BP) + MOVL R10, 516(BP) + MOVL R10, 584(BP) + MOVL R10, 612(BP) + SHRQ $0x20, R10 + MOVL R10, 40(BP) + MOVL R10, 124(BP) + MOVL R10, 152(BP) + MOVL R10, 244(BP) + MOVL R10, 276(BP) + MOVL R10, 388(BP) + MOVL R10, 416(BP) + MOVL R10, 496(BP) + MOVL R10, 588(BP) + MOVL R10, 620(BP) + MOVL R11, 28(BP) + MOVL R11, 108(BP) + MOVL R11, 196(BP) + MOVL R11, 256(BP) + MOVL R11, 312(BP) + MOVL R11, 340(BP) + MOVL R11, 436(BP) + MOVL R11, 520(BP) + MOVL R11, 528(BP) + MOVL R11, 616(BP) + SHRQ $0x20, R11 + MOVL R11, 44(BP) + MOVL R11, 136(BP) + MOVL R11, 184(BP) + MOVL R11, 208(BP) + MOVL R11, 292(BP) + MOVL R11, 372(BP) + MOVL R11, 448(BP) + MOVL R11, 468(BP) + MOVL R11, 580(BP) + MOVL R11, 600(BP) + MOVL R12, 48(BP) + MOVL R12, 100(BP) + MOVL R12, 160(BP) + MOVL R12, 268(BP) + MOVL R12, 328(BP) + MOVL R12, 348(BP) + MOVL R12, 444(BP) + MOVL R12, 504(BP) + MOVL R12, 556(BP) + MOVL R12, 596(BP) + SHRQ $0x20, R12 + MOVL R12, 64(BP) + MOVL R12, 88(BP) + MOVL R12, 188(BP) + MOVL R12, 224(BP) + MOVL R12, 272(BP) + MOVL R12, 396(BP) + MOVL R12, 440(BP) + MOVL R12, 492(BP) + MOVL R12, 548(BP) + MOVL R12, 628(BP) + MOVL R13, 52(BP) + MOVL R13, 96(BP) + MOVL R13, 176(BP) + MOVL R13, 260(BP) + MOVL R13, 284(BP) + MOVL R13, 356(BP) + MOVL R13, 428(BP) + MOVL R13, 524(BP) + MOVL R13, 572(BP) + MOVL R13, 592(BP) + SHRQ $0x20, R13 + MOVL R13, 68(BP) + MOVL R13, 120(BP) + MOVL R13, 144(BP) + MOVL R13, 220(BP) + MOVL R13, 308(BP) + MOVL R13, 360(BP) + MOVL R13, 460(BP) + MOVL R13, 480(BP) + MOVL R13, 536(BP) + MOVL R13, 640(BP) + MOVL R14, 56(BP) + MOVL R14, 128(BP) + MOVL R14, 148(BP) + MOVL R14, 232(BP) + MOVL R14, 324(BP) + MOVL R14, 352(BP) + MOVL R14, 400(BP) + MOVL R14, 472(BP) + MOVL R14, 560(BP) + MOVL R14, 648(BP) + SHRQ $0x20, R14 + MOVL R14, 72(BP) + MOVL R14, 92(BP) + MOVL R14, 172(BP) + MOVL R14, 216(BP) + MOVL R14, 332(BP) + MOVL R14, 384(BP) + MOVL R14, 424(BP) + MOVL R14, 464(BP) + MOVL R14, 564(BP) + MOVL R14, 636(BP) + MOVL R15, 60(BP) + MOVL R15, 80(BP) + MOVL R15, 192(BP) + MOVL R15, 236(BP) + MOVL R15, 304(BP) + MOVL R15, 392(BP) + MOVL R15, 408(BP) + MOVL R15, 484(BP) + MOVL R15, 532(BP) + MOVL R15, 644(BP) + SHRQ $0x20, R15 + MOVL R15, 76(BP) + MOVL R15, 104(BP) + MOVL R15, 156(BP) + MOVL R15, 252(BP) + MOVL R15, 300(BP) + MOVL R15, 376(BP) + MOVL R15, 420(BP) + MOVL R15, 500(BP) + MOVL R15, 544(BP) + MOVL R15, 624(BP) + PADDL 16(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 32(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 48(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 64(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 80(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 96(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 112(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 128(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 144(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 160(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 176(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 192(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 208(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 224(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 240(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 256(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 272(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 288(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 304(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 320(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 336(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 352(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 368(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 384(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 400(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 416(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 432(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 448(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 464(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 480(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 496(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 512(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 528(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 544(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 560(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 576(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 592(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 608(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 624(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x10, X8 + PSRLL $0x10, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 640(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + MOVO X7, X8 + PSLLL $0x18, X8 + PSRLL $0x08, X7 + PXOR X8, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PXOR X4, X0 + PXOR X5, X1 + PXOR X6, X0 + PXOR X7, X1 + LEAQ 64(SI), SI + SUBQ $0x40, DX + JNE loop + MOVO X15, (BP) + MOVQ (BP), R9 + MOVQ R9, (BX) + MOVOU X0, (AX) + MOVOU X1, 16(AX) + RET -#define BLAKE2s_SSE2() \ - PRECOMPUTE_MSG(BP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15); \ - ROUND_SSE2(X4, X5, X6, X7, 16(BP), 32(BP), 48(BP), 64(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+64(BP), 32+64(BP), 48+64(BP), 64+64(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+128(BP), 32+128(BP), 48+128(BP), 64+128(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+192(BP), 32+192(BP), 48+192(BP), 64+192(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+256(BP), 32+256(BP), 48+256(BP), 64+256(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+320(BP), 32+320(BP), 48+320(BP), 64+320(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+384(BP), 32+384(BP), 48+384(BP), 64+384(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+448(BP), 32+448(BP), 48+448(BP), 64+448(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+512(BP), 32+512(BP), 48+512(BP), 64+512(BP), X8); \ - ROUND_SSE2(X4, X5, X6, X7, 16+576(BP), 32+576(BP), 48+576(BP), 64+576(BP), X8) +DATA iv0<>+0(SB)/4, $0x6a09e667 +DATA iv0<>+4(SB)/4, $0xbb67ae85 +DATA iv0<>+8(SB)/4, $0x3c6ef372 +DATA iv0<>+12(SB)/4, $0xa54ff53a +GLOBL iv0<>(SB), RODATA|NOPTR, $16 -#define BLAKE2s_SSSE3() \ - PRECOMPUTE_MSG(BP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15); \ - ROUND_SSSE3(X4, X5, X6, X7, 16(BP), 32(BP), 48(BP), 64(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+64(BP), 32+64(BP), 48+64(BP), 64+64(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+128(BP), 32+128(BP), 48+128(BP), 64+128(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+192(BP), 32+192(BP), 48+192(BP), 64+192(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+256(BP), 32+256(BP), 48+256(BP), 64+256(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+320(BP), 32+320(BP), 48+320(BP), 64+320(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+384(BP), 32+384(BP), 48+384(BP), 64+384(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+448(BP), 32+448(BP), 48+448(BP), 64+448(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+512(BP), 32+512(BP), 48+512(BP), 64+512(BP), X8, X13, X14); \ - ROUND_SSSE3(X4, X5, X6, X7, 16+576(BP), 32+576(BP), 48+576(BP), 64+576(BP), X8, X13, X14) +DATA iv1<>+0(SB)/4, $0x510e527f +DATA iv1<>+4(SB)/4, $0x9b05688c +DATA iv1<>+8(SB)/4, $0x1f83d9ab +DATA iv1<>+12(SB)/4, $0x5be0cd19 +GLOBL iv1<>(SB), RODATA|NOPTR, $16 -#define BLAKE2s_SSE4() \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \ - LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0); \ - ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14) +DATA counter<>+0(SB)/8, $0x0000000000000040 +DATA counter<>+8(SB)/8, $0x0000000000000000 +GLOBL counter<>(SB), RODATA|NOPTR, $16 -#define HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_FUNC) \ - MOVQ h, AX; \ - MOVQ c, BX; \ - MOVL flag, CX; \ - MOVQ blocks_base, SI; \ - MOVQ blocks_len, DX; \ - \ - MOVQ SP, BP; \ - ADDQ $15, BP; \ - ANDQ $~15, BP; \ - \ - MOVQ 0(BX), R9; \ - MOVQ R9, 0(BP); \ - MOVQ CX, 8(BP); \ - \ - MOVOU 0(AX), X0; \ - MOVOU 16(AX), X1; \ - MOVOU iv0<>(SB), X2; \ - MOVOU iv1<>(SB), X3 \ - \ - MOVOU counter<>(SB), X12; \ - MOVOU rol16<>(SB), X13; \ - MOVOU rol8<>(SB), X14; \ - MOVO 0(BP), X15; \ - \ - loop: \ - MOVO X0, X4; \ - MOVO X1, X5; \ - MOVO X2, X6; \ - MOVO X3, X7; \ - \ - PADDQ X12, X15; \ - PXOR X15, X7; \ - \ - BLAKE2s_FUNC(); \ - \ - PXOR X4, X0; \ - PXOR X5, X1; \ - PXOR X6, X0; \ - PXOR X7, X1; \ - \ - LEAQ 64(SI), SI; \ - SUBQ $64, DX; \ - JNE loop; \ - \ - MOVO X15, 0(BP); \ - MOVQ 0(BP), R9; \ - MOVQ R9, 0(BX); \ - \ - MOVOU X0, 0(AX); \ - MOVOU X1, 16(AX) +DATA rol16<>+0(SB)/8, $0x0504070601000302 +DATA rol16<>+8(SB)/8, $0x0d0c0f0e09080b0a +GLOBL rol16<>(SB), RODATA|NOPTR, $16 -// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) -TEXT ·hashBlocksSSE2(SB), 0, $672-48 // frame = 656 + 16 byte alignment - HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE2) - RET +DATA rol8<>+0(SB)/8, $0x0407060500030201 +DATA rol8<>+8(SB)/8, $0x0c0f0e0d080b0a09 +GLOBL rol8<>(SB), RODATA|NOPTR, $16 // func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) -TEXT ·hashBlocksSSSE3(SB), 0, $672-48 // frame = 656 + 16 byte alignment - HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSSE3) +// Requires: SSE2, SSSE3 +TEXT ·hashBlocksSSSE3(SB), $672-48 + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVL flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DX + MOVQ SP, BP + ADDQ $0x0f, BP + ANDQ $-16, BP + MOVQ (BX), R9 + MOVQ R9, (BP) + MOVQ CX, 8(BP) + MOVOU (AX), X0 + MOVOU 16(AX), X1 + MOVOU iv0<>+0(SB), X2 + MOVOU iv1<>+0(SB), X3 + MOVOU counter<>+0(SB), X12 + MOVOU rol16<>+0(SB), X13 + MOVOU rol8<>+0(SB), X14 + MOVO (BP), X15 + +loop: + MOVO X0, X4 + MOVO X1, X5 + MOVO X2, X6 + MOVO X3, X7 + PADDQ X12, X15 + PXOR X15, X7 + MOVQ (SI), R8 + MOVQ 8(SI), R9 + MOVQ 16(SI), R10 + MOVQ 24(SI), R11 + MOVQ 32(SI), R12 + MOVQ 40(SI), R13 + MOVQ 48(SI), R14 + MOVQ 56(SI), R15 + MOVL R8, 16(BP) + MOVL R8, 116(BP) + MOVL R8, 164(BP) + MOVL R8, 264(BP) + MOVL R8, 288(BP) + MOVL R8, 344(BP) + MOVL R8, 432(BP) + MOVL R8, 512(BP) + MOVL R8, 540(BP) + MOVL R8, 652(BP) + SHRQ $0x20, R8 + MOVL R8, 32(BP) + MOVL R8, 112(BP) + MOVL R8, 200(BP) + MOVL R8, 228(BP) + MOVL R8, 320(BP) + MOVL R8, 380(BP) + MOVL R8, 404(BP) + MOVL R8, 488(BP) + MOVL R8, 568(BP) + MOVL R8, 604(BP) + MOVL R9, 20(BP) + MOVL R9, 132(BP) + MOVL R9, 168(BP) + MOVL R9, 240(BP) + MOVL R9, 280(BP) + MOVL R9, 336(BP) + MOVL R9, 456(BP) + MOVL R9, 508(BP) + MOVL R9, 576(BP) + MOVL R9, 608(BP) + SHRQ $0x20, R9 + MOVL R9, 36(BP) + MOVL R9, 140(BP) + MOVL R9, 180(BP) + MOVL R9, 212(BP) + MOVL R9, 316(BP) + MOVL R9, 364(BP) + MOVL R9, 452(BP) + MOVL R9, 476(BP) + MOVL R9, 552(BP) + MOVL R9, 632(BP) + MOVL R10, 24(BP) + MOVL R10, 84(BP) + MOVL R10, 204(BP) + MOVL R10, 248(BP) + MOVL R10, 296(BP) + MOVL R10, 368(BP) + MOVL R10, 412(BP) + MOVL R10, 516(BP) + MOVL R10, 584(BP) + MOVL R10, 612(BP) + SHRQ $0x20, R10 + MOVL R10, 40(BP) + MOVL R10, 124(BP) + MOVL R10, 152(BP) + MOVL R10, 244(BP) + MOVL R10, 276(BP) + MOVL R10, 388(BP) + MOVL R10, 416(BP) + MOVL R10, 496(BP) + MOVL R10, 588(BP) + MOVL R10, 620(BP) + MOVL R11, 28(BP) + MOVL R11, 108(BP) + MOVL R11, 196(BP) + MOVL R11, 256(BP) + MOVL R11, 312(BP) + MOVL R11, 340(BP) + MOVL R11, 436(BP) + MOVL R11, 520(BP) + MOVL R11, 528(BP) + MOVL R11, 616(BP) + SHRQ $0x20, R11 + MOVL R11, 44(BP) + MOVL R11, 136(BP) + MOVL R11, 184(BP) + MOVL R11, 208(BP) + MOVL R11, 292(BP) + MOVL R11, 372(BP) + MOVL R11, 448(BP) + MOVL R11, 468(BP) + MOVL R11, 580(BP) + MOVL R11, 600(BP) + MOVL R12, 48(BP) + MOVL R12, 100(BP) + MOVL R12, 160(BP) + MOVL R12, 268(BP) + MOVL R12, 328(BP) + MOVL R12, 348(BP) + MOVL R12, 444(BP) + MOVL R12, 504(BP) + MOVL R12, 556(BP) + MOVL R12, 596(BP) + SHRQ $0x20, R12 + MOVL R12, 64(BP) + MOVL R12, 88(BP) + MOVL R12, 188(BP) + MOVL R12, 224(BP) + MOVL R12, 272(BP) + MOVL R12, 396(BP) + MOVL R12, 440(BP) + MOVL R12, 492(BP) + MOVL R12, 548(BP) + MOVL R12, 628(BP) + MOVL R13, 52(BP) + MOVL R13, 96(BP) + MOVL R13, 176(BP) + MOVL R13, 260(BP) + MOVL R13, 284(BP) + MOVL R13, 356(BP) + MOVL R13, 428(BP) + MOVL R13, 524(BP) + MOVL R13, 572(BP) + MOVL R13, 592(BP) + SHRQ $0x20, R13 + MOVL R13, 68(BP) + MOVL R13, 120(BP) + MOVL R13, 144(BP) + MOVL R13, 220(BP) + MOVL R13, 308(BP) + MOVL R13, 360(BP) + MOVL R13, 460(BP) + MOVL R13, 480(BP) + MOVL R13, 536(BP) + MOVL R13, 640(BP) + MOVL R14, 56(BP) + MOVL R14, 128(BP) + MOVL R14, 148(BP) + MOVL R14, 232(BP) + MOVL R14, 324(BP) + MOVL R14, 352(BP) + MOVL R14, 400(BP) + MOVL R14, 472(BP) + MOVL R14, 560(BP) + MOVL R14, 648(BP) + SHRQ $0x20, R14 + MOVL R14, 72(BP) + MOVL R14, 92(BP) + MOVL R14, 172(BP) + MOVL R14, 216(BP) + MOVL R14, 332(BP) + MOVL R14, 384(BP) + MOVL R14, 424(BP) + MOVL R14, 464(BP) + MOVL R14, 564(BP) + MOVL R14, 636(BP) + MOVL R15, 60(BP) + MOVL R15, 80(BP) + MOVL R15, 192(BP) + MOVL R15, 236(BP) + MOVL R15, 304(BP) + MOVL R15, 392(BP) + MOVL R15, 408(BP) + MOVL R15, 484(BP) + MOVL R15, 532(BP) + MOVL R15, 644(BP) + SHRQ $0x20, R15 + MOVL R15, 76(BP) + MOVL R15, 104(BP) + MOVL R15, 156(BP) + MOVL R15, 252(BP) + MOVL R15, 300(BP) + MOVL R15, 376(BP) + MOVL R15, 420(BP) + MOVL R15, 500(BP) + MOVL R15, 544(BP) + MOVL R15, 624(BP) + PADDL 16(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 32(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 48(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 64(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 80(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 96(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 112(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 128(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 144(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 160(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 176(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 192(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 208(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 224(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 240(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 256(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 272(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 288(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 304(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 320(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 336(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 352(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 368(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 384(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 400(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 416(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 432(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 448(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 464(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 480(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 496(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 512(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 528(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 544(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 560(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 576(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PADDL 592(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 608(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL 624(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL 640(BP), X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PXOR X4, X0 + PXOR X5, X1 + PXOR X6, X0 + PXOR X7, X1 + LEAQ 64(SI), SI + SUBQ $0x40, DX + JNE loop + MOVO X15, (BP) + MOVQ (BP), R9 + MOVQ R9, (BX) + MOVOU X0, (AX) + MOVOU X1, 16(AX) RET // func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) -TEXT ·hashBlocksSSE4(SB), 0, $32-48 // frame = 16 + 16 byte alignment - HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE4) +// Requires: SSE2, SSE4.1, SSSE3 +TEXT ·hashBlocksSSE4(SB), $32-48 + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVL flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DX + MOVQ SP, BP + ADDQ $0x0f, BP + ANDQ $-16, BP + MOVQ (BX), R9 + MOVQ R9, (BP) + MOVQ CX, 8(BP) + MOVOU (AX), X0 + MOVOU 16(AX), X1 + MOVOU iv0<>+0(SB), X2 + MOVOU iv1<>+0(SB), X3 + MOVOU counter<>+0(SB), X12 + MOVOU rol16<>+0(SB), X13 + MOVOU rol8<>+0(SB), X14 + MOVO (BP), X15 + +loop: + MOVO X0, X4 + MOVO X1, X5 + MOVO X2, X6 + MOVO X3, X7 + PADDQ X12, X15 + PXOR X15, X7 + MOVL (SI), X8 + PINSRD $0x01, 8(SI), X8 + PINSRD $0x02, 16(SI), X8 + PINSRD $0x03, 24(SI), X8 + MOVL 4(SI), X9 + PINSRD $0x01, 12(SI), X9 + PINSRD $0x02, 20(SI), X9 + PINSRD $0x03, 28(SI), X9 + MOVL 32(SI), X10 + PINSRD $0x01, 40(SI), X10 + PINSRD $0x02, 48(SI), X10 + PINSRD $0x03, 56(SI), X10 + MOVL 36(SI), X11 + PINSRD $0x01, 44(SI), X11 + PINSRD $0x02, 52(SI), X11 + PINSRD $0x03, 60(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 56(SI), X8 + PINSRD $0x01, 16(SI), X8 + PINSRD $0x02, 36(SI), X8 + PINSRD $0x03, 52(SI), X8 + MOVL 40(SI), X9 + PINSRD $0x01, 32(SI), X9 + PINSRD $0x02, 60(SI), X9 + PINSRD $0x03, 24(SI), X9 + MOVL 4(SI), X10 + PINSRD $0x01, (SI), X10 + PINSRD $0x02, 44(SI), X10 + PINSRD $0x03, 20(SI), X10 + MOVL 48(SI), X11 + PINSRD $0x01, 8(SI), X11 + PINSRD $0x02, 28(SI), X11 + PINSRD $0x03, 12(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 44(SI), X8 + PINSRD $0x01, 48(SI), X8 + PINSRD $0x02, 20(SI), X8 + PINSRD $0x03, 60(SI), X8 + MOVL 32(SI), X9 + PINSRD $0x01, (SI), X9 + PINSRD $0x02, 8(SI), X9 + PINSRD $0x03, 52(SI), X9 + MOVL 40(SI), X10 + PINSRD $0x01, 12(SI), X10 + PINSRD $0x02, 28(SI), X10 + PINSRD $0x03, 36(SI), X10 + MOVL 56(SI), X11 + PINSRD $0x01, 24(SI), X11 + PINSRD $0x02, 4(SI), X11 + PINSRD $0x03, 16(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 28(SI), X8 + PINSRD $0x01, 12(SI), X8 + PINSRD $0x02, 52(SI), X8 + PINSRD $0x03, 44(SI), X8 + MOVL 36(SI), X9 + PINSRD $0x01, 4(SI), X9 + PINSRD $0x02, 48(SI), X9 + PINSRD $0x03, 56(SI), X9 + MOVL 8(SI), X10 + PINSRD $0x01, 20(SI), X10 + PINSRD $0x02, 16(SI), X10 + PINSRD $0x03, 60(SI), X10 + MOVL 24(SI), X11 + PINSRD $0x01, 40(SI), X11 + PINSRD $0x02, (SI), X11 + PINSRD $0x03, 32(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 36(SI), X8 + PINSRD $0x01, 20(SI), X8 + PINSRD $0x02, 8(SI), X8 + PINSRD $0x03, 40(SI), X8 + MOVL (SI), X9 + PINSRD $0x01, 28(SI), X9 + PINSRD $0x02, 16(SI), X9 + PINSRD $0x03, 60(SI), X9 + MOVL 56(SI), X10 + PINSRD $0x01, 44(SI), X10 + PINSRD $0x02, 24(SI), X10 + PINSRD $0x03, 12(SI), X10 + MOVL 4(SI), X11 + PINSRD $0x01, 48(SI), X11 + PINSRD $0x02, 32(SI), X11 + PINSRD $0x03, 52(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 8(SI), X8 + PINSRD $0x01, 24(SI), X8 + PINSRD $0x02, (SI), X8 + PINSRD $0x03, 32(SI), X8 + MOVL 48(SI), X9 + PINSRD $0x01, 40(SI), X9 + PINSRD $0x02, 44(SI), X9 + PINSRD $0x03, 12(SI), X9 + MOVL 16(SI), X10 + PINSRD $0x01, 28(SI), X10 + PINSRD $0x02, 60(SI), X10 + PINSRD $0x03, 4(SI), X10 + MOVL 52(SI), X11 + PINSRD $0x01, 20(SI), X11 + PINSRD $0x02, 56(SI), X11 + PINSRD $0x03, 36(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 48(SI), X8 + PINSRD $0x01, 4(SI), X8 + PINSRD $0x02, 56(SI), X8 + PINSRD $0x03, 16(SI), X8 + MOVL 20(SI), X9 + PINSRD $0x01, 60(SI), X9 + PINSRD $0x02, 52(SI), X9 + PINSRD $0x03, 40(SI), X9 + MOVL (SI), X10 + PINSRD $0x01, 24(SI), X10 + PINSRD $0x02, 36(SI), X10 + PINSRD $0x03, 32(SI), X10 + MOVL 28(SI), X11 + PINSRD $0x01, 12(SI), X11 + PINSRD $0x02, 8(SI), X11 + PINSRD $0x03, 44(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 52(SI), X8 + PINSRD $0x01, 28(SI), X8 + PINSRD $0x02, 48(SI), X8 + PINSRD $0x03, 12(SI), X8 + MOVL 44(SI), X9 + PINSRD $0x01, 56(SI), X9 + PINSRD $0x02, 4(SI), X9 + PINSRD $0x03, 36(SI), X9 + MOVL 20(SI), X10 + PINSRD $0x01, 60(SI), X10 + PINSRD $0x02, 32(SI), X10 + PINSRD $0x03, 8(SI), X10 + MOVL (SI), X11 + PINSRD $0x01, 16(SI), X11 + PINSRD $0x02, 24(SI), X11 + PINSRD $0x03, 40(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 24(SI), X8 + PINSRD $0x01, 56(SI), X8 + PINSRD $0x02, 44(SI), X8 + PINSRD $0x03, (SI), X8 + MOVL 60(SI), X9 + PINSRD $0x01, 36(SI), X9 + PINSRD $0x02, 12(SI), X9 + PINSRD $0x03, 32(SI), X9 + MOVL 48(SI), X10 + PINSRD $0x01, 52(SI), X10 + PINSRD $0x02, 4(SI), X10 + PINSRD $0x03, 40(SI), X10 + MOVL 8(SI), X11 + PINSRD $0x01, 28(SI), X11 + PINSRD $0x02, 16(SI), X11 + PINSRD $0x03, 20(SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + MOVL 40(SI), X8 + PINSRD $0x01, 32(SI), X8 + PINSRD $0x02, 28(SI), X8 + PINSRD $0x03, 4(SI), X8 + MOVL 8(SI), X9 + PINSRD $0x01, 16(SI), X9 + PINSRD $0x02, 24(SI), X9 + PINSRD $0x03, 20(SI), X9 + MOVL 60(SI), X10 + PINSRD $0x01, 36(SI), X10 + PINSRD $0x02, 12(SI), X10 + PINSRD $0x03, 52(SI), X10 + MOVL 44(SI), X11 + PINSRD $0x01, 56(SI), X11 + PINSRD $0x02, 48(SI), X11 + PINSRD $0x03, (SI), X11 + PADDL X8, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X9, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X5, X5 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X7, X7 + PADDL X10, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X13, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x14, X8 + PSRLL $0x0c, X5 + PXOR X8, X5 + PADDL X11, X4 + PADDL X5, X4 + PXOR X4, X7 + PSHUFB X14, X7 + PADDL X7, X6 + PXOR X6, X5 + MOVO X5, X8 + PSLLL $0x19, X8 + PSRLL $0x07, X5 + PXOR X8, X5 + PSHUFL $0x39, X7, X7 + PSHUFL $0x4e, X6, X6 + PSHUFL $0x93, X5, X5 + PXOR X4, X0 + PXOR X5, X1 + PXOR X6, X0 + PXOR X7, X1 + LEAQ 64(SI), SI + SUBQ $0x40, DX + JNE loop + MOVO X15, (BP) + MOVQ (BP), R9 + MOVQ R9, (BX) + MOVOU X0, (AX) + MOVOU X1, 16(AX) RET diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go index db42e6676a..c709b72847 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go +++ b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego +//go:build (!arm64 && !s390x && !ppc64 && !ppc64le) || !gc || purego package chacha20 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go similarity index 89% rename from vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go rename to vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go index 3a4287f990..bd183d9ba1 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go +++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build gc && !purego +//go:build gc && !purego && (ppc64 || ppc64le) package chacha20 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s similarity index 76% rename from vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s rename to vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s index c672ccf698..a660b4112f 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s +++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s @@ -19,7 +19,7 @@ // The differences in this and the original implementation are // due to the calling conventions and initialization of constants. -//go:build gc && !purego +//go:build gc && !purego && (ppc64 || ppc64le) #include "textflag.h" @@ -36,32 +36,68 @@ // for VPERMXOR #define MASK R18 -DATA consts<>+0x00(SB)/8, $0x3320646e61707865 -DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 -DATA consts<>+0x10(SB)/8, $0x0000000000000001 -DATA consts<>+0x18(SB)/8, $0x0000000000000000 -DATA consts<>+0x20(SB)/8, $0x0000000000000004 -DATA consts<>+0x28(SB)/8, $0x0000000000000000 -DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d -DATA consts<>+0x38(SB)/8, $0x0203000106070405 -DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c -DATA consts<>+0x48(SB)/8, $0x0102030005060704 -DATA consts<>+0x50(SB)/8, $0x6170786561707865 -DATA consts<>+0x58(SB)/8, $0x6170786561707865 -DATA consts<>+0x60(SB)/8, $0x3320646e3320646e -DATA consts<>+0x68(SB)/8, $0x3320646e3320646e -DATA consts<>+0x70(SB)/8, $0x79622d3279622d32 -DATA consts<>+0x78(SB)/8, $0x79622d3279622d32 -DATA consts<>+0x80(SB)/8, $0x6b2065746b206574 -DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 -DATA consts<>+0x90(SB)/8, $0x0000000100000000 -DATA consts<>+0x98(SB)/8, $0x0000000300000002 -DATA consts<>+0xa0(SB)/8, $0x5566774411223300 -DATA consts<>+0xa8(SB)/8, $0xddeeffcc99aabb88 -DATA consts<>+0xb0(SB)/8, $0x6677445522330011 -DATA consts<>+0xb8(SB)/8, $0xeeffccddaabb8899 +DATA consts<>+0x00(SB)/4, $0x61707865 +DATA consts<>+0x04(SB)/4, $0x3320646e +DATA consts<>+0x08(SB)/4, $0x79622d32 +DATA consts<>+0x0c(SB)/4, $0x6b206574 +DATA consts<>+0x10(SB)/4, $0x00000001 +DATA consts<>+0x14(SB)/4, $0x00000000 +DATA consts<>+0x18(SB)/4, $0x00000000 +DATA consts<>+0x1c(SB)/4, $0x00000000 +DATA consts<>+0x20(SB)/4, $0x00000004 +DATA consts<>+0x24(SB)/4, $0x00000000 +DATA consts<>+0x28(SB)/4, $0x00000000 +DATA consts<>+0x2c(SB)/4, $0x00000000 +DATA consts<>+0x30(SB)/4, $0x0e0f0c0d +DATA consts<>+0x34(SB)/4, $0x0a0b0809 +DATA consts<>+0x38(SB)/4, $0x06070405 +DATA consts<>+0x3c(SB)/4, $0x02030001 +DATA consts<>+0x40(SB)/4, $0x0d0e0f0c +DATA consts<>+0x44(SB)/4, $0x090a0b08 +DATA consts<>+0x48(SB)/4, $0x05060704 +DATA consts<>+0x4c(SB)/4, $0x01020300 +DATA consts<>+0x50(SB)/4, $0x61707865 +DATA consts<>+0x54(SB)/4, $0x61707865 +DATA consts<>+0x58(SB)/4, $0x61707865 +DATA consts<>+0x5c(SB)/4, $0x61707865 +DATA consts<>+0x60(SB)/4, $0x3320646e +DATA consts<>+0x64(SB)/4, $0x3320646e +DATA consts<>+0x68(SB)/4, $0x3320646e +DATA consts<>+0x6c(SB)/4, $0x3320646e +DATA consts<>+0x70(SB)/4, $0x79622d32 +DATA consts<>+0x74(SB)/4, $0x79622d32 +DATA consts<>+0x78(SB)/4, $0x79622d32 +DATA consts<>+0x7c(SB)/4, $0x79622d32 +DATA consts<>+0x80(SB)/4, $0x6b206574 +DATA consts<>+0x84(SB)/4, $0x6b206574 +DATA consts<>+0x88(SB)/4, $0x6b206574 +DATA consts<>+0x8c(SB)/4, $0x6b206574 +DATA consts<>+0x90(SB)/4, $0x00000000 +DATA consts<>+0x94(SB)/4, $0x00000001 +DATA consts<>+0x98(SB)/4, $0x00000002 +DATA consts<>+0x9c(SB)/4, $0x00000003 +DATA consts<>+0xa0(SB)/4, $0x11223300 +DATA consts<>+0xa4(SB)/4, $0x55667744 +DATA consts<>+0xa8(SB)/4, $0x99aabb88 +DATA consts<>+0xac(SB)/4, $0xddeeffcc +DATA consts<>+0xb0(SB)/4, $0x22330011 +DATA consts<>+0xb4(SB)/4, $0x66774455 +DATA consts<>+0xb8(SB)/4, $0xaabb8899 +DATA consts<>+0xbc(SB)/4, $0xeeffccdd GLOBL consts<>(SB), RODATA, $0xc0 +#ifdef GOARCH_ppc64 +#define BE_XXBRW_INIT() \ + LVSL (R0)(R0), V24 \ + VSPLTISB $3, V25 \ + VXOR V24, V25, V24 \ + +#define BE_XXBRW(vr) VPERM vr, vr, V24, vr +#else +#define BE_XXBRW_INIT() +#define BE_XXBRW(vr) +#endif + //func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 MOVD out+0(FP), OUT @@ -94,6 +130,8 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 // Clear V27 VXOR V27, V27, V27 + BE_XXBRW_INIT() + // V28 LXVW4X (CONSTBASE)(R11), VS60 @@ -299,6 +337,11 @@ loop_vsx: VADDUWM V8, V18, V8 VADDUWM V12, V19, V12 + BE_XXBRW(V0) + BE_XXBRW(V4) + BE_XXBRW(V8) + BE_XXBRW(V12) + CMPU LEN, $64 BLT tail_vsx @@ -327,6 +370,11 @@ loop_vsx: VADDUWM V9, V18, V8 VADDUWM V13, V19, V12 + BE_XXBRW(V0) + BE_XXBRW(V4) + BE_XXBRW(V8) + BE_XXBRW(V12) + CMPU LEN, $64 BLT tail_vsx @@ -334,8 +382,8 @@ loop_vsx: LXVW4X (INP)(R8), VS60 LXVW4X (INP)(R9), VS61 LXVW4X (INP)(R10), VS62 - VXOR V27, V0, V27 + VXOR V27, V0, V27 VXOR V28, V4, V28 VXOR V29, V8, V29 VXOR V30, V12, V30 @@ -354,6 +402,11 @@ loop_vsx: VADDUWM V10, V18, V8 VADDUWM V14, V19, V12 + BE_XXBRW(V0) + BE_XXBRW(V4) + BE_XXBRW(V8) + BE_XXBRW(V12) + CMPU LEN, $64 BLT tail_vsx @@ -381,6 +434,11 @@ loop_vsx: VADDUWM V11, V18, V8 VADDUWM V15, V19, V12 + BE_XXBRW(V0) + BE_XXBRW(V4) + BE_XXBRW(V8) + BE_XXBRW(V12) + CMPU LEN, $64 BLT tail_vsx @@ -408,9 +466,9 @@ loop_vsx: done_vsx: // Increment counter by number of 64 byte blocks - MOVD (CNT), R14 + MOVWZ (CNT), R14 ADD BLOCKS, R14 - MOVD R14, (CNT) + MOVWZ R14, (CNT) RET tail_vsx: diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s index 731d2ac6db..fd5ee845f9 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s @@ -1,2715 +1,9762 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare. +// Code generated by command: go run chacha20poly1305_amd64_asm.go -out ../chacha20poly1305_amd64.s -pkg chacha20poly1305. DO NOT EDIT. //go:build gc && !purego #include "textflag.h" -// General register allocation -#define oup DI -#define inp SI -#define inl BX -#define adp CX // free to reuse, after we hash the additional data -#define keyp R8 // free to reuse, when we copy the key to stack -#define itr2 R9 // general iterator -#define itr1 CX // general iterator -#define acc0 R10 -#define acc1 R11 -#define acc2 R12 -#define t0 R13 -#define t1 R14 -#define t2 R15 -#define t3 R8 -// Register and stack allocation for the SSE code -#define rStore (0*16)(BP) -#define sStore (1*16)(BP) -#define state1Store (2*16)(BP) -#define state2Store (3*16)(BP) -#define tmpStore (4*16)(BP) -#define ctr0Store (5*16)(BP) -#define ctr1Store (6*16)(BP) -#define ctr2Store (7*16)(BP) -#define ctr3Store (8*16)(BP) -#define A0 X0 -#define A1 X1 -#define A2 X2 -#define B0 X3 -#define B1 X4 -#define B2 X5 -#define C0 X6 -#define C1 X7 -#define C2 X8 -#define D0 X9 -#define D1 X10 -#define D2 X11 -#define T0 X12 -#define T1 X13 -#define T2 X14 -#define T3 X15 -#define A3 T0 -#define B3 T1 -#define C3 T2 -#define D3 T3 -// Register and stack allocation for the AVX2 code -#define rsStoreAVX2 (0*32)(BP) -#define state1StoreAVX2 (1*32)(BP) -#define state2StoreAVX2 (2*32)(BP) -#define ctr0StoreAVX2 (3*32)(BP) -#define ctr1StoreAVX2 (4*32)(BP) -#define ctr2StoreAVX2 (5*32)(BP) -#define ctr3StoreAVX2 (6*32)(BP) -#define tmpStoreAVX2 (7*32)(BP) // 256 bytes on stack -#define AA0 Y0 -#define AA1 Y5 -#define AA2 Y6 -#define AA3 Y7 -#define BB0 Y14 -#define BB1 Y9 -#define BB2 Y10 -#define BB3 Y11 -#define CC0 Y12 -#define CC1 Y13 -#define CC2 Y8 -#define CC3 Y15 -#define DD0 Y4 -#define DD1 Y1 -#define DD2 Y2 -#define DD3 Y3 -#define TT0 DD3 -#define TT1 AA3 -#define TT2 BB3 -#define TT3 CC3 -// ChaCha20 constants -DATA ·chacha20Constants<>+0x00(SB)/4, $0x61707865 -DATA ·chacha20Constants<>+0x04(SB)/4, $0x3320646e -DATA ·chacha20Constants<>+0x08(SB)/4, $0x79622d32 -DATA ·chacha20Constants<>+0x0c(SB)/4, $0x6b206574 -DATA ·chacha20Constants<>+0x10(SB)/4, $0x61707865 -DATA ·chacha20Constants<>+0x14(SB)/4, $0x3320646e -DATA ·chacha20Constants<>+0x18(SB)/4, $0x79622d32 -DATA ·chacha20Constants<>+0x1c(SB)/4, $0x6b206574 -// <<< 16 with PSHUFB -DATA ·rol16<>+0x00(SB)/8, $0x0504070601000302 -DATA ·rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A -DATA ·rol16<>+0x10(SB)/8, $0x0504070601000302 -DATA ·rol16<>+0x18(SB)/8, $0x0D0C0F0E09080B0A -// <<< 8 with PSHUFB -DATA ·rol8<>+0x00(SB)/8, $0x0605040702010003 -DATA ·rol8<>+0x08(SB)/8, $0x0E0D0C0F0A09080B -DATA ·rol8<>+0x10(SB)/8, $0x0605040702010003 -DATA ·rol8<>+0x18(SB)/8, $0x0E0D0C0F0A09080B - -DATA ·avx2InitMask<>+0x00(SB)/8, $0x0 -DATA ·avx2InitMask<>+0x08(SB)/8, $0x0 -DATA ·avx2InitMask<>+0x10(SB)/8, $0x1 -DATA ·avx2InitMask<>+0x18(SB)/8, $0x0 - -DATA ·avx2IncMask<>+0x00(SB)/8, $0x2 -DATA ·avx2IncMask<>+0x08(SB)/8, $0x0 -DATA ·avx2IncMask<>+0x10(SB)/8, $0x2 -DATA ·avx2IncMask<>+0x18(SB)/8, $0x0 -// Poly1305 key clamp -DATA ·polyClampMask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF -DATA ·polyClampMask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC -DATA ·polyClampMask<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF -DATA ·polyClampMask<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF - -DATA ·sseIncMask<>+0x00(SB)/8, $0x1 -DATA ·sseIncMask<>+0x08(SB)/8, $0x0 -// To load/store the last < 16 bytes in a buffer -DATA ·andMask<>+0x00(SB)/8, $0x00000000000000ff -DATA ·andMask<>+0x08(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x10(SB)/8, $0x000000000000ffff -DATA ·andMask<>+0x18(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x20(SB)/8, $0x0000000000ffffff -DATA ·andMask<>+0x28(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x30(SB)/8, $0x00000000ffffffff -DATA ·andMask<>+0x38(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x40(SB)/8, $0x000000ffffffffff -DATA ·andMask<>+0x48(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x50(SB)/8, $0x0000ffffffffffff -DATA ·andMask<>+0x58(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x60(SB)/8, $0x00ffffffffffffff -DATA ·andMask<>+0x68(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x70(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0x78(SB)/8, $0x0000000000000000 -DATA ·andMask<>+0x80(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0x88(SB)/8, $0x00000000000000ff -DATA ·andMask<>+0x90(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0x98(SB)/8, $0x000000000000ffff -DATA ·andMask<>+0xa0(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0xa8(SB)/8, $0x0000000000ffffff -DATA ·andMask<>+0xb0(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0xb8(SB)/8, $0x00000000ffffffff -DATA ·andMask<>+0xc0(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0xc8(SB)/8, $0x000000ffffffffff -DATA ·andMask<>+0xd0(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0xd8(SB)/8, $0x0000ffffffffffff -DATA ·andMask<>+0xe0(SB)/8, $0xffffffffffffffff -DATA ·andMask<>+0xe8(SB)/8, $0x00ffffffffffffff - -GLOBL ·chacha20Constants<>(SB), (NOPTR+RODATA), $32 -GLOBL ·rol16<>(SB), (NOPTR+RODATA), $32 -GLOBL ·rol8<>(SB), (NOPTR+RODATA), $32 -GLOBL ·sseIncMask<>(SB), (NOPTR+RODATA), $16 -GLOBL ·avx2IncMask<>(SB), (NOPTR+RODATA), $32 -GLOBL ·avx2InitMask<>(SB), (NOPTR+RODATA), $32 -GLOBL ·polyClampMask<>(SB), (NOPTR+RODATA), $32 -GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240 -// No PALIGNR in Go ASM yet (but VPALIGNR is present). -#define shiftB0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X3, X3 -#define shiftB1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x04 // PALIGNR $4, X4, X4 -#define shiftB2Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X5, X5 -#define shiftB3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X13, X13 -#define shiftC0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X6, X6 -#define shiftC1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x08 // PALIGNR $8, X7, X7 -#define shiftC2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc0; BYTE $0x08 // PALIGNR $8, X8, X8 -#define shiftC3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X14, X14 -#define shiftD0Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x0c // PALIGNR $12, X9, X9 -#define shiftD1Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x0c // PALIGNR $12, X10, X10 -#define shiftD2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X11, X11 -#define shiftD3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x0c // PALIGNR $12, X15, X15 -#define shiftB0Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X3, X3 -#define shiftB1Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x0c // PALIGNR $12, X4, X4 -#define shiftB2Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X5, X5 -#define shiftB3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X13, X13 -#define shiftC0Right shiftC0Left -#define shiftC1Right shiftC1Left -#define shiftC2Right shiftC2Left -#define shiftC3Right shiftC3Left -#define shiftD0Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x04 // PALIGNR $4, X9, X9 -#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10 -#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11 -#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15 - -// Some macros - -// ROL rotates the uint32s in register R left by N bits, using temporary T. -#define ROL(N, R, T) \ - MOVO R, T; PSLLL $(N), T; PSRLL $(32-(N)), R; PXOR T, R - -// ROL16 rotates the uint32s in register R left by 16, using temporary T if needed. -#ifdef GOAMD64_v2 -#define ROL16(R, T) PSHUFB ·rol16<>(SB), R -#else -#define ROL16(R, T) ROL(16, R, T) -#endif - -// ROL8 rotates the uint32s in register R left by 8, using temporary T if needed. -#ifdef GOAMD64_v2 -#define ROL8(R, T) PSHUFB ·rol8<>(SB), R -#else -#define ROL8(R, T) ROL(8, R, T) -#endif - -#define chachaQR(A, B, C, D, T) \ - PADDD B, A; PXOR A, D; ROL16(D, T) \ - PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \ - PADDD B, A; PXOR A, D; ROL8(D, T) \ - PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B - -#define chachaQR_AVX2(A, B, C, D, T) \ - VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol16<>(SB), D, D \ - VPADDD D, C, C; VPXOR C, B, B; VPSLLD $12, B, T; VPSRLD $20, B, B; VPXOR T, B, B \ - VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol8<>(SB), D, D \ - VPADDD D, C, C; VPXOR C, B, B; VPSLLD $7, B, T; VPSRLD $25, B, B; VPXOR T, B, B - -#define polyAdd(S) ADDQ S, acc0; ADCQ 8+S, acc1; ADCQ $1, acc2 -#define polyMulStage1 MOVQ (0*8)(BP), AX; MOVQ AX, t2; MULQ acc0; MOVQ AX, t0; MOVQ DX, t1; MOVQ (0*8)(BP), AX; MULQ acc1; IMULQ acc2, t2; ADDQ AX, t1; ADCQ DX, t2 -#define polyMulStage2 MOVQ (1*8)(BP), AX; MOVQ AX, t3; MULQ acc0; ADDQ AX, t1; ADCQ $0, DX; MOVQ DX, acc0; MOVQ (1*8)(BP), AX; MULQ acc1; ADDQ AX, t2; ADCQ $0, DX -#define polyMulStage3 IMULQ acc2, t3; ADDQ acc0, t2; ADCQ DX, t3 -#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t3, t2; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2 - -#define polyMulStage1_AVX2 MOVQ (0*8)(BP), DX; MOVQ DX, t2; MULXQ acc0, t0, t1; IMULQ acc2, t2; MULXQ acc1, AX, DX; ADDQ AX, t1; ADCQ DX, t2 -#define polyMulStage2_AVX2 MOVQ (1*8)(BP), DX; MULXQ acc0, acc0, AX; ADDQ acc0, t1; MULXQ acc1, acc1, t3; ADCQ acc1, t2; ADCQ $0, t3 -#define polyMulStage3_AVX2 IMULQ acc2, DX; ADDQ AX, t2; ADCQ DX, t3 - -#define polyMul polyMulStage1; polyMulStage2; polyMulStage3; polyMulReduceStage -#define polyMulAVX2 polyMulStage1_AVX2; polyMulStage2_AVX2; polyMulStage3_AVX2; polyMulReduceStage -// ---------------------------------------------------------------------------- + +// func polyHashADInternal<>() TEXT polyHashADInternal<>(SB), NOSPLIT, $0 - // adp points to beginning of additional data - // itr2 holds ad length - XORQ acc0, acc0 - XORQ acc1, acc1 - XORQ acc2, acc2 - CMPQ itr2, $13 - JNE hashADLoop - -openFastTLSAD: - // Special treatment for the TLS case of 13 bytes - MOVQ (adp), acc0 - MOVQ 5(adp), acc1 - SHRQ $24, acc1 - MOVQ $1, acc2 - polyMul + // Hack: Must declare #define macros inside of a function due to Avo constraints + // ROL rotates the uint32s in register R left by N bits, using temporary T. + #define ROL(N, R, T) \ + MOVO R, T; \ + PSLLL $(N), T; \ + PSRLL $(32-(N)), R; \ + PXOR T, R + + // ROL8 rotates the uint32s in register R left by 8, using temporary T if needed. + #ifdef GOAMD64_v2 + #define ROL8(R, T) PSHUFB ·rol8<>(SB), R + #else + #define ROL8(R, T) ROL(8, R, T) + #endif + + // ROL16 rotates the uint32s in register R left by 16, using temporary T if needed. + #ifdef GOAMD64_v2 + #define ROL16(R, T) PSHUFB ·rol16<>(SB), R + #else + #define ROL16(R, T) ROL(16, R, T) + #endif + XORQ R10, R10 + XORQ R11, R11 + XORQ R12, R12 + CMPQ R9, $0x0d + JNE hashADLoop + MOVQ (CX), R10 + MOVQ 5(CX), R11 + SHRQ $0x18, R11 + MOVQ $0x00000001, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 RET hashADLoop: // Hash in 16 byte chunks - CMPQ itr2, $16 - JB hashADTail - polyAdd(0(adp)) - LEAQ (1*16)(adp), adp - SUBQ $16, itr2 - polyMul - JMP hashADLoop + CMPQ R9, $0x10 + JB hashADTail + ADDQ (CX), R10 + ADCQ 8(CX), R11 + ADCQ $0x01, R12 + LEAQ 16(CX), CX + SUBQ $0x10, R9 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + JMP hashADLoop hashADTail: - CMPQ itr2, $0 + CMPQ R9, $0x00 JE hashADDone // Hash last < 16 byte tail - XORQ t0, t0 - XORQ t1, t1 - XORQ t2, t2 - ADDQ itr2, adp + XORQ R13, R13 + XORQ R14, R14 + XORQ R15, R15 + ADDQ R9, CX hashADTailLoop: - SHLQ $8, t0, t1 - SHLQ $8, t0 - MOVB -1(adp), t2 - XORQ t2, t0 - DECQ adp - DECQ itr2 - JNE hashADTailLoop - -hashADTailFinish: - ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 - polyMul - - // Finished AD + SHLQ $0x08, R13, R14 + SHLQ $0x08, R13 + MOVB -1(CX), R15 + XORQ R15, R13 + DECQ CX + DECQ R9 + JNE hashADTailLoop + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + hashADDone: RET -// ---------------------------------------------------------------------------- -// func chacha20Poly1305Open(dst, key, src, ad []byte) bool -TEXT ·chacha20Poly1305Open(SB), 0, $288-97 +// func chacha20Poly1305Open(dst []byte, key []uint32, src []byte, ad []byte) bool +// Requires: AVX, AVX2, BMI2, CMOV, SSE2 +TEXT ·chacha20Poly1305Open(SB), $288-97 // For aligned stack access MOVQ SP, BP - ADDQ $32, BP + ADDQ $0x20, BP ANDQ $-32, BP - MOVQ dst+0(FP), oup - MOVQ key+24(FP), keyp - MOVQ src+48(FP), inp - MOVQ src_len+56(FP), inl - MOVQ ad+72(FP), adp + MOVQ dst_base+0(FP), DI + MOVQ key_base+24(FP), R8 + MOVQ src_base+48(FP), SI + MOVQ src_len+56(FP), BX + MOVQ ad_base+72(FP), CX // Check for AVX2 support - CMPB ·useAVX2(SB), $1 + CMPB ·useAVX2+0(SB), $0x01 JE chacha20Poly1305Open_AVX2 // Special optimization, for very short buffers - CMPQ inl, $128 - JBE openSSE128 // About 16% faster + CMPQ BX, $0x80 + JBE openSSE128 // For long buffers, prepare the poly key first - MOVOU ·chacha20Constants<>(SB), A0 - MOVOU (1*16)(keyp), B0 - MOVOU (2*16)(keyp), C0 - MOVOU (3*16)(keyp), D0 - MOVO D0, T1 + MOVOU ·chacha20Constants<>+0(SB), X0 + MOVOU 16(R8), X3 + MOVOU 32(R8), X6 + MOVOU 48(R8), X9 + MOVO X9, X13 // Store state on stack for future use - MOVO B0, state1Store - MOVO C0, state2Store - MOVO D0, ctr3Store - MOVQ $10, itr2 + MOVO X3, 32(BP) + MOVO X6, 48(BP) + MOVO X9, 128(BP) + MOVQ $0x0000000a, R9 openSSEPreparePolyKey: - chachaQR(A0, B0, C0, D0, T0) - shiftB0Left; shiftC0Left; shiftD0Left - chachaQR(A0, B0, C0, D0, T0) - shiftB0Right; shiftC0Right; shiftD0Right - DECQ itr2 - JNE openSSEPreparePolyKey + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + DECQ R9 + JNE openSSEPreparePolyKey // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded - PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0 + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL 32(BP), X3 // Clamp and store the key - PAND ·polyClampMask<>(SB), A0 - MOVO A0, rStore; MOVO B0, sStore + PAND ·polyClampMask<>+0(SB), X0 + MOVO X0, (BP) + MOVO X3, 16(BP) // Hash AAD - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) openSSEMainLoop: - CMPQ inl, $256 + CMPQ BX, $0x00000100 JB openSSEMainLoopDone // Load state, increment counter blocks - MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0 - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 - MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + MOVO ·chacha20Constants<>+0(SB), X0 + MOVO 32(BP), X3 + MOVO 48(BP), X6 + MOVO 128(BP), X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X2, X12 + MOVO X5, X13 + MOVO X8, X14 + MOVO X11, X15 + PADDL ·sseIncMask<>+0(SB), X15 // Store counters - MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store + MOVO X9, 80(BP) + MOVO X10, 96(BP) + MOVO X11, 112(BP) + MOVO X15, 128(BP) - // There are 10 ChaCha20 iterations of 2QR each, so for 6 iterations we hash 2 blocks, and for the remaining 4 only 1 block - for a total of 16 - MOVQ $4, itr1 - MOVQ inp, itr2 + // There are 10 ChaCha20 iterations of 2QR each, so for 6 iterations we hash + // 2 blocks, and for the remaining 4 only 1 block - for a total of 16 + MOVQ $0x00000004, CX + MOVQ SI, R9 openSSEInternalLoop: - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - polyAdd(0(itr2)) - shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left - shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left - shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left - polyMulStage1 - polyMulStage2 - LEAQ (2*8)(itr2), itr2 - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - polyMulStage3 - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - polyMulReduceStage - shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right - shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right - shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right - DECQ itr1 - JGE openSSEInternalLoop - - polyAdd(0(itr2)) - polyMul - LEAQ (2*8)(itr2), itr2 - - CMPQ itr1, $-6 - JG openSSEInternalLoop + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x0c + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + LEAQ 16(R9), R9 + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x04 + DECQ CX + JGE openSSEInternalLoop + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(R9), R9 + CMPQ CX, $-6 + JG openSSEInternalLoop // Add in the state - PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 - PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 - PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 - PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 + PADDD ·chacha20Constants<>+0(SB), X0 + PADDD ·chacha20Constants<>+0(SB), X1 + PADDD ·chacha20Constants<>+0(SB), X2 + PADDD ·chacha20Constants<>+0(SB), X12 + PADDD 32(BP), X3 + PADDD 32(BP), X4 + PADDD 32(BP), X5 + PADDD 32(BP), X13 + PADDD 48(BP), X6 + PADDD 48(BP), X7 + PADDD 48(BP), X8 + PADDD 48(BP), X14 + PADDD 80(BP), X9 + PADDD 96(BP), X10 + PADDD 112(BP), X11 + PADDD 128(BP), X15 // Load - xor - store - MOVO D3, tmpStore - MOVOU (0*16)(inp), D3; PXOR D3, A0; MOVOU A0, (0*16)(oup) - MOVOU (1*16)(inp), D3; PXOR D3, B0; MOVOU B0, (1*16)(oup) - MOVOU (2*16)(inp), D3; PXOR D3, C0; MOVOU C0, (2*16)(oup) - MOVOU (3*16)(inp), D3; PXOR D3, D0; MOVOU D0, (3*16)(oup) - MOVOU (4*16)(inp), D0; PXOR D0, A1; MOVOU A1, (4*16)(oup) - MOVOU (5*16)(inp), D0; PXOR D0, B1; MOVOU B1, (5*16)(oup) - MOVOU (6*16)(inp), D0; PXOR D0, C1; MOVOU C1, (6*16)(oup) - MOVOU (7*16)(inp), D0; PXOR D0, D1; MOVOU D1, (7*16)(oup) - MOVOU (8*16)(inp), D0; PXOR D0, A2; MOVOU A2, (8*16)(oup) - MOVOU (9*16)(inp), D0; PXOR D0, B2; MOVOU B2, (9*16)(oup) - MOVOU (10*16)(inp), D0; PXOR D0, C2; MOVOU C2, (10*16)(oup) - MOVOU (11*16)(inp), D0; PXOR D0, D2; MOVOU D2, (11*16)(oup) - MOVOU (12*16)(inp), D0; PXOR D0, A3; MOVOU A3, (12*16)(oup) - MOVOU (13*16)(inp), D0; PXOR D0, B3; MOVOU B3, (13*16)(oup) - MOVOU (14*16)(inp), D0; PXOR D0, C3; MOVOU C3, (14*16)(oup) - MOVOU (15*16)(inp), D0; PXOR tmpStore, D0; MOVOU D0, (15*16)(oup) - LEAQ 256(inp), inp - LEAQ 256(oup), oup - SUBQ $256, inl + MOVO X15, 64(BP) + MOVOU (SI), X15 + PXOR X15, X0 + MOVOU X0, (DI) + MOVOU 16(SI), X15 + PXOR X15, X3 + MOVOU X3, 16(DI) + MOVOU 32(SI), X15 + PXOR X15, X6 + MOVOU X6, 32(DI) + MOVOU 48(SI), X15 + PXOR X15, X9 + MOVOU X9, 48(DI) + MOVOU 64(SI), X9 + PXOR X9, X1 + MOVOU X1, 64(DI) + MOVOU 80(SI), X9 + PXOR X9, X4 + MOVOU X4, 80(DI) + MOVOU 96(SI), X9 + PXOR X9, X7 + MOVOU X7, 96(DI) + MOVOU 112(SI), X9 + PXOR X9, X10 + MOVOU X10, 112(DI) + MOVOU 128(SI), X9 + PXOR X9, X2 + MOVOU X2, 128(DI) + MOVOU 144(SI), X9 + PXOR X9, X5 + MOVOU X5, 144(DI) + MOVOU 160(SI), X9 + PXOR X9, X8 + MOVOU X8, 160(DI) + MOVOU 176(SI), X9 + PXOR X9, X11 + MOVOU X11, 176(DI) + MOVOU 192(SI), X9 + PXOR X9, X12 + MOVOU X12, 192(DI) + MOVOU 208(SI), X9 + PXOR X9, X13 + MOVOU X13, 208(DI) + MOVOU 224(SI), X9 + PXOR X9, X14 + MOVOU X14, 224(DI) + MOVOU 240(SI), X9 + PXOR 64(BP), X9 + MOVOU X9, 240(DI) + LEAQ 256(SI), SI + LEAQ 256(DI), DI + SUBQ $0x00000100, BX JMP openSSEMainLoop openSSEMainLoopDone: // Handle the various tail sizes efficiently - TESTQ inl, inl + TESTQ BX, BX JE openSSEFinalize - CMPQ inl, $64 + CMPQ BX, $0x40 JBE openSSETail64 - CMPQ inl, $128 + CMPQ BX, $0x80 JBE openSSETail128 - CMPQ inl, $192 + CMPQ BX, $0xc0 JBE openSSETail192 JMP openSSETail256 openSSEFinalize: // Hash in the PT, AAD lengths - ADDQ ad_len+80(FP), acc0; ADCQ src_len+56(FP), acc1; ADCQ $1, acc2 - polyMul + ADDQ ad_len+80(FP), R10 + ADCQ src_len+56(FP), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 // Final reduce - MOVQ acc0, t0 - MOVQ acc1, t1 - MOVQ acc2, t2 - SUBQ $-5, acc0 - SBBQ $-1, acc1 - SBBQ $3, acc2 - CMOVQCS t0, acc0 - CMOVQCS t1, acc1 - CMOVQCS t2, acc2 + MOVQ R10, R13 + MOVQ R11, R14 + MOVQ R12, R15 + SUBQ $-5, R10 + SBBQ $-1, R11 + SBBQ $0x03, R12 + CMOVQCS R13, R10 + CMOVQCS R14, R11 + CMOVQCS R15, R12 // Add in the "s" part of the key - ADDQ 0+sStore, acc0 - ADCQ 8+sStore, acc1 + ADDQ 16(BP), R10 + ADCQ 24(BP), R11 // Finally, constant time compare to the tag at the end of the message XORQ AX, AX - MOVQ $1, DX - XORQ (0*8)(inp), acc0 - XORQ (1*8)(inp), acc1 - ORQ acc1, acc0 + MOVQ $0x00000001, DX + XORQ (SI), R10 + XORQ 8(SI), R11 + ORQ R11, R10 CMOVQEQ DX, AX // Return true iff tags are equal MOVB AX, ret+96(FP) RET -// ---------------------------------------------------------------------------- -// Special optimization for buffers smaller than 129 bytes openSSE128: - // For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks - MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0 - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 - MOVO B0, T1; MOVO C0, T2; MOVO D1, T3 - MOVQ $10, itr2 + MOVOU ·chacha20Constants<>+0(SB), X0 + MOVOU 16(R8), X3 + MOVOU 32(R8), X6 + MOVOU 48(R8), X9 + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X3, X13 + MOVO X6, X14 + MOVO X10, X15 + MOVQ $0x0000000a, R9 openSSE128InnerCipherLoop: - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Left; shiftB1Left; shiftB2Left - shiftC0Left; shiftC1Left; shiftC2Left - shiftD0Left; shiftD1Left; shiftD2Left - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Right; shiftB1Right; shiftB2Right - shiftC0Right; shiftC1Right; shiftC2Right - shiftD0Right; shiftD1Right; shiftD2Right - DECQ itr2 - JNE openSSE128InnerCipherLoop + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + DECQ R9 + JNE openSSE128InnerCipherLoop // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded - PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 - PADDL T1, B0; PADDL T1, B1; PADDL T1, B2 - PADDL T2, C1; PADDL T2, C2 - PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2 + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL ·chacha20Constants<>+0(SB), X2 + PADDL X13, X3 + PADDL X13, X4 + PADDL X13, X5 + PADDL X14, X7 + PADDL X14, X8 + PADDL X15, X10 + PADDL ·sseIncMask<>+0(SB), X15 + PADDL X15, X11 // Clamp and store the key - PAND ·polyClampMask<>(SB), A0 - MOVOU A0, rStore; MOVOU B0, sStore + PAND ·polyClampMask<>+0(SB), X0 + MOVOU X0, (BP) + MOVOU X3, 16(BP) // Hash - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) openSSE128Open: - CMPQ inl, $16 + CMPQ BX, $0x10 JB openSSETail16 - SUBQ $16, inl + SUBQ $0x10, BX // Load for hashing - polyAdd(0(inp)) + ADDQ (SI), R10 + ADCQ 8(SI), R11 + ADCQ $0x01, R12 // Load for decryption - MOVOU (inp), T0; PXOR T0, A1; MOVOU A1, (oup) - LEAQ (1*16)(inp), inp - LEAQ (1*16)(oup), oup - polyMul + MOVOU (SI), X12 + PXOR X12, X1 + MOVOU X1, (DI) + LEAQ 16(SI), SI + LEAQ 16(DI), DI + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 // Shift the stream "left" - MOVO B1, A1 - MOVO C1, B1 - MOVO D1, C1 - MOVO A2, D1 - MOVO B2, A2 - MOVO C2, B2 - MOVO D2, C2 + MOVO X4, X1 + MOVO X7, X4 + MOVO X10, X7 + MOVO X2, X10 + MOVO X5, X2 + MOVO X8, X5 + MOVO X11, X8 JMP openSSE128Open openSSETail16: - TESTQ inl, inl + TESTQ BX, BX JE openSSEFinalize // We can safely load the CT from the end, because it is padded with the MAC - MOVQ inl, itr2 - SHLQ $4, itr2 - LEAQ ·andMask<>(SB), t0 - MOVOU (inp), T0 - ADDQ inl, inp - PAND -16(t0)(itr2*1), T0 - MOVO T0, 0+tmpStore - MOVQ T0, t0 - MOVQ 8+tmpStore, t1 - PXOR A1, T0 + MOVQ BX, R9 + SHLQ $0x04, R9 + LEAQ ·andMask<>+0(SB), R13 + MOVOU (SI), X12 + ADDQ BX, SI + PAND -16(R13)(R9*1), X12 + MOVO X12, 64(BP) + MOVQ X12, R13 + MOVQ 72(BP), R14 + PXOR X1, X12 // We can only store one byte at a time, since plaintext can be shorter than 16 bytes openSSETail16Store: - MOVQ T0, t3 - MOVB t3, (oup) - PSRLDQ $1, T0 - INCQ oup - DECQ inl + MOVQ X12, R8 + MOVB R8, (DI) + PSRLDQ $0x01, X12 + INCQ DI + DECQ BX JNE openSSETail16Store - ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 - polyMul + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 JMP openSSEFinalize -// ---------------------------------------------------------------------------- -// Special optimization for the last 64 bytes of ciphertext openSSETail64: - // Need to decrypt up to 64 bytes - prepare single block - MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store - XORQ itr2, itr2 - MOVQ inl, itr1 - CMPQ itr1, $16 - JB openSSETail64LoopB + MOVO ·chacha20Constants<>+0(SB), X0 + MOVO 32(BP), X3 + MOVO 48(BP), X6 + MOVO 128(BP), X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X9, 80(BP) + XORQ R9, R9 + MOVQ BX, CX + CMPQ CX, $0x10 + JB openSSETail64LoopB openSSETail64LoopA: - // Perform ChaCha rounds, while hashing the remaining input - polyAdd(0(inp)(itr2*1)) - polyMul - SUBQ $16, itr1 + ADDQ (SI)(R9*1), R10 + ADCQ 8(SI)(R9*1), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + SUBQ $0x10, CX openSSETail64LoopB: - ADDQ $16, itr2 - chachaQR(A0, B0, C0, D0, T0) - shiftB0Left; shiftC0Left; shiftD0Left - chachaQR(A0, B0, C0, D0, T0) - shiftB0Right; shiftC0Right; shiftD0Right - - CMPQ itr1, $16 - JAE openSSETail64LoopA - - CMPQ itr2, $160 - JNE openSSETail64LoopB - - PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0; PADDL state2Store, C0; PADDL ctr0Store, D0 + ADDQ $0x10, R9 + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + CMPQ CX, $0x10 + JAE openSSETail64LoopA + CMPQ R9, $0xa0 + JNE openSSETail64LoopB + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL 32(BP), X3 + PADDL 48(BP), X6 + PADDL 80(BP), X9 openSSETail64DecLoop: - CMPQ inl, $16 + CMPQ BX, $0x10 JB openSSETail64DecLoopDone - SUBQ $16, inl - MOVOU (inp), T0 - PXOR T0, A0 - MOVOU A0, (oup) - LEAQ 16(inp), inp - LEAQ 16(oup), oup - MOVO B0, A0 - MOVO C0, B0 - MOVO D0, C0 + SUBQ $0x10, BX + MOVOU (SI), X12 + PXOR X12, X0 + MOVOU X0, (DI) + LEAQ 16(SI), SI + LEAQ 16(DI), DI + MOVO X3, X0 + MOVO X6, X3 + MOVO X9, X6 JMP openSSETail64DecLoop openSSETail64DecLoopDone: - MOVO A0, A1 + MOVO X0, X1 JMP openSSETail16 -// ---------------------------------------------------------------------------- -// Special optimization for the last 128 bytes of ciphertext openSSETail128: - // Need to decrypt up to 128 bytes - prepare two blocks - MOVO ·chacha20Constants<>(SB), A1; MOVO state1Store, B1; MOVO state2Store, C1; MOVO ctr3Store, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr0Store - MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr1Store - XORQ itr2, itr2 - MOVQ inl, itr1 - ANDQ $-16, itr1 + MOVO ·chacha20Constants<>+0(SB), X1 + MOVO 32(BP), X4 + MOVO 48(BP), X7 + MOVO 128(BP), X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X10, 80(BP) + MOVO X1, X0 + MOVO X4, X3 + MOVO X7, X6 + MOVO X10, X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X9, 96(BP) + XORQ R9, R9 + MOVQ BX, CX + ANDQ $-16, CX openSSETail128LoopA: - // Perform ChaCha rounds, while hashing the remaining input - polyAdd(0(inp)(itr2*1)) - polyMul + ADDQ (SI)(R9*1), R10 + ADCQ 8(SI)(R9*1), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 openSSETail128LoopB: - ADDQ $16, itr2 - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) - shiftB0Left; shiftC0Left; shiftD0Left - shiftB1Left; shiftC1Left; shiftD1Left - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) - shiftB0Right; shiftC0Right; shiftD0Right - shiftB1Right; shiftC1Right; shiftD1Right - - CMPQ itr2, itr1 - JB openSSETail128LoopA - - CMPQ itr2, $160 - JNE openSSETail128LoopB - - PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1 - PADDL state1Store, B0; PADDL state1Store, B1 - PADDL state2Store, C0; PADDL state2Store, C1 - PADDL ctr1Store, D0; PADDL ctr0Store, D1 - - MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 - PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1 - MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup) - - SUBQ $64, inl - LEAQ 64(inp), inp - LEAQ 64(oup), oup - JMP openSSETail64DecLoop - -// ---------------------------------------------------------------------------- -// Special optimization for the last 192 bytes of ciphertext + ADDQ $0x10, R9 + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + CMPQ R9, CX + JB openSSETail128LoopA + CMPQ R9, $0xa0 + JNE openSSETail128LoopB + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL 32(BP), X3 + PADDL 32(BP), X4 + PADDL 48(BP), X6 + PADDL 48(BP), X7 + PADDL 96(BP), X9 + PADDL 80(BP), X10 + MOVOU (SI), X12 + MOVOU 16(SI), X13 + MOVOU 32(SI), X14 + MOVOU 48(SI), X15 + PXOR X12, X1 + PXOR X13, X4 + PXOR X14, X7 + PXOR X15, X10 + MOVOU X1, (DI) + MOVOU X4, 16(DI) + MOVOU X7, 32(DI) + MOVOU X10, 48(DI) + SUBQ $0x40, BX + LEAQ 64(SI), SI + LEAQ 64(DI), DI + JMP openSSETail64DecLoop + openSSETail192: - // Need to decrypt up to 192 bytes - prepare three blocks - MOVO ·chacha20Constants<>(SB), A2; MOVO state1Store, B2; MOVO state2Store, C2; MOVO ctr3Store, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr0Store - MOVO A2, A1; MOVO B2, B1; MOVO C2, C1; MOVO D2, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store - MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr2Store - - MOVQ inl, itr1 - MOVQ $160, itr2 - CMPQ itr1, $160 - CMOVQGT itr2, itr1 - ANDQ $-16, itr1 - XORQ itr2, itr2 + MOVO ·chacha20Constants<>+0(SB), X2 + MOVO 32(BP), X5 + MOVO 48(BP), X8 + MOVO 128(BP), X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X11, 80(BP) + MOVO X2, X1 + MOVO X5, X4 + MOVO X8, X7 + MOVO X11, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X10, 96(BP) + MOVO X1, X0 + MOVO X4, X3 + MOVO X7, X6 + MOVO X10, X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X9, 112(BP) + MOVQ BX, CX + MOVQ $0x000000a0, R9 + CMPQ CX, $0xa0 + CMOVQGT R9, CX + ANDQ $-16, CX + XORQ R9, R9 openSSLTail192LoopA: - // Perform ChaCha rounds, while hashing the remaining input - polyAdd(0(inp)(itr2*1)) - polyMul + ADDQ (SI)(R9*1), R10 + ADCQ 8(SI)(R9*1), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 openSSLTail192LoopB: - ADDQ $16, itr2 - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Left; shiftC0Left; shiftD0Left - shiftB1Left; shiftC1Left; shiftD1Left - shiftB2Left; shiftC2Left; shiftD2Left - - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Right; shiftC0Right; shiftD0Right - shiftB1Right; shiftC1Right; shiftD1Right - shiftB2Right; shiftC2Right; shiftD2Right - - CMPQ itr2, itr1 - JB openSSLTail192LoopA - - CMPQ itr2, $160 - JNE openSSLTail192LoopB - - CMPQ inl, $176 - JB openSSLTail192Store - - polyAdd(160(inp)) - polyMul - - CMPQ inl, $192 - JB openSSLTail192Store - - polyAdd(176(inp)) - polyMul + ADDQ $0x10, R9 + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + CMPQ R9, CX + JB openSSLTail192LoopA + CMPQ R9, $0xa0 + JNE openSSLTail192LoopB + CMPQ BX, $0xb0 + JB openSSLTail192Store + ADDQ 160(SI), R10 + ADCQ 168(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + CMPQ BX, $0xc0 + JB openSSLTail192Store + ADDQ 176(SI), R10 + ADCQ 184(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 openSSLTail192Store: - PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 - PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2 - PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2 - PADDL ctr2Store, D0; PADDL ctr1Store, D1; PADDL ctr0Store, D2 - - MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 - PXOR T0, A2; PXOR T1, B2; PXOR T2, C2; PXOR T3, D2 - MOVOU A2, (0*16)(oup); MOVOU B2, (1*16)(oup); MOVOU C2, (2*16)(oup); MOVOU D2, (3*16)(oup) - - MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3 - PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1 - MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) - - SUBQ $128, inl - LEAQ 128(inp), inp - LEAQ 128(oup), oup - JMP openSSETail64DecLoop - -// ---------------------------------------------------------------------------- -// Special optimization for the last 256 bytes of ciphertext + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL ·chacha20Constants<>+0(SB), X2 + PADDL 32(BP), X3 + PADDL 32(BP), X4 + PADDL 32(BP), X5 + PADDL 48(BP), X6 + PADDL 48(BP), X7 + PADDL 48(BP), X8 + PADDL 112(BP), X9 + PADDL 96(BP), X10 + PADDL 80(BP), X11 + MOVOU (SI), X12 + MOVOU 16(SI), X13 + MOVOU 32(SI), X14 + MOVOU 48(SI), X15 + PXOR X12, X2 + PXOR X13, X5 + PXOR X14, X8 + PXOR X15, X11 + MOVOU X2, (DI) + MOVOU X5, 16(DI) + MOVOU X8, 32(DI) + MOVOU X11, 48(DI) + MOVOU 64(SI), X12 + MOVOU 80(SI), X13 + MOVOU 96(SI), X14 + MOVOU 112(SI), X15 + PXOR X12, X1 + PXOR X13, X4 + PXOR X14, X7 + PXOR X15, X10 + MOVOU X1, 64(DI) + MOVOU X4, 80(DI) + MOVOU X7, 96(DI) + MOVOU X10, 112(DI) + SUBQ $0x80, BX + LEAQ 128(SI), SI + LEAQ 128(DI), DI + JMP openSSETail64DecLoop + openSSETail256: - // Need to decrypt up to 256 bytes - prepare four blocks - MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0 - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 - MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + MOVO ·chacha20Constants<>+0(SB), X0 + MOVO 32(BP), X3 + MOVO 48(BP), X6 + MOVO 128(BP), X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X2, X12 + MOVO X5, X13 + MOVO X8, X14 + MOVO X11, X15 + PADDL ·sseIncMask<>+0(SB), X15 // Store counters - MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store - XORQ itr2, itr2 + MOVO X9, 80(BP) + MOVO X10, 96(BP) + MOVO X11, 112(BP) + MOVO X15, 128(BP) + XORQ R9, R9 openSSETail256Loop: - // This loop inteleaves 8 ChaCha quarter rounds with 1 poly multiplication - polyAdd(0(inp)(itr2*1)) - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left - shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left - shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left - polyMulStage1 - polyMulStage2 - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - polyMulStage3 - polyMulReduceStage - shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right - shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right - shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right - ADDQ $2*8, itr2 - CMPQ itr2, $160 - JB openSSETail256Loop - MOVQ inl, itr1 - ANDQ $-16, itr1 + ADDQ (SI)(R9*1), R10 + ADCQ 8(SI)(R9*1), R11 + ADCQ $0x01, R12 + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x0c + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x04 + ADDQ $0x10, R9 + CMPQ R9, $0xa0 + JB openSSETail256Loop + MOVQ BX, CX + ANDQ $-16, CX openSSETail256HashLoop: - polyAdd(0(inp)(itr2*1)) - polyMul - ADDQ $2*8, itr2 - CMPQ itr2, itr1 - JB openSSETail256HashLoop + ADDQ (SI)(R9*1), R10 + ADCQ 8(SI)(R9*1), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + ADDQ $0x10, R9 + CMPQ R9, CX + JB openSSETail256HashLoop // Add in the state - PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 - PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 - PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 - PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 - MOVO D3, tmpStore + PADDD ·chacha20Constants<>+0(SB), X0 + PADDD ·chacha20Constants<>+0(SB), X1 + PADDD ·chacha20Constants<>+0(SB), X2 + PADDD ·chacha20Constants<>+0(SB), X12 + PADDD 32(BP), X3 + PADDD 32(BP), X4 + PADDD 32(BP), X5 + PADDD 32(BP), X13 + PADDD 48(BP), X6 + PADDD 48(BP), X7 + PADDD 48(BP), X8 + PADDD 48(BP), X14 + PADDD 80(BP), X9 + PADDD 96(BP), X10 + PADDD 112(BP), X11 + PADDD 128(BP), X15 + MOVO X15, 64(BP) // Load - xor - store - MOVOU (0*16)(inp), D3; PXOR D3, A0 - MOVOU (1*16)(inp), D3; PXOR D3, B0 - MOVOU (2*16)(inp), D3; PXOR D3, C0 - MOVOU (3*16)(inp), D3; PXOR D3, D0 - MOVOU A0, (0*16)(oup) - MOVOU B0, (1*16)(oup) - MOVOU C0, (2*16)(oup) - MOVOU D0, (3*16)(oup) - MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0 - PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1 - MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) - MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0 - PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2 - MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup) - LEAQ 192(inp), inp - LEAQ 192(oup), oup - SUBQ $192, inl - MOVO A3, A0 - MOVO B3, B0 - MOVO C3, C0 - MOVO tmpStore, D0 - - JMP openSSETail64DecLoop - -// ---------------------------------------------------------------------------- -// ------------------------- AVX2 Code ---------------------------------------- + MOVOU (SI), X15 + PXOR X15, X0 + MOVOU 16(SI), X15 + PXOR X15, X3 + MOVOU 32(SI), X15 + PXOR X15, X6 + MOVOU 48(SI), X15 + PXOR X15, X9 + MOVOU X0, (DI) + MOVOU X3, 16(DI) + MOVOU X6, 32(DI) + MOVOU X9, 48(DI) + MOVOU 64(SI), X0 + MOVOU 80(SI), X3 + MOVOU 96(SI), X6 + MOVOU 112(SI), X9 + PXOR X0, X1 + PXOR X3, X4 + PXOR X6, X7 + PXOR X9, X10 + MOVOU X1, 64(DI) + MOVOU X4, 80(DI) + MOVOU X7, 96(DI) + MOVOU X10, 112(DI) + MOVOU 128(SI), X0 + MOVOU 144(SI), X3 + MOVOU 160(SI), X6 + MOVOU 176(SI), X9 + PXOR X0, X2 + PXOR X3, X5 + PXOR X6, X8 + PXOR X9, X11 + MOVOU X2, 128(DI) + MOVOU X5, 144(DI) + MOVOU X8, 160(DI) + MOVOU X11, 176(DI) + LEAQ 192(SI), SI + LEAQ 192(DI), DI + SUBQ $0xc0, BX + MOVO X12, X0 + MOVO X13, X3 + MOVO X14, X6 + MOVO 64(BP), X9 + JMP openSSETail64DecLoop + chacha20Poly1305Open_AVX2: VZEROUPPER - VMOVDQU ·chacha20Constants<>(SB), AA0 - BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14 - BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12 - BYTE $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4 - VPADDD ·avx2InitMask<>(SB), DD0, DD0 + VMOVDQU ·chacha20Constants<>+0(SB), Y0 + BYTE $0xc4 + BYTE $0x42 + BYTE $0x7d + BYTE $0x5a + BYTE $0x70 + BYTE $0x10 + BYTE $0xc4 + BYTE $0x42 + BYTE $0x7d + BYTE $0x5a + BYTE $0x60 + BYTE $0x20 + BYTE $0xc4 + BYTE $0xc2 + BYTE $0x7d + BYTE $0x5a + BYTE $0x60 + BYTE $0x30 + VPADDD ·avx2InitMask<>+0(SB), Y4, Y4 // Special optimization, for very short buffers - CMPQ inl, $192 + CMPQ BX, $0xc0 JBE openAVX2192 - CMPQ inl, $320 + CMPQ BX, $0x00000140 JBE openAVX2320 // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream - VMOVDQA BB0, state1StoreAVX2 - VMOVDQA CC0, state2StoreAVX2 - VMOVDQA DD0, ctr3StoreAVX2 - MOVQ $10, itr2 + VMOVDQA Y14, 32(BP) + VMOVDQA Y12, 64(BP) + VMOVDQA Y4, 192(BP) + MOVQ $0x0000000a, R9 openAVX2PreparePolyKey: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0 - DECQ itr2 - JNE openAVX2PreparePolyKey - - VPADDD ·chacha20Constants<>(SB), AA0, AA0 - VPADDD state1StoreAVX2, BB0, BB0 - VPADDD state2StoreAVX2, CC0, CC0 - VPADDD ctr3StoreAVX2, DD0, DD0 - - VPERM2I128 $0x02, AA0, BB0, TT0 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x04, Y4, Y4, Y4 + DECQ R9 + JNE openAVX2PreparePolyKey + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD 32(BP), Y14, Y14 + VPADDD 64(BP), Y12, Y12 + VPADDD 192(BP), Y4, Y4 + VPERM2I128 $0x02, Y0, Y14, Y3 // Clamp and store poly key - VPAND ·polyClampMask<>(SB), TT0, TT0 - VMOVDQA TT0, rsStoreAVX2 + VPAND ·polyClampMask<>+0(SB), Y3, Y3 + VMOVDQA Y3, (BP) // Stream for the first 64 bytes - VPERM2I128 $0x13, AA0, BB0, AA0 - VPERM2I128 $0x13, CC0, DD0, BB0 + VPERM2I128 $0x13, Y0, Y14, Y0 + VPERM2I128 $0x13, Y12, Y4, Y14 // Hash AD + first 64 bytes - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) - XORQ itr1, itr1 + XORQ CX, CX openAVX2InitialHash64: - polyAdd(0(inp)(itr1*1)) - polyMulAVX2 - ADDQ $16, itr1 - CMPQ itr1, $64 - JNE openAVX2InitialHash64 + ADDQ (SI)(CX*1), R10 + ADCQ 8(SI)(CX*1), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + ADDQ $0x10, CX + CMPQ CX, $0x40 + JNE openAVX2InitialHash64 // Decrypt the first 64 bytes - VPXOR (0*32)(inp), AA0, AA0 - VPXOR (1*32)(inp), BB0, BB0 - VMOVDQU AA0, (0*32)(oup) - VMOVDQU BB0, (1*32)(oup) - LEAQ (2*32)(inp), inp - LEAQ (2*32)(oup), oup - SUBQ $64, inl + VPXOR (SI), Y0, Y0 + VPXOR 32(SI), Y14, Y14 + VMOVDQU Y0, (DI) + VMOVDQU Y14, 32(DI) + LEAQ 64(SI), SI + LEAQ 64(DI), DI + SUBQ $0x40, BX openAVX2MainLoop: - CMPQ inl, $512 + CMPQ BX, $0x00000200 JB openAVX2MainLoopDone // Load state, increment counter blocks, store the incremented counters - VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 - VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 - VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 - XORQ itr1, itr1 + VMOVDQU ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA Y0, Y7 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA Y14, Y11 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA Y12, Y15 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VPADDD ·avx2IncMask<>+0(SB), Y2, Y3 + VMOVDQA Y4, 96(BP) + VMOVDQA Y1, 128(BP) + VMOVDQA Y2, 160(BP) + VMOVDQA Y3, 192(BP) + XORQ CX, CX openAVX2InternalLoop: - // Lets just say this spaghetti loop interleaves 2 quarter rounds with 3 poly multiplications - // Effectively per 512 bytes of stream we hash 480 bytes of ciphertext - polyAdd(0*8(inp)(itr1*1)) - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - polyMulStage1_AVX2 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - polyMulStage2_AVX2 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - polyMulStage3_AVX2 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulReduceStage - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - polyAdd(2*8(inp)(itr1*1)) - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - polyMulStage1_AVX2 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulStage2_AVX2 - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - polyMulStage3_AVX2 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - polyMulReduceStage - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - polyAdd(4*8(inp)(itr1*1)) - LEAQ (6*8)(itr1), itr1 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulStage1_AVX2 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - polyMulStage2_AVX2 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - polyMulStage3_AVX2 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulReduceStage - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 - CMPQ itr1, $480 + ADDQ (SI)(CX*1), R10 + ADCQ 8(SI)(CX*1), R11 + ADCQ $0x01, R12 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + ADDQ 16(SI)(CX*1), R10 + ADCQ 24(SI)(CX*1), R11 + ADCQ $0x01, R12 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x04, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPALIGNR $0x0c, Y3, Y3, Y3 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + ADDQ 32(SI)(CX*1), R10 + ADCQ 40(SI)(CX*1), R11 + ADCQ $0x01, R12 + LEAQ 48(CX), CX + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x0c, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + VPALIGNR $0x04, Y3, Y3, Y3 + CMPQ CX, $0x000001e0 JNE openAVX2InternalLoop - - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 - VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 - VMOVDQA CC3, tmpStoreAVX2 + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD ·chacha20Constants<>+0(SB), Y7, Y7 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 32(BP), Y11, Y11 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD 64(BP), Y15, Y15 + VPADDD 96(BP), Y4, Y4 + VPADDD 128(BP), Y1, Y1 + VPADDD 160(BP), Y2, Y2 + VPADDD 192(BP), Y3, Y3 + VMOVDQA Y15, 224(BP) // We only hashed 480 of the 512 bytes available - hash the remaining 32 here - polyAdd(480(inp)) - polyMulAVX2 - VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0 - VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0 - VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup) - VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 - VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 - VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) + ADDQ 480(SI), R10 + ADCQ 488(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPERM2I128 $0x02, Y0, Y14, Y15 + VPERM2I128 $0x13, Y0, Y14, Y14 + VPERM2I128 $0x02, Y12, Y4, Y0 + VPERM2I128 $0x13, Y12, Y4, Y12 + VPXOR (SI), Y15, Y15 + VPXOR 32(SI), Y0, Y0 + VPXOR 64(SI), Y14, Y14 + VPXOR 96(SI), Y12, Y12 + VMOVDQU Y15, (DI) + VMOVDQU Y0, 32(DI) + VMOVDQU Y14, 64(DI) + VMOVDQU Y12, 96(DI) + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + VPXOR 128(SI), Y0, Y0 + VPXOR 160(SI), Y14, Y14 + VPXOR 192(SI), Y12, Y12 + VPXOR 224(SI), Y4, Y4 + VMOVDQU Y0, 128(DI) + VMOVDQU Y14, 160(DI) + VMOVDQU Y12, 192(DI) + VMOVDQU Y4, 224(DI) // and here - polyAdd(496(inp)) - polyMulAVX2 - VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 - VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 - VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) - VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 - VPXOR (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0 - VMOVDQU AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup) - LEAQ (32*16)(inp), inp - LEAQ (32*16)(oup), oup - SUBQ $(32*16), inl + ADDQ 496(SI), R10 + ADCQ 504(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + VPXOR 256(SI), Y0, Y0 + VPXOR 288(SI), Y14, Y14 + VPXOR 320(SI), Y12, Y12 + VPXOR 352(SI), Y4, Y4 + VMOVDQU Y0, 256(DI) + VMOVDQU Y14, 288(DI) + VMOVDQU Y12, 320(DI) + VMOVDQU Y4, 352(DI) + VPERM2I128 $0x02, Y7, Y11, Y0 + VPERM2I128 $0x02, 224(BP), Y3, Y14 + VPERM2I128 $0x13, Y7, Y11, Y12 + VPERM2I128 $0x13, 224(BP), Y3, Y4 + VPXOR 384(SI), Y0, Y0 + VPXOR 416(SI), Y14, Y14 + VPXOR 448(SI), Y12, Y12 + VPXOR 480(SI), Y4, Y4 + VMOVDQU Y0, 384(DI) + VMOVDQU Y14, 416(DI) + VMOVDQU Y12, 448(DI) + VMOVDQU Y4, 480(DI) + LEAQ 512(SI), SI + LEAQ 512(DI), DI + SUBQ $0x00000200, BX JMP openAVX2MainLoop openAVX2MainLoopDone: // Handle the various tail sizes efficiently - TESTQ inl, inl + TESTQ BX, BX JE openSSEFinalize - CMPQ inl, $128 + CMPQ BX, $0x80 JBE openAVX2Tail128 - CMPQ inl, $256 + CMPQ BX, $0x00000100 JBE openAVX2Tail256 - CMPQ inl, $384 + CMPQ BX, $0x00000180 JBE openAVX2Tail384 JMP openAVX2Tail512 -// ---------------------------------------------------------------------------- -// Special optimization for buffers smaller than 193 bytes openAVX2192: - // For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks - VMOVDQA AA0, AA1 - VMOVDQA BB0, BB1 - VMOVDQA CC0, CC1 - VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VMOVDQA AA0, AA2 - VMOVDQA BB0, BB2 - VMOVDQA CC0, CC2 - VMOVDQA DD0, DD2 - VMOVDQA DD1, TT3 - MOVQ $10, itr2 + VMOVDQA Y0, Y5 + VMOVDQA Y14, Y9 + VMOVDQA Y12, Y13 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y0, Y6 + VMOVDQA Y14, Y10 + VMOVDQA Y12, Y8 + VMOVDQA Y4, Y2 + VMOVDQA Y1, Y15 + MOVQ $0x0000000a, R9 openAVX2192InnerCipherLoop: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 - DECQ itr2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + DECQ R9 JNE openAVX2192InnerCipherLoop - VPADDD AA2, AA0, AA0; VPADDD AA2, AA1, AA1 - VPADDD BB2, BB0, BB0; VPADDD BB2, BB1, BB1 - VPADDD CC2, CC0, CC0; VPADDD CC2, CC1, CC1 - VPADDD DD2, DD0, DD0; VPADDD TT3, DD1, DD1 - VPERM2I128 $0x02, AA0, BB0, TT0 + VPADDD Y6, Y0, Y0 + VPADDD Y6, Y5, Y5 + VPADDD Y10, Y14, Y14 + VPADDD Y10, Y9, Y9 + VPADDD Y8, Y12, Y12 + VPADDD Y8, Y13, Y13 + VPADDD Y2, Y4, Y4 + VPADDD Y15, Y1, Y1 + VPERM2I128 $0x02, Y0, Y14, Y3 // Clamp and store poly key - VPAND ·polyClampMask<>(SB), TT0, TT0 - VMOVDQA TT0, rsStoreAVX2 + VPAND ·polyClampMask<>+0(SB), Y3, Y3 + VMOVDQA Y3, (BP) // Stream for up to 192 bytes - VPERM2I128 $0x13, AA0, BB0, AA0 - VPERM2I128 $0x13, CC0, DD0, BB0 - VPERM2I128 $0x02, AA1, BB1, CC0 - VPERM2I128 $0x02, CC1, DD1, DD0 - VPERM2I128 $0x13, AA1, BB1, AA1 - VPERM2I128 $0x13, CC1, DD1, BB1 + VPERM2I128 $0x13, Y0, Y14, Y0 + VPERM2I128 $0x13, Y12, Y4, Y14 + VPERM2I128 $0x02, Y5, Y9, Y12 + VPERM2I128 $0x02, Y13, Y1, Y4 + VPERM2I128 $0x13, Y5, Y9, Y5 + VPERM2I128 $0x13, Y13, Y1, Y9 openAVX2ShortOpen: // Hash - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) openAVX2ShortOpenLoop: - CMPQ inl, $32 + CMPQ BX, $0x20 JB openAVX2ShortTail32 - SUBQ $32, inl + SUBQ $0x20, BX // Load for hashing - polyAdd(0*8(inp)) - polyMulAVX2 - polyAdd(2*8(inp)) - polyMulAVX2 + ADDQ (SI), R10 + ADCQ 8(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + ADDQ 16(SI), R10 + ADCQ 24(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 // Load for decryption - VPXOR (inp), AA0, AA0 - VMOVDQU AA0, (oup) - LEAQ (1*32)(inp), inp - LEAQ (1*32)(oup), oup + VPXOR (SI), Y0, Y0 + VMOVDQU Y0, (DI) + LEAQ 32(SI), SI + LEAQ 32(DI), DI // Shift stream left - VMOVDQA BB0, AA0 - VMOVDQA CC0, BB0 - VMOVDQA DD0, CC0 - VMOVDQA AA1, DD0 - VMOVDQA BB1, AA1 - VMOVDQA CC1, BB1 - VMOVDQA DD1, CC1 - VMOVDQA AA2, DD1 - VMOVDQA BB2, AA2 + VMOVDQA Y14, Y0 + VMOVDQA Y12, Y14 + VMOVDQA Y4, Y12 + VMOVDQA Y5, Y4 + VMOVDQA Y9, Y5 + VMOVDQA Y13, Y9 + VMOVDQA Y1, Y13 + VMOVDQA Y6, Y1 + VMOVDQA Y10, Y6 JMP openAVX2ShortOpenLoop openAVX2ShortTail32: - CMPQ inl, $16 - VMOVDQA A0, A1 + CMPQ BX, $0x10 + VMOVDQA X0, X1 JB openAVX2ShortDone - - SUBQ $16, inl + SUBQ $0x10, BX // Load for hashing - polyAdd(0*8(inp)) - polyMulAVX2 + ADDQ (SI), R10 + ADCQ 8(SI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 // Load for decryption - VPXOR (inp), A0, T0 - VMOVDQU T0, (oup) - LEAQ (1*16)(inp), inp - LEAQ (1*16)(oup), oup - VPERM2I128 $0x11, AA0, AA0, AA0 - VMOVDQA A0, A1 + VPXOR (SI), X0, X12 + VMOVDQU X12, (DI) + LEAQ 16(SI), SI + LEAQ 16(DI), DI + VPERM2I128 $0x11, Y0, Y0, Y0 + VMOVDQA X0, X1 openAVX2ShortDone: VZEROUPPER JMP openSSETail16 -// ---------------------------------------------------------------------------- -// Special optimization for buffers smaller than 321 bytes openAVX2320: - // For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks - VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2 - VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3 - MOVQ $10, itr2 + VMOVDQA Y0, Y5 + VMOVDQA Y14, Y9 + VMOVDQA Y12, Y13 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y0, Y6 + VMOVDQA Y14, Y10 + VMOVDQA Y12, Y8 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VMOVDQA Y14, Y7 + VMOVDQA Y12, Y11 + VMOVDQA Y4, Y15 + MOVQ $0x0000000a, R9 openAVX2320InnerCipherLoop: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 - DECQ itr2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + DECQ R9 JNE openAVX2320InnerCipherLoop - - VMOVDQA ·chacha20Constants<>(SB), TT0 - VPADDD TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2 - VPADDD TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2 - VPADDD TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2 - VMOVDQA ·avx2IncMask<>(SB), TT0 - VPADDD TT3, DD0, DD0; VPADDD TT0, TT3, TT3 - VPADDD TT3, DD1, DD1; VPADDD TT0, TT3, TT3 - VPADDD TT3, DD2, DD2 + VMOVDQA ·chacha20Constants<>+0(SB), Y3 + VPADDD Y3, Y0, Y0 + VPADDD Y3, Y5, Y5 + VPADDD Y3, Y6, Y6 + VPADDD Y7, Y14, Y14 + VPADDD Y7, Y9, Y9 + VPADDD Y7, Y10, Y10 + VPADDD Y11, Y12, Y12 + VPADDD Y11, Y13, Y13 + VPADDD Y11, Y8, Y8 + VMOVDQA ·avx2IncMask<>+0(SB), Y3 + VPADDD Y15, Y4, Y4 + VPADDD Y3, Y15, Y15 + VPADDD Y15, Y1, Y1 + VPADDD Y3, Y15, Y15 + VPADDD Y15, Y2, Y2 // Clamp and store poly key - VPERM2I128 $0x02, AA0, BB0, TT0 - VPAND ·polyClampMask<>(SB), TT0, TT0 - VMOVDQA TT0, rsStoreAVX2 + VPERM2I128 $0x02, Y0, Y14, Y3 + VPAND ·polyClampMask<>+0(SB), Y3, Y3 + VMOVDQA Y3, (BP) // Stream for up to 320 bytes - VPERM2I128 $0x13, AA0, BB0, AA0 - VPERM2I128 $0x13, CC0, DD0, BB0 - VPERM2I128 $0x02, AA1, BB1, CC0 - VPERM2I128 $0x02, CC1, DD1, DD0 - VPERM2I128 $0x13, AA1, BB1, AA1 - VPERM2I128 $0x13, CC1, DD1, BB1 - VPERM2I128 $0x02, AA2, BB2, CC1 - VPERM2I128 $0x02, CC2, DD2, DD1 - VPERM2I128 $0x13, AA2, BB2, AA2 - VPERM2I128 $0x13, CC2, DD2, BB2 + VPERM2I128 $0x13, Y0, Y14, Y0 + VPERM2I128 $0x13, Y12, Y4, Y14 + VPERM2I128 $0x02, Y5, Y9, Y12 + VPERM2I128 $0x02, Y13, Y1, Y4 + VPERM2I128 $0x13, Y5, Y9, Y5 + VPERM2I128 $0x13, Y13, Y1, Y9 + VPERM2I128 $0x02, Y6, Y10, Y13 + VPERM2I128 $0x02, Y8, Y2, Y1 + VPERM2I128 $0x13, Y6, Y10, Y6 + VPERM2I128 $0x13, Y8, Y2, Y10 JMP openAVX2ShortOpen -// ---------------------------------------------------------------------------- -// Special optimization for the last 128 bytes of ciphertext openAVX2Tail128: // Need to decrypt up to 128 bytes - prepare two blocks - VMOVDQA ·chacha20Constants<>(SB), AA1 - VMOVDQA state1StoreAVX2, BB1 - VMOVDQA state2StoreAVX2, CC1 - VMOVDQA ctr3StoreAVX2, DD1 - VPADDD ·avx2IncMask<>(SB), DD1, DD1 - VMOVDQA DD1, DD0 - - XORQ itr2, itr2 - MOVQ inl, itr1 - ANDQ $-16, itr1 - TESTQ itr1, itr1 - JE openAVX2Tail128LoopB + VMOVDQA ·chacha20Constants<>+0(SB), Y5 + VMOVDQA 32(BP), Y9 + VMOVDQA 64(BP), Y13 + VMOVDQA 192(BP), Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y1 + VMOVDQA Y1, Y4 + XORQ R9, R9 + MOVQ BX, CX + ANDQ $-16, CX + TESTQ CX, CX + JE openAVX2Tail128LoopB openAVX2Tail128LoopA: - // Perform ChaCha rounds, while hashing the remaining input - polyAdd(0(inp)(itr2*1)) - polyMulAVX2 + ADDQ (SI)(R9*1), R10 + ADCQ 8(SI)(R9*1), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 openAVX2Tail128LoopB: - ADDQ $16, itr2 - chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $4, BB1, BB1, BB1 - VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $12, DD1, DD1, DD1 - chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $12, BB1, BB1, BB1 - VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $4, DD1, DD1, DD1 - CMPQ itr2, itr1 - JB openAVX2Tail128LoopA - CMPQ itr2, $160 - JNE openAVX2Tail128LoopB - - VPADDD ·chacha20Constants<>(SB), AA1, AA1 - VPADDD state1StoreAVX2, BB1, BB1 - VPADDD state2StoreAVX2, CC1, CC1 - VPADDD DD0, DD1, DD1 - VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + ADDQ $0x10, R9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y1, Y1, Y1 + CMPQ R9, CX + JB openAVX2Tail128LoopA + CMPQ R9, $0xa0 + JNE openAVX2Tail128LoopB + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD 32(BP), Y9, Y9 + VPADDD 64(BP), Y13, Y13 + VPADDD Y4, Y1, Y1 + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 openAVX2TailLoop: - CMPQ inl, $32 + CMPQ BX, $0x20 JB openAVX2Tail - SUBQ $32, inl + SUBQ $0x20, BX // Load for decryption - VPXOR (inp), AA0, AA0 - VMOVDQU AA0, (oup) - LEAQ (1*32)(inp), inp - LEAQ (1*32)(oup), oup - VMOVDQA BB0, AA0 - VMOVDQA CC0, BB0 - VMOVDQA DD0, CC0 + VPXOR (SI), Y0, Y0 + VMOVDQU Y0, (DI) + LEAQ 32(SI), SI + LEAQ 32(DI), DI + VMOVDQA Y14, Y0 + VMOVDQA Y12, Y14 + VMOVDQA Y4, Y12 JMP openAVX2TailLoop openAVX2Tail: - CMPQ inl, $16 - VMOVDQA A0, A1 + CMPQ BX, $0x10 + VMOVDQA X0, X1 JB openAVX2TailDone - SUBQ $16, inl + SUBQ $0x10, BX // Load for decryption - VPXOR (inp), A0, T0 - VMOVDQU T0, (oup) - LEAQ (1*16)(inp), inp - LEAQ (1*16)(oup), oup - VPERM2I128 $0x11, AA0, AA0, AA0 - VMOVDQA A0, A1 + VPXOR (SI), X0, X12 + VMOVDQU X12, (DI) + LEAQ 16(SI), SI + LEAQ 16(DI), DI + VPERM2I128 $0x11, Y0, Y0, Y0 + VMOVDQA X0, X1 openAVX2TailDone: VZEROUPPER JMP openSSETail16 -// ---------------------------------------------------------------------------- -// Special optimization for the last 256 bytes of ciphertext openAVX2Tail256: - // Need to decrypt up to 256 bytes - prepare four blocks - VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VMOVDQA DD0, TT1 - VMOVDQA DD1, TT2 + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y4, Y7 + VMOVDQA Y1, Y11 // Compute the number of iterations that will hash data - MOVQ inl, tmpStoreAVX2 - MOVQ inl, itr1 - SUBQ $128, itr1 - SHRQ $4, itr1 - MOVQ $10, itr2 - CMPQ itr1, $10 - CMOVQGT itr2, itr1 - MOVQ inp, inl - XORQ itr2, itr2 + MOVQ BX, 224(BP) + MOVQ BX, CX + SUBQ $0x80, CX + SHRQ $0x04, CX + MOVQ $0x0000000a, R9 + CMPQ CX, $0x0a + CMOVQGT R9, CX + MOVQ SI, BX + XORQ R9, R9 openAVX2Tail256LoopA: - polyAdd(0(inl)) - polyMulAVX2 - LEAQ 16(inl), inl + ADDQ (BX), R10 + ADCQ 8(BX), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(BX), BX - // Perform ChaCha rounds, while hashing the remaining input openAVX2Tail256LoopB: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 - INCQ itr2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 - CMPQ itr2, itr1 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + INCQ R9 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + CMPQ R9, CX JB openAVX2Tail256LoopA + CMPQ R9, $0x0a + JNE openAVX2Tail256LoopB + MOVQ BX, R9 + SUBQ SI, BX + MOVQ BX, CX + MOVQ 224(BP), BX - CMPQ itr2, $10 - JNE openAVX2Tail256LoopB - - MOVQ inl, itr2 - SUBQ inp, inl - MOVQ inl, itr1 - MOVQ tmpStoreAVX2, inl - - // Hash the remainder of data (if any) openAVX2Tail256Hash: - ADDQ $16, itr1 - CMPQ itr1, inl - JGT openAVX2Tail256HashEnd - polyAdd (0(itr2)) - polyMulAVX2 - LEAQ 16(itr2), itr2 - JMP openAVX2Tail256Hash - -// Store 128 bytes safely, then go to store loop + ADDQ $0x10, CX + CMPQ CX, BX + JGT openAVX2Tail256HashEnd + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(R9), R9 + JMP openAVX2Tail256Hash + openAVX2Tail256HashEnd: - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1 - VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1 - VPERM2I128 $0x02, AA0, BB0, AA2; VPERM2I128 $0x02, CC0, DD0, BB2; VPERM2I128 $0x13, AA0, BB0, CC2; VPERM2I128 $0x13, CC0, DD0, DD2 - VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 - - VPXOR (0*32)(inp), AA2, AA2; VPXOR (1*32)(inp), BB2, BB2; VPXOR (2*32)(inp), CC2, CC2; VPXOR (3*32)(inp), DD2, DD2 - VMOVDQU AA2, (0*32)(oup); VMOVDQU BB2, (1*32)(oup); VMOVDQU CC2, (2*32)(oup); VMOVDQU DD2, (3*32)(oup) - LEAQ (4*32)(inp), inp - LEAQ (4*32)(oup), oup - SUBQ $4*32, inl - - JMP openAVX2TailLoop - -// ---------------------------------------------------------------------------- -// Special optimization for the last 384 bytes of ciphertext + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD Y7, Y4, Y4 + VPADDD Y11, Y1, Y1 + VPERM2I128 $0x02, Y0, Y14, Y6 + VPERM2I128 $0x02, Y12, Y4, Y10 + VPERM2I128 $0x13, Y0, Y14, Y8 + VPERM2I128 $0x13, Y12, Y4, Y2 + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + VPXOR (SI), Y6, Y6 + VPXOR 32(SI), Y10, Y10 + VPXOR 64(SI), Y8, Y8 + VPXOR 96(SI), Y2, Y2 + VMOVDQU Y6, (DI) + VMOVDQU Y10, 32(DI) + VMOVDQU Y8, 64(DI) + VMOVDQU Y2, 96(DI) + LEAQ 128(SI), SI + LEAQ 128(DI), DI + SUBQ $0x80, BX + JMP openAVX2TailLoop + openAVX2Tail384: // Need to decrypt up to 384 bytes - prepare six blocks - VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VPADDD ·avx2IncMask<>(SB), DD1, DD2 - VMOVDQA DD0, ctr0StoreAVX2 - VMOVDQA DD1, ctr1StoreAVX2 - VMOVDQA DD2, ctr2StoreAVX2 + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VMOVDQA Y4, 96(BP) + VMOVDQA Y1, 128(BP) + VMOVDQA Y2, 160(BP) // Compute the number of iterations that will hash two blocks of data - MOVQ inl, tmpStoreAVX2 - MOVQ inl, itr1 - SUBQ $256, itr1 - SHRQ $4, itr1 - ADDQ $6, itr1 - MOVQ $10, itr2 - CMPQ itr1, $10 - CMOVQGT itr2, itr1 - MOVQ inp, inl - XORQ itr2, itr2 - - // Perform ChaCha rounds, while hashing the remaining input + MOVQ BX, 224(BP) + MOVQ BX, CX + SUBQ $0x00000100, CX + SHRQ $0x04, CX + ADDQ $0x06, CX + MOVQ $0x0000000a, R9 + CMPQ CX, $0x0a + CMOVQGT R9, CX + MOVQ SI, BX + XORQ R9, R9 + openAVX2Tail384LoopB: - polyAdd(0(inl)) - polyMulAVX2 - LEAQ 16(inl), inl + ADDQ (BX), R10 + ADCQ 8(BX), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(BX), BX openAVX2Tail384LoopA: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 - polyAdd(0(inl)) - polyMulAVX2 - LEAQ 16(inl), inl - INCQ itr2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 - - CMPQ itr2, itr1 - JB openAVX2Tail384LoopB - - CMPQ itr2, $10 - JNE openAVX2Tail384LoopA - - MOVQ inl, itr2 - SUBQ inp, inl - MOVQ inl, itr1 - MOVQ tmpStoreAVX2, inl + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + ADDQ (BX), R10 + ADCQ 8(BX), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(BX), BX + INCQ R9 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + CMPQ R9, CX + JB openAVX2Tail384LoopB + CMPQ R9, $0x0a + JNE openAVX2Tail384LoopA + MOVQ BX, R9 + SUBQ SI, BX + MOVQ BX, CX + MOVQ 224(BP), BX openAVX2Tail384Hash: - ADDQ $16, itr1 - CMPQ itr1, inl - JGT openAVX2Tail384HashEnd - polyAdd(0(itr2)) - polyMulAVX2 - LEAQ 16(itr2), itr2 - JMP openAVX2Tail384Hash - -// Store 256 bytes safely, then go to store loop + ADDQ $0x10, CX + CMPQ CX, BX + JGT openAVX2Tail384HashEnd + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(R9), R9 + JMP openAVX2Tail384Hash + openAVX2Tail384HashEnd: - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2 - VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2 - VPERM2I128 $0x02, AA0, BB0, TT0; VPERM2I128 $0x02, CC0, DD0, TT1; VPERM2I128 $0x13, AA0, BB0, TT2; VPERM2I128 $0x13, CC0, DD0, TT3 - VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3 - VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup) - VPERM2I128 $0x02, AA1, BB1, TT0; VPERM2I128 $0x02, CC1, DD1, TT1; VPERM2I128 $0x13, AA1, BB1, TT2; VPERM2I128 $0x13, CC1, DD1, TT3 - VPXOR (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3 - VMOVDQU TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup) - VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 - LEAQ (8*32)(inp), inp - LEAQ (8*32)(oup), oup - SUBQ $8*32, inl + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD 96(BP), Y4, Y4 + VPADDD 128(BP), Y1, Y1 + VPADDD 160(BP), Y2, Y2 + VPERM2I128 $0x02, Y0, Y14, Y3 + VPERM2I128 $0x02, Y12, Y4, Y7 + VPERM2I128 $0x13, Y0, Y14, Y11 + VPERM2I128 $0x13, Y12, Y4, Y15 + VPXOR (SI), Y3, Y3 + VPXOR 32(SI), Y7, Y7 + VPXOR 64(SI), Y11, Y11 + VPXOR 96(SI), Y15, Y15 + VMOVDQU Y3, (DI) + VMOVDQU Y7, 32(DI) + VMOVDQU Y11, 64(DI) + VMOVDQU Y15, 96(DI) + VPERM2I128 $0x02, Y5, Y9, Y3 + VPERM2I128 $0x02, Y13, Y1, Y7 + VPERM2I128 $0x13, Y5, Y9, Y11 + VPERM2I128 $0x13, Y13, Y1, Y15 + VPXOR 128(SI), Y3, Y3 + VPXOR 160(SI), Y7, Y7 + VPXOR 192(SI), Y11, Y11 + VPXOR 224(SI), Y15, Y15 + VMOVDQU Y3, 128(DI) + VMOVDQU Y7, 160(DI) + VMOVDQU Y11, 192(DI) + VMOVDQU Y15, 224(DI) + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + LEAQ 256(SI), SI + LEAQ 256(DI), DI + SUBQ $0x00000100, BX JMP openAVX2TailLoop -// ---------------------------------------------------------------------------- -// Special optimization for the last 512 bytes of ciphertext openAVX2Tail512: - VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 - VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 - VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 - XORQ itr1, itr1 - MOVQ inp, itr2 + VMOVDQU ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA Y0, Y7 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA Y14, Y11 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA Y12, Y15 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VPADDD ·avx2IncMask<>+0(SB), Y2, Y3 + VMOVDQA Y4, 96(BP) + VMOVDQA Y1, 128(BP) + VMOVDQA Y2, 160(BP) + VMOVDQA Y3, 192(BP) + XORQ CX, CX + MOVQ SI, R9 openAVX2Tail512LoopB: - polyAdd(0(itr2)) - polyMulAVX2 - LEAQ (2*8)(itr2), itr2 + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(R9), R9 openAVX2Tail512LoopA: - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyAdd(0*8(itr2)) - polyMulAVX2 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - polyAdd(2*8(itr2)) - polyMulAVX2 - LEAQ (4*8)(itr2), itr2 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 - INCQ itr1 - CMPQ itr1, $4 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x04, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPALIGNR $0x0c, Y3, Y3, Y3 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + ADDQ 16(R9), R10 + ADCQ 24(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(R9), R9 + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x0c, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + VPALIGNR $0x04, Y3, Y3, Y3 + INCQ CX + CMPQ CX, $0x04 JLT openAVX2Tail512LoopB - - CMPQ itr1, $10 - JNE openAVX2Tail512LoopA - - MOVQ inl, itr1 - SUBQ $384, itr1 - ANDQ $-16, itr1 + CMPQ CX, $0x0a + JNE openAVX2Tail512LoopA + MOVQ BX, CX + SUBQ $0x00000180, CX + ANDQ $-16, CX openAVX2Tail512HashLoop: - TESTQ itr1, itr1 + TESTQ CX, CX JE openAVX2Tail512HashEnd - polyAdd(0(itr2)) - polyMulAVX2 - LEAQ 16(itr2), itr2 - SUBQ $16, itr1 + ADDQ (R9), R10 + ADCQ 8(R9), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(R9), R9 + SUBQ $0x10, CX JMP openAVX2Tail512HashLoop openAVX2Tail512HashEnd: - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 - VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 - VMOVDQA CC3, tmpStoreAVX2 - VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0 - VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0 - VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup) - VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 - VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 - VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) - VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 - VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 - VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) - VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 - - LEAQ (12*32)(inp), inp - LEAQ (12*32)(oup), oup - SUBQ $12*32, inl - - JMP openAVX2TailLoop - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- -// func chacha20Poly1305Seal(dst, key, src, ad []byte) -TEXT ·chacha20Poly1305Seal(SB), 0, $288-96 - // For aligned stack access + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD ·chacha20Constants<>+0(SB), Y7, Y7 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 32(BP), Y11, Y11 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD 64(BP), Y15, Y15 + VPADDD 96(BP), Y4, Y4 + VPADDD 128(BP), Y1, Y1 + VPADDD 160(BP), Y2, Y2 + VPADDD 192(BP), Y3, Y3 + VMOVDQA Y15, 224(BP) + VPERM2I128 $0x02, Y0, Y14, Y15 + VPERM2I128 $0x13, Y0, Y14, Y14 + VPERM2I128 $0x02, Y12, Y4, Y0 + VPERM2I128 $0x13, Y12, Y4, Y12 + VPXOR (SI), Y15, Y15 + VPXOR 32(SI), Y0, Y0 + VPXOR 64(SI), Y14, Y14 + VPXOR 96(SI), Y12, Y12 + VMOVDQU Y15, (DI) + VMOVDQU Y0, 32(DI) + VMOVDQU Y14, 64(DI) + VMOVDQU Y12, 96(DI) + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + VPXOR 128(SI), Y0, Y0 + VPXOR 160(SI), Y14, Y14 + VPXOR 192(SI), Y12, Y12 + VPXOR 224(SI), Y4, Y4 + VMOVDQU Y0, 128(DI) + VMOVDQU Y14, 160(DI) + VMOVDQU Y12, 192(DI) + VMOVDQU Y4, 224(DI) + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + VPXOR 256(SI), Y0, Y0 + VPXOR 288(SI), Y14, Y14 + VPXOR 320(SI), Y12, Y12 + VPXOR 352(SI), Y4, Y4 + VMOVDQU Y0, 256(DI) + VMOVDQU Y14, 288(DI) + VMOVDQU Y12, 320(DI) + VMOVDQU Y4, 352(DI) + VPERM2I128 $0x02, Y7, Y11, Y0 + VPERM2I128 $0x02, 224(BP), Y3, Y14 + VPERM2I128 $0x13, Y7, Y11, Y12 + VPERM2I128 $0x13, 224(BP), Y3, Y4 + LEAQ 384(SI), SI + LEAQ 384(DI), DI + SUBQ $0x00000180, BX + JMP openAVX2TailLoop + +DATA ·chacha20Constants<>+0(SB)/4, $0x61707865 +DATA ·chacha20Constants<>+4(SB)/4, $0x3320646e +DATA ·chacha20Constants<>+8(SB)/4, $0x79622d32 +DATA ·chacha20Constants<>+12(SB)/4, $0x6b206574 +DATA ·chacha20Constants<>+16(SB)/4, $0x61707865 +DATA ·chacha20Constants<>+20(SB)/4, $0x3320646e +DATA ·chacha20Constants<>+24(SB)/4, $0x79622d32 +DATA ·chacha20Constants<>+28(SB)/4, $0x6b206574 +GLOBL ·chacha20Constants<>(SB), RODATA|NOPTR, $32 + +DATA ·polyClampMask<>+0(SB)/8, $0x0ffffffc0fffffff +DATA ·polyClampMask<>+8(SB)/8, $0x0ffffffc0ffffffc +DATA ·polyClampMask<>+16(SB)/8, $0xffffffffffffffff +DATA ·polyClampMask<>+24(SB)/8, $0xffffffffffffffff +GLOBL ·polyClampMask<>(SB), RODATA|NOPTR, $32 + +DATA ·sseIncMask<>+0(SB)/8, $0x0000000000000001 +DATA ·sseIncMask<>+8(SB)/8, $0x0000000000000000 +GLOBL ·sseIncMask<>(SB), RODATA|NOPTR, $16 + +DATA ·andMask<>+0(SB)/8, $0x00000000000000ff +DATA ·andMask<>+8(SB)/8, $0x0000000000000000 +DATA ·andMask<>+16(SB)/8, $0x000000000000ffff +DATA ·andMask<>+24(SB)/8, $0x0000000000000000 +DATA ·andMask<>+32(SB)/8, $0x0000000000ffffff +DATA ·andMask<>+40(SB)/8, $0x0000000000000000 +DATA ·andMask<>+48(SB)/8, $0x00000000ffffffff +DATA ·andMask<>+56(SB)/8, $0x0000000000000000 +DATA ·andMask<>+64(SB)/8, $0x000000ffffffffff +DATA ·andMask<>+72(SB)/8, $0x0000000000000000 +DATA ·andMask<>+80(SB)/8, $0x0000ffffffffffff +DATA ·andMask<>+88(SB)/8, $0x0000000000000000 +DATA ·andMask<>+96(SB)/8, $0x00ffffffffffffff +DATA ·andMask<>+104(SB)/8, $0x0000000000000000 +DATA ·andMask<>+112(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+120(SB)/8, $0x0000000000000000 +DATA ·andMask<>+128(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+136(SB)/8, $0x00000000000000ff +DATA ·andMask<>+144(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+152(SB)/8, $0x000000000000ffff +DATA ·andMask<>+160(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+168(SB)/8, $0x0000000000ffffff +DATA ·andMask<>+176(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+184(SB)/8, $0x00000000ffffffff +DATA ·andMask<>+192(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+200(SB)/8, $0x000000ffffffffff +DATA ·andMask<>+208(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+216(SB)/8, $0x0000ffffffffffff +DATA ·andMask<>+224(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+232(SB)/8, $0x00ffffffffffffff +GLOBL ·andMask<>(SB), RODATA|NOPTR, $240 + +DATA ·avx2InitMask<>+0(SB)/8, $0x0000000000000000 +DATA ·avx2InitMask<>+8(SB)/8, $0x0000000000000000 +DATA ·avx2InitMask<>+16(SB)/8, $0x0000000000000001 +DATA ·avx2InitMask<>+24(SB)/8, $0x0000000000000000 +GLOBL ·avx2InitMask<>(SB), RODATA|NOPTR, $32 + +DATA ·rol16<>+0(SB)/8, $0x0504070601000302 +DATA ·rol16<>+8(SB)/8, $0x0d0c0f0e09080b0a +DATA ·rol16<>+16(SB)/8, $0x0504070601000302 +DATA ·rol16<>+24(SB)/8, $0x0d0c0f0e09080b0a +GLOBL ·rol16<>(SB), RODATA|NOPTR, $32 + +DATA ·rol8<>+0(SB)/8, $0x0605040702010003 +DATA ·rol8<>+8(SB)/8, $0x0e0d0c0f0a09080b +DATA ·rol8<>+16(SB)/8, $0x0605040702010003 +DATA ·rol8<>+24(SB)/8, $0x0e0d0c0f0a09080b +GLOBL ·rol8<>(SB), RODATA|NOPTR, $32 + +DATA ·avx2IncMask<>+0(SB)/8, $0x0000000000000002 +DATA ·avx2IncMask<>+8(SB)/8, $0x0000000000000000 +DATA ·avx2IncMask<>+16(SB)/8, $0x0000000000000002 +DATA ·avx2IncMask<>+24(SB)/8, $0x0000000000000000 +GLOBL ·avx2IncMask<>(SB), RODATA|NOPTR, $32 + +// func chacha20Poly1305Seal(dst []byte, key []uint32, src []byte, ad []byte) +// Requires: AVX, AVX2, BMI2, CMOV, SSE2 +TEXT ·chacha20Poly1305Seal(SB), $288-96 MOVQ SP, BP - ADDQ $32, BP + ADDQ $0x20, BP ANDQ $-32, BP - MOVQ dst+0(FP), oup - MOVQ key+24(FP), keyp - MOVQ src+48(FP), inp - MOVQ src_len+56(FP), inl - MOVQ ad+72(FP), adp - - CMPB ·useAVX2(SB), $1 + MOVQ dst_base+0(FP), DI + MOVQ key_base+24(FP), R8 + MOVQ src_base+48(FP), SI + MOVQ src_len+56(FP), BX + MOVQ ad_base+72(FP), CX + CMPB ·useAVX2+0(SB), $0x01 JE chacha20Poly1305Seal_AVX2 // Special optimization, for very short buffers - CMPQ inl, $128 - JBE sealSSE128 // About 15% faster + CMPQ BX, $0x80 + JBE sealSSE128 // In the seal case - prepare the poly key + 3 blocks of stream in the first iteration - MOVOU ·chacha20Constants<>(SB), A0 - MOVOU (1*16)(keyp), B0 - MOVOU (2*16)(keyp), C0 - MOVOU (3*16)(keyp), D0 + MOVOU ·chacha20Constants<>+0(SB), X0 + MOVOU 16(R8), X3 + MOVOU 32(R8), X6 + MOVOU 48(R8), X9 // Store state on stack for future use - MOVO B0, state1Store - MOVO C0, state2Store + MOVO X3, 32(BP) + MOVO X6, 48(BP) // Load state, increment counter blocks - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 - MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X2, X12 + MOVO X5, X13 + MOVO X8, X14 + MOVO X11, X15 + PADDL ·sseIncMask<>+0(SB), X15 // Store counters - MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store - MOVQ $10, itr2 + MOVO X9, 80(BP) + MOVO X10, 96(BP) + MOVO X11, 112(BP) + MOVO X15, 128(BP) + MOVQ $0x0000000a, R9 sealSSEIntroLoop: - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left - shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left - shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left - - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right - shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right - shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right - DECQ itr2 - JNE sealSSEIntroLoop + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x0c + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x04 + DECQ R9 + JNE sealSSEIntroLoop // Add in the state - PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 - PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 - PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 - PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 + PADDD ·chacha20Constants<>+0(SB), X0 + PADDD ·chacha20Constants<>+0(SB), X1 + PADDD ·chacha20Constants<>+0(SB), X2 + PADDD ·chacha20Constants<>+0(SB), X12 + PADDD 32(BP), X3 + PADDD 32(BP), X4 + PADDD 32(BP), X5 + PADDD 32(BP), X13 + PADDD 48(BP), X7 + PADDD 48(BP), X8 + PADDD 48(BP), X14 + PADDD 96(BP), X10 + PADDD 112(BP), X11 + PADDD 128(BP), X15 // Clamp and store the key - PAND ·polyClampMask<>(SB), A0 - MOVO A0, rStore - MOVO B0, sStore + PAND ·polyClampMask<>+0(SB), X0 + MOVO X0, (BP) + MOVO X3, 16(BP) // Hash AAD - MOVQ ad_len+80(FP), itr2 - CALL polyHashADInternal<>(SB) - - MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0 - PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1 - MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup) - MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0 - PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2 - MOVOU A2, (4*16)(oup); MOVOU B2, (5*16)(oup); MOVOU C2, (6*16)(oup); MOVOU D2, (7*16)(oup) - - MOVQ $128, itr1 - SUBQ $128, inl - LEAQ 128(inp), inp - - MOVO A3, A1; MOVO B3, B1; MOVO C3, C1; MOVO D3, D1 - - CMPQ inl, $64 - JBE sealSSE128SealHash - - MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0 - PXOR A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3 - MOVOU A3, (8*16)(oup); MOVOU B3, (9*16)(oup); MOVOU C3, (10*16)(oup); MOVOU D3, (11*16)(oup) - - ADDQ $64, itr1 - SUBQ $64, inl - LEAQ 64(inp), inp - - MOVQ $2, itr1 - MOVQ $8, itr2 - - CMPQ inl, $64 - JBE sealSSETail64 - CMPQ inl, $128 - JBE sealSSETail128 - CMPQ inl, $192 - JBE sealSSETail192 + MOVQ ad_len+80(FP), R9 + CALL polyHashADInternal<>(SB) + MOVOU (SI), X0 + MOVOU 16(SI), X3 + MOVOU 32(SI), X6 + MOVOU 48(SI), X9 + PXOR X0, X1 + PXOR X3, X4 + PXOR X6, X7 + PXOR X9, X10 + MOVOU X1, (DI) + MOVOU X4, 16(DI) + MOVOU X7, 32(DI) + MOVOU X10, 48(DI) + MOVOU 64(SI), X0 + MOVOU 80(SI), X3 + MOVOU 96(SI), X6 + MOVOU 112(SI), X9 + PXOR X0, X2 + PXOR X3, X5 + PXOR X6, X8 + PXOR X9, X11 + MOVOU X2, 64(DI) + MOVOU X5, 80(DI) + MOVOU X8, 96(DI) + MOVOU X11, 112(DI) + MOVQ $0x00000080, CX + SUBQ $0x80, BX + LEAQ 128(SI), SI + MOVO X12, X1 + MOVO X13, X4 + MOVO X14, X7 + MOVO X15, X10 + CMPQ BX, $0x40 + JBE sealSSE128SealHash + MOVOU (SI), X0 + MOVOU 16(SI), X3 + MOVOU 32(SI), X6 + MOVOU 48(SI), X9 + PXOR X0, X12 + PXOR X3, X13 + PXOR X6, X14 + PXOR X9, X15 + MOVOU X12, 128(DI) + MOVOU X13, 144(DI) + MOVOU X14, 160(DI) + MOVOU X15, 176(DI) + ADDQ $0x40, CX + SUBQ $0x40, BX + LEAQ 64(SI), SI + MOVQ $0x00000002, CX + MOVQ $0x00000008, R9 + CMPQ BX, $0x40 + JBE sealSSETail64 + CMPQ BX, $0x80 + JBE sealSSETail128 + CMPQ BX, $0xc0 + JBE sealSSETail192 sealSSEMainLoop: // Load state, increment counter blocks - MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0 - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 - MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + MOVO ·chacha20Constants<>+0(SB), X0 + MOVO 32(BP), X3 + MOVO 48(BP), X6 + MOVO 128(BP), X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X2, X12 + MOVO X5, X13 + MOVO X8, X14 + MOVO X11, X15 + PADDL ·sseIncMask<>+0(SB), X15 // Store counters - MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store + MOVO X9, 80(BP) + MOVO X10, 96(BP) + MOVO X11, 112(BP) + MOVO X15, 128(BP) sealSSEInnerLoop: - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - polyAdd(0(oup)) - shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left - shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left - shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left - polyMulStage1 - polyMulStage2 - LEAQ (2*8)(oup), oup - MOVO C3, tmpStore - chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) - MOVO tmpStore, C3 - MOVO C1, tmpStore - polyMulStage3 - chachaQR(A3, B3, C3, D3, C1) - MOVO tmpStore, C1 - polyMulReduceStage - shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right - shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right - shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right - DECQ itr2 - JGE sealSSEInnerLoop - polyAdd(0(oup)) - polyMul - LEAQ (2*8)(oup), oup - DECQ itr1 - JG sealSSEInnerLoop + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x0c + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + LEAQ 16(DI), DI + MOVO X14, 64(BP) + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X3 + PXOR X14, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X14) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X3 + PXOR X14, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X4 + PXOR X14, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X14) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X4 + PXOR X14, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x0c, X14 + PSRLL $0x14, X5 + PXOR X14, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X14) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X14 + PSLLL $0x07, X14 + PSRLL $0x19, X5 + PXOR X14, X5 + MOVO 64(BP), X14 + MOVO X7, 64(BP) + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + PADDD X13, X12 + PXOR X12, X15 + ROL16(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x0c, X7 + PSRLL $0x14, X13 + PXOR X7, X13 + PADDD X13, X12 + PXOR X12, X15 + ROL8(X15, X7) + PADDD X15, X14 + PXOR X14, X13 + MOVO X13, X7 + PSLLL $0x07, X7 + PSRLL $0x19, X13 + PXOR X7, X13 + MOVO 64(BP), X7 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x04 + DECQ R9 + JGE sealSSEInnerLoop + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI + DECQ CX + JG sealSSEInnerLoop // Add in the state - PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 - PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 - PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 - PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 - MOVO D3, tmpStore + PADDD ·chacha20Constants<>+0(SB), X0 + PADDD ·chacha20Constants<>+0(SB), X1 + PADDD ·chacha20Constants<>+0(SB), X2 + PADDD ·chacha20Constants<>+0(SB), X12 + PADDD 32(BP), X3 + PADDD 32(BP), X4 + PADDD 32(BP), X5 + PADDD 32(BP), X13 + PADDD 48(BP), X6 + PADDD 48(BP), X7 + PADDD 48(BP), X8 + PADDD 48(BP), X14 + PADDD 80(BP), X9 + PADDD 96(BP), X10 + PADDD 112(BP), X11 + PADDD 128(BP), X15 + MOVO X15, 64(BP) // Load - xor - store - MOVOU (0*16)(inp), D3; PXOR D3, A0 - MOVOU (1*16)(inp), D3; PXOR D3, B0 - MOVOU (2*16)(inp), D3; PXOR D3, C0 - MOVOU (3*16)(inp), D3; PXOR D3, D0 - MOVOU A0, (0*16)(oup) - MOVOU B0, (1*16)(oup) - MOVOU C0, (2*16)(oup) - MOVOU D0, (3*16)(oup) - MOVO tmpStore, D3 - - MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0 - PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1 - MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) - MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0 - PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2 - MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup) - ADDQ $192, inp - MOVQ $192, itr1 - SUBQ $192, inl - MOVO A3, A1 - MOVO B3, B1 - MOVO C3, C1 - MOVO D3, D1 - CMPQ inl, $64 + MOVOU (SI), X15 + PXOR X15, X0 + MOVOU 16(SI), X15 + PXOR X15, X3 + MOVOU 32(SI), X15 + PXOR X15, X6 + MOVOU 48(SI), X15 + PXOR X15, X9 + MOVOU X0, (DI) + MOVOU X3, 16(DI) + MOVOU X6, 32(DI) + MOVOU X9, 48(DI) + MOVO 64(BP), X15 + MOVOU 64(SI), X0 + MOVOU 80(SI), X3 + MOVOU 96(SI), X6 + MOVOU 112(SI), X9 + PXOR X0, X1 + PXOR X3, X4 + PXOR X6, X7 + PXOR X9, X10 + MOVOU X1, 64(DI) + MOVOU X4, 80(DI) + MOVOU X7, 96(DI) + MOVOU X10, 112(DI) + MOVOU 128(SI), X0 + MOVOU 144(SI), X3 + MOVOU 160(SI), X6 + MOVOU 176(SI), X9 + PXOR X0, X2 + PXOR X3, X5 + PXOR X6, X8 + PXOR X9, X11 + MOVOU X2, 128(DI) + MOVOU X5, 144(DI) + MOVOU X8, 160(DI) + MOVOU X11, 176(DI) + ADDQ $0xc0, SI + MOVQ $0x000000c0, CX + SUBQ $0xc0, BX + MOVO X12, X1 + MOVO X13, X4 + MOVO X14, X7 + MOVO X15, X10 + CMPQ BX, $0x40 JBE sealSSE128SealHash - MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0 - PXOR A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3 - MOVOU A3, (12*16)(oup); MOVOU B3, (13*16)(oup); MOVOU C3, (14*16)(oup); MOVOU D3, (15*16)(oup) - LEAQ 64(inp), inp - SUBQ $64, inl - MOVQ $6, itr1 - MOVQ $4, itr2 - CMPQ inl, $192 + MOVOU (SI), X0 + MOVOU 16(SI), X3 + MOVOU 32(SI), X6 + MOVOU 48(SI), X9 + PXOR X0, X12 + PXOR X3, X13 + PXOR X6, X14 + PXOR X9, X15 + MOVOU X12, 192(DI) + MOVOU X13, 208(DI) + MOVOU X14, 224(DI) + MOVOU X15, 240(DI) + LEAQ 64(SI), SI + SUBQ $0x40, BX + MOVQ $0x00000006, CX + MOVQ $0x00000004, R9 + CMPQ BX, $0xc0 JG sealSSEMainLoop - - MOVQ inl, itr1 - TESTQ inl, inl + MOVQ BX, CX + TESTQ BX, BX JE sealSSE128SealHash - MOVQ $6, itr1 - CMPQ inl, $64 + MOVQ $0x00000006, CX + CMPQ BX, $0x40 JBE sealSSETail64 - CMPQ inl, $128 + CMPQ BX, $0x80 JBE sealSSETail128 JMP sealSSETail192 -// ---------------------------------------------------------------------------- -// Special optimization for the last 64 bytes of plaintext sealSSETail64: - // Need to encrypt up to 64 bytes - prepare single block, hash 192 or 256 bytes - MOVO ·chacha20Constants<>(SB), A1 - MOVO state1Store, B1 - MOVO state2Store, C1 - MOVO ctr3Store, D1 - PADDL ·sseIncMask<>(SB), D1 - MOVO D1, ctr0Store + MOVO ·chacha20Constants<>+0(SB), X1 + MOVO 32(BP), X4 + MOVO 48(BP), X7 + MOVO 128(BP), X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X10, 80(BP) sealSSETail64LoopA: - // Perform ChaCha rounds, while hashing the previously encrypted ciphertext - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealSSETail64LoopB: - chachaQR(A1, B1, C1, D1, T1) - shiftB1Left; shiftC1Left; shiftD1Left - chachaQR(A1, B1, C1, D1, T1) - shiftB1Right; shiftC1Right; shiftD1Right - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup - - DECQ itr1 - JG sealSSETail64LoopA - - DECQ itr2 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X13) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X13 + PSLLL $0x0c, X13 + PSRLL $0x14, X4 + PXOR X13, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X13) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X13 + PSLLL $0x07, X13 + PSRLL $0x19, X4 + PXOR X13, X4 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X13) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X13 + PSLLL $0x0c, X13 + PSRLL $0x14, X4 + PXOR X13, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X13) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X13 + PSLLL $0x07, X13 + PSRLL $0x19, X4 + PXOR X13, X4 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI + DECQ CX + JG sealSSETail64LoopA + DECQ R9 JGE sealSSETail64LoopB - PADDL ·chacha20Constants<>(SB), A1 - PADDL state1Store, B1 - PADDL state2Store, C1 - PADDL ctr0Store, D1 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL 32(BP), X4 + PADDL 48(BP), X7 + PADDL 80(BP), X10 + JMP sealSSE128Seal - JMP sealSSE128Seal - -// ---------------------------------------------------------------------------- -// Special optimization for the last 128 bytes of plaintext sealSSETail128: - // Need to encrypt up to 128 bytes - prepare two blocks, hash 192 or 256 bytes - MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store + MOVO ·chacha20Constants<>+0(SB), X0 + MOVO 32(BP), X3 + MOVO 48(BP), X6 + MOVO 128(BP), X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X9, 80(BP) + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X10, 96(BP) sealSSETail128LoopA: - // Perform ChaCha rounds, while hashing the previously encrypted ciphertext - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealSSETail128LoopB: - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) - shiftB0Left; shiftC0Left; shiftD0Left - shiftB1Left; shiftC1Left; shiftD1Left - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) - shiftB0Right; shiftC0Right; shiftD0Right - shiftB1Right; shiftC1Right; shiftD1Right - - DECQ itr1 - JG sealSSETail128LoopA - - DECQ itr2 - JGE sealSSETail128LoopB - - PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1 - PADDL state1Store, B0; PADDL state1Store, B1 - PADDL state2Store, C0; PADDL state2Store, C1 - PADDL ctr0Store, D0; PADDL ctr1Store, D1 - - MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 - PXOR T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0 - MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup) - - MOVQ $64, itr1 - LEAQ 64(inp), inp - SUBQ $64, inl - - JMP sealSSE128SealHash - -// ---------------------------------------------------------------------------- -// Special optimization for the last 192 bytes of plaintext + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + DECQ CX + JG sealSSETail128LoopA + DECQ R9 + JGE sealSSETail128LoopB + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL 32(BP), X3 + PADDL 32(BP), X4 + PADDL 48(BP), X6 + PADDL 48(BP), X7 + PADDL 80(BP), X9 + PADDL 96(BP), X10 + MOVOU (SI), X12 + MOVOU 16(SI), X13 + MOVOU 32(SI), X14 + MOVOU 48(SI), X15 + PXOR X12, X0 + PXOR X13, X3 + PXOR X14, X6 + PXOR X15, X9 + MOVOU X0, (DI) + MOVOU X3, 16(DI) + MOVOU X6, 32(DI) + MOVOU X9, 48(DI) + MOVQ $0x00000040, CX + LEAQ 64(SI), SI + SUBQ $0x40, BX + JMP sealSSE128SealHash + sealSSETail192: - // Need to encrypt up to 192 bytes - prepare three blocks, hash 192 or 256 bytes - MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr2Store + MOVO ·chacha20Constants<>+0(SB), X0 + MOVO 32(BP), X3 + MOVO 48(BP), X6 + MOVO 128(BP), X9 + PADDL ·sseIncMask<>+0(SB), X9 + MOVO X9, 80(BP) + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X10, 96(BP) + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X11, 112(BP) sealSSETail192LoopA: - // Perform ChaCha rounds, while hashing the previously encrypted ciphertext - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealSSETail192LoopB: - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Left; shiftC0Left; shiftD0Left - shiftB1Left; shiftC1Left; shiftD1Left - shiftB2Left; shiftC2Left; shiftD2Left - - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup - - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Right; shiftC0Right; shiftD0Right - shiftB1Right; shiftC1Right; shiftD1Right - shiftB2Right; shiftC2Right; shiftD2Right - - DECQ itr1 - JG sealSSETail192LoopA - - DECQ itr2 - JGE sealSSETail192LoopB - - PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 - PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2 - PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2 - PADDL ctr0Store, D0; PADDL ctr1Store, D1; PADDL ctr2Store, D2 - - MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 - PXOR T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0 - MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup) - MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3 - PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1 - MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) - - MOVO A2, A1 - MOVO B2, B1 - MOVO C2, C1 - MOVO D2, D1 - MOVQ $128, itr1 - LEAQ 128(inp), inp - SUBQ $128, inl - - JMP sealSSE128SealHash - -// ---------------------------------------------------------------------------- -// Special seal optimization for buffers smaller than 129 bytes + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + DECQ CX + JG sealSSETail192LoopA + DECQ R9 + JGE sealSSETail192LoopB + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL ·chacha20Constants<>+0(SB), X2 + PADDL 32(BP), X3 + PADDL 32(BP), X4 + PADDL 32(BP), X5 + PADDL 48(BP), X6 + PADDL 48(BP), X7 + PADDL 48(BP), X8 + PADDL 80(BP), X9 + PADDL 96(BP), X10 + PADDL 112(BP), X11 + MOVOU (SI), X12 + MOVOU 16(SI), X13 + MOVOU 32(SI), X14 + MOVOU 48(SI), X15 + PXOR X12, X0 + PXOR X13, X3 + PXOR X14, X6 + PXOR X15, X9 + MOVOU X0, (DI) + MOVOU X3, 16(DI) + MOVOU X6, 32(DI) + MOVOU X9, 48(DI) + MOVOU 64(SI), X12 + MOVOU 80(SI), X13 + MOVOU 96(SI), X14 + MOVOU 112(SI), X15 + PXOR X12, X1 + PXOR X13, X4 + PXOR X14, X7 + PXOR X15, X10 + MOVOU X1, 64(DI) + MOVOU X4, 80(DI) + MOVOU X7, 96(DI) + MOVOU X10, 112(DI) + MOVO X2, X1 + MOVO X5, X4 + MOVO X8, X7 + MOVO X11, X10 + MOVQ $0x00000080, CX + LEAQ 128(SI), SI + SUBQ $0x80, BX + JMP sealSSE128SealHash + sealSSE128: - // For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks - MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0 - MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 - MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 - MOVO B0, T1; MOVO C0, T2; MOVO D1, T3 - MOVQ $10, itr2 + MOVOU ·chacha20Constants<>+0(SB), X0 + MOVOU 16(R8), X3 + MOVOU 32(R8), X6 + MOVOU 48(R8), X9 + MOVO X0, X1 + MOVO X3, X4 + MOVO X6, X7 + MOVO X9, X10 + PADDL ·sseIncMask<>+0(SB), X10 + MOVO X1, X2 + MOVO X4, X5 + MOVO X7, X8 + MOVO X10, X11 + PADDL ·sseIncMask<>+0(SB), X11 + MOVO X3, X13 + MOVO X6, X14 + MOVO X10, X15 + MOVQ $0x0000000a, R9 sealSSE128InnerCipherLoop: - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Left; shiftB1Left; shiftB2Left - shiftC0Left; shiftC1Left; shiftC2Left - shiftD0Left; shiftD1Left; shiftD2Left - chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) - shiftB0Right; shiftB1Right; shiftB2Right - shiftC0Right; shiftC1Right; shiftC2Right - shiftD0Right; shiftD1Right; shiftD2Right - DECQ itr2 - JNE sealSSE128InnerCipherLoop + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x04 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x0c + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + PADDD X3, X0 + PXOR X0, X9 + ROL16(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X3 + PXOR X12, X3 + PADDD X3, X0 + PXOR X0, X9 + ROL8(X9, X12) + PADDD X9, X6 + PXOR X6, X3 + MOVO X3, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X3 + PXOR X12, X3 + PADDD X4, X1 + PXOR X1, X10 + ROL16(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X4 + PXOR X12, X4 + PADDD X4, X1 + PXOR X1, X10 + ROL8(X10, X12) + PADDD X10, X7 + PXOR X7, X4 + MOVO X4, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X4 + PXOR X12, X4 + PADDD X5, X2 + PXOR X2, X11 + ROL16(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x0c, X12 + PSRLL $0x14, X5 + PXOR X12, X5 + PADDD X5, X2 + PXOR X2, X11 + ROL8(X11, X12) + PADDD X11, X8 + PXOR X8, X5 + MOVO X5, X12 + PSLLL $0x07, X12 + PSRLL $0x19, X5 + PXOR X12, X5 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xe4 + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xed + BYTE $0x0c + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xf6 + BYTE $0x08 + BYTE $0x66 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xff + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc0 + BYTE $0x08 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xc9 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xd2 + BYTE $0x04 + BYTE $0x66 + BYTE $0x45 + BYTE $0x0f + BYTE $0x3a + BYTE $0x0f + BYTE $0xdb + BYTE $0x04 + DECQ R9 + JNE sealSSE128InnerCipherLoop // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded - PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 - PADDL T1, B0; PADDL T1, B1; PADDL T1, B2 - PADDL T2, C1; PADDL T2, C2 - PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2 - PAND ·polyClampMask<>(SB), A0 - MOVOU A0, rStore - MOVOU B0, sStore + PADDL ·chacha20Constants<>+0(SB), X0 + PADDL ·chacha20Constants<>+0(SB), X1 + PADDL ·chacha20Constants<>+0(SB), X2 + PADDL X13, X3 + PADDL X13, X4 + PADDL X13, X5 + PADDL X14, X7 + PADDL X14, X8 + PADDL X15, X10 + PADDL ·sseIncMask<>+0(SB), X15 + PADDL X15, X11 + PAND ·polyClampMask<>+0(SB), X0 + MOVOU X0, (BP) + MOVOU X3, 16(BP) // Hash - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) - XORQ itr1, itr1 + XORQ CX, CX sealSSE128SealHash: - // itr1 holds the number of bytes encrypted but not yet hashed - CMPQ itr1, $16 - JB sealSSE128Seal - polyAdd(0(oup)) - polyMul - - SUBQ $16, itr1 - ADDQ $16, oup - - JMP sealSSE128SealHash + CMPQ CX, $0x10 + JB sealSSE128Seal + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + SUBQ $0x10, CX + ADDQ $0x10, DI + JMP sealSSE128SealHash sealSSE128Seal: - CMPQ inl, $16 + CMPQ BX, $0x10 JB sealSSETail - SUBQ $16, inl + SUBQ $0x10, BX // Load for decryption - MOVOU (inp), T0 - PXOR T0, A1 - MOVOU A1, (oup) - LEAQ (1*16)(inp), inp - LEAQ (1*16)(oup), oup + MOVOU (SI), X12 + PXOR X12, X1 + MOVOU X1, (DI) + LEAQ 16(SI), SI + LEAQ 16(DI), DI // Extract for hashing - MOVQ A1, t0 - PSRLDQ $8, A1 - MOVQ A1, t1 - ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 - polyMul + MOVQ X1, R13 + PSRLDQ $0x08, X1 + MOVQ X1, R14 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 // Shift the stream "left" - MOVO B1, A1 - MOVO C1, B1 - MOVO D1, C1 - MOVO A2, D1 - MOVO B2, A2 - MOVO C2, B2 - MOVO D2, C2 + MOVO X4, X1 + MOVO X7, X4 + MOVO X10, X7 + MOVO X2, X10 + MOVO X5, X2 + MOVO X8, X5 + MOVO X11, X8 JMP sealSSE128Seal sealSSETail: - TESTQ inl, inl + TESTQ BX, BX JE sealSSEFinalize // We can only load the PT one byte at a time to avoid read after end of buffer - MOVQ inl, itr2 - SHLQ $4, itr2 - LEAQ ·andMask<>(SB), t0 - MOVQ inl, itr1 - LEAQ -1(inp)(inl*1), inp - XORQ t2, t2 - XORQ t3, t3 + MOVQ BX, R9 + SHLQ $0x04, R9 + LEAQ ·andMask<>+0(SB), R13 + MOVQ BX, CX + LEAQ -1(SI)(BX*1), SI + XORQ R15, R15 + XORQ R8, R8 XORQ AX, AX sealSSETailLoadLoop: - SHLQ $8, t2, t3 - SHLQ $8, t2 - MOVB (inp), AX - XORQ AX, t2 - LEAQ -1(inp), inp - DECQ itr1 + SHLQ $0x08, R15, R8 + SHLQ $0x08, R15 + MOVB (SI), AX + XORQ AX, R15 + LEAQ -1(SI), SI + DECQ CX JNE sealSSETailLoadLoop - MOVQ t2, 0+tmpStore - MOVQ t3, 8+tmpStore - PXOR 0+tmpStore, A1 - MOVOU A1, (oup) - MOVOU -16(t0)(itr2*1), T0 - PAND T0, A1 - MOVQ A1, t0 - PSRLDQ $8, A1 - MOVQ A1, t1 - ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 - polyMul - - ADDQ inl, oup + MOVQ R15, 64(BP) + MOVQ R8, 72(BP) + PXOR 64(BP), X1 + MOVOU X1, (DI) + MOVOU -16(R13)(R9*1), X12 + PAND X12, X1 + MOVQ X1, R13 + PSRLDQ $0x08, X1 + MOVQ X1, R14 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + ADDQ BX, DI sealSSEFinalize: // Hash in the buffer lengths - ADDQ ad_len+80(FP), acc0 - ADCQ src_len+56(FP), acc1 - ADCQ $1, acc2 - polyMul + ADDQ ad_len+80(FP), R10 + ADCQ src_len+56(FP), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 // Final reduce - MOVQ acc0, t0 - MOVQ acc1, t1 - MOVQ acc2, t2 - SUBQ $-5, acc0 - SBBQ $-1, acc1 - SBBQ $3, acc2 - CMOVQCS t0, acc0 - CMOVQCS t1, acc1 - CMOVQCS t2, acc2 + MOVQ R10, R13 + MOVQ R11, R14 + MOVQ R12, R15 + SUBQ $-5, R10 + SBBQ $-1, R11 + SBBQ $0x03, R12 + CMOVQCS R13, R10 + CMOVQCS R14, R11 + CMOVQCS R15, R12 // Add in the "s" part of the key - ADDQ 0+sStore, acc0 - ADCQ 8+sStore, acc1 + ADDQ 16(BP), R10 + ADCQ 24(BP), R11 // Finally store the tag at the end of the message - MOVQ acc0, (0*8)(oup) - MOVQ acc1, (1*8)(oup) + MOVQ R10, (DI) + MOVQ R11, 8(DI) RET -// ---------------------------------------------------------------------------- -// ------------------------- AVX2 Code ---------------------------------------- chacha20Poly1305Seal_AVX2: VZEROUPPER - VMOVDQU ·chacha20Constants<>(SB), AA0 - BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14 - BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12 - BYTE $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4 - VPADDD ·avx2InitMask<>(SB), DD0, DD0 + VMOVDQU ·chacha20Constants<>+0(SB), Y0 + BYTE $0xc4 + BYTE $0x42 + BYTE $0x7d + BYTE $0x5a + BYTE $0x70 + BYTE $0x10 + BYTE $0xc4 + BYTE $0x42 + BYTE $0x7d + BYTE $0x5a + BYTE $0x60 + BYTE $0x20 + BYTE $0xc4 + BYTE $0xc2 + BYTE $0x7d + BYTE $0x5a + BYTE $0x60 + BYTE $0x30 + VPADDD ·avx2InitMask<>+0(SB), Y4, Y4 // Special optimizations, for very short buffers - CMPQ inl, $192 - JBE seal192AVX2 // 33% faster - CMPQ inl, $320 - JBE seal320AVX2 // 17% faster + CMPQ BX, $0x000000c0 + JBE seal192AVX2 + CMPQ BX, $0x00000140 + JBE seal320AVX2 // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream - VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 - VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3; VMOVDQA BB0, state1StoreAVX2 - VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3; VMOVDQA CC0, state2StoreAVX2 - VPADDD ·avx2IncMask<>(SB), DD0, DD1; VMOVDQA DD0, ctr0StoreAVX2 - VPADDD ·avx2IncMask<>(SB), DD1, DD2; VMOVDQA DD1, ctr1StoreAVX2 - VPADDD ·avx2IncMask<>(SB), DD2, DD3; VMOVDQA DD2, ctr2StoreAVX2 - VMOVDQA DD3, ctr3StoreAVX2 - MOVQ $10, itr2 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA Y0, Y7 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA Y14, Y11 + VMOVDQA Y14, 32(BP) + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA Y12, Y15 + VMOVDQA Y12, 64(BP) + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y4, 96(BP) + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VMOVDQA Y1, 128(BP) + VPADDD ·avx2IncMask<>+0(SB), Y2, Y3 + VMOVDQA Y2, 160(BP) + VMOVDQA Y3, 192(BP) + MOVQ $0x0000000a, R9 sealAVX2IntroLoop: - VMOVDQA CC3, tmpStoreAVX2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) - VMOVDQA tmpStoreAVX2, CC3 - VMOVDQA CC1, tmpStoreAVX2 - chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) - VMOVDQA tmpStoreAVX2, CC1 - - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0 - VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1 - VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2 - VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3 - - VMOVDQA CC3, tmpStoreAVX2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) - VMOVDQA tmpStoreAVX2, CC3 - VMOVDQA CC1, tmpStoreAVX2 - chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) - VMOVDQA tmpStoreAVX2, CC1 - - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0 - VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1 - VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2 - VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3 - DECQ itr2 - JNE sealAVX2IntroLoop - - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 - VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 - - VPERM2I128 $0x13, CC0, DD0, CC0 // Stream bytes 96 - 127 - VPERM2I128 $0x02, AA0, BB0, DD0 // The Poly1305 key - VPERM2I128 $0x13, AA0, BB0, AA0 // Stream bytes 64 - 95 + VMOVDQA Y15, 224(BP) + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VMOVDQA 224(BP), Y15 + VMOVDQA Y13, 224(BP) + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x0c, Y11, Y13 + VPSRLD $0x14, Y11, Y11 + VPXOR Y13, Y11, Y11 + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x07, Y11, Y13 + VPSRLD $0x19, Y11, Y11 + VPXOR Y13, Y11, Y11 + VMOVDQA 224(BP), Y13 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPALIGNR $0x04, Y11, Y11, Y11 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x0c, Y3, Y3, Y3 + VMOVDQA Y15, 224(BP) + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VMOVDQA 224(BP), Y15 + VMOVDQA Y13, 224(BP) + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x0c, Y11, Y13 + VPSRLD $0x14, Y11, Y11 + VPXOR Y13, Y11, Y11 + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x07, Y11, Y13 + VPSRLD $0x19, Y11, Y11 + VPXOR Y13, Y11, Y11 + VMOVDQA 224(BP), Y13 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x04, Y2, Y2, Y2 + VPALIGNR $0x0c, Y11, Y11, Y11 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x04, Y3, Y3, Y3 + DECQ R9 + JNE sealAVX2IntroLoop + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD ·chacha20Constants<>+0(SB), Y7, Y7 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 32(BP), Y11, Y11 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD 64(BP), Y15, Y15 + VPADDD 96(BP), Y4, Y4 + VPADDD 128(BP), Y1, Y1 + VPADDD 160(BP), Y2, Y2 + VPADDD 192(BP), Y3, Y3 + VPERM2I128 $0x13, Y12, Y4, Y12 + VPERM2I128 $0x02, Y0, Y14, Y4 + VPERM2I128 $0x13, Y0, Y14, Y0 // Clamp and store poly key - VPAND ·polyClampMask<>(SB), DD0, DD0 - VMOVDQA DD0, rsStoreAVX2 + VPAND ·polyClampMask<>+0(SB), Y4, Y4 + VMOVDQA Y4, (BP) // Hash AD - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) // Can store at least 320 bytes - VPXOR (0*32)(inp), AA0, AA0 - VPXOR (1*32)(inp), CC0, CC0 - VMOVDQU AA0, (0*32)(oup) - VMOVDQU CC0, (1*32)(oup) - - VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 - VPXOR (2*32)(inp), AA0, AA0; VPXOR (3*32)(inp), BB0, BB0; VPXOR (4*32)(inp), CC0, CC0; VPXOR (5*32)(inp), DD0, DD0 - VMOVDQU AA0, (2*32)(oup); VMOVDQU BB0, (3*32)(oup); VMOVDQU CC0, (4*32)(oup); VMOVDQU DD0, (5*32)(oup) - VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 - VPXOR (6*32)(inp), AA0, AA0; VPXOR (7*32)(inp), BB0, BB0; VPXOR (8*32)(inp), CC0, CC0; VPXOR (9*32)(inp), DD0, DD0 - VMOVDQU AA0, (6*32)(oup); VMOVDQU BB0, (7*32)(oup); VMOVDQU CC0, (8*32)(oup); VMOVDQU DD0, (9*32)(oup) - - MOVQ $320, itr1 - SUBQ $320, inl - LEAQ 320(inp), inp - - VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, CC3, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, CC3, DD3, DD0 - CMPQ inl, $128 + VPXOR (SI), Y0, Y0 + VPXOR 32(SI), Y12, Y12 + VMOVDQU Y0, (DI) + VMOVDQU Y12, 32(DI) + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + VPXOR 64(SI), Y0, Y0 + VPXOR 96(SI), Y14, Y14 + VPXOR 128(SI), Y12, Y12 + VPXOR 160(SI), Y4, Y4 + VMOVDQU Y0, 64(DI) + VMOVDQU Y14, 96(DI) + VMOVDQU Y12, 128(DI) + VMOVDQU Y4, 160(DI) + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + VPXOR 192(SI), Y0, Y0 + VPXOR 224(SI), Y14, Y14 + VPXOR 256(SI), Y12, Y12 + VPXOR 288(SI), Y4, Y4 + VMOVDQU Y0, 192(DI) + VMOVDQU Y14, 224(DI) + VMOVDQU Y12, 256(DI) + VMOVDQU Y4, 288(DI) + MOVQ $0x00000140, CX + SUBQ $0x00000140, BX + LEAQ 320(SI), SI + VPERM2I128 $0x02, Y7, Y11, Y0 + VPERM2I128 $0x02, Y15, Y3, Y14 + VPERM2I128 $0x13, Y7, Y11, Y12 + VPERM2I128 $0x13, Y15, Y3, Y4 + CMPQ BX, $0x80 JBE sealAVX2SealHash - - VPXOR (0*32)(inp), AA0, AA0; VPXOR (1*32)(inp), BB0, BB0; VPXOR (2*32)(inp), CC0, CC0; VPXOR (3*32)(inp), DD0, DD0 - VMOVDQU AA0, (10*32)(oup); VMOVDQU BB0, (11*32)(oup); VMOVDQU CC0, (12*32)(oup); VMOVDQU DD0, (13*32)(oup) - SUBQ $128, inl - LEAQ 128(inp), inp - - MOVQ $8, itr1 - MOVQ $2, itr2 - - CMPQ inl, $128 - JBE sealAVX2Tail128 - CMPQ inl, $256 - JBE sealAVX2Tail256 - CMPQ inl, $384 - JBE sealAVX2Tail384 - CMPQ inl, $512 - JBE sealAVX2Tail512 + VPXOR (SI), Y0, Y0 + VPXOR 32(SI), Y14, Y14 + VPXOR 64(SI), Y12, Y12 + VPXOR 96(SI), Y4, Y4 + VMOVDQU Y0, 320(DI) + VMOVDQU Y14, 352(DI) + VMOVDQU Y12, 384(DI) + VMOVDQU Y4, 416(DI) + SUBQ $0x80, BX + LEAQ 128(SI), SI + MOVQ $0x00000008, CX + MOVQ $0x00000002, R9 + CMPQ BX, $0x80 + JBE sealAVX2Tail128 + CMPQ BX, $0x00000100 + JBE sealAVX2Tail256 + CMPQ BX, $0x00000180 + JBE sealAVX2Tail384 + CMPQ BX, $0x00000200 + JBE sealAVX2Tail512 // We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop - VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 - VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 - - VMOVDQA CC3, tmpStoreAVX2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) - VMOVDQA tmpStoreAVX2, CC3 - VMOVDQA CC1, tmpStoreAVX2 - chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) - VMOVDQA tmpStoreAVX2, CC1 - - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0 - VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1 - VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2 - VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3 - - VMOVDQA CC3, tmpStoreAVX2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) - VMOVDQA tmpStoreAVX2, CC3 - VMOVDQA CC1, tmpStoreAVX2 - chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) - VMOVDQA tmpStoreAVX2, CC1 - - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0 - VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1 - VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2 - VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - - SUBQ $16, oup // Adjust the pointer - MOVQ $9, itr1 - JMP sealAVX2InternalLoopStart + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA Y0, Y7 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA Y14, Y11 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA Y12, Y15 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VPADDD ·avx2IncMask<>+0(SB), Y2, Y3 + VMOVDQA Y4, 96(BP) + VMOVDQA Y1, 128(BP) + VMOVDQA Y2, 160(BP) + VMOVDQA Y3, 192(BP) + VMOVDQA Y15, 224(BP) + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VMOVDQA 224(BP), Y15 + VMOVDQA Y13, 224(BP) + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x0c, Y11, Y13 + VPSRLD $0x14, Y11, Y11 + VPXOR Y13, Y11, Y11 + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x07, Y11, Y13 + VPSRLD $0x19, Y11, Y11 + VPXOR Y13, Y11, Y11 + VMOVDQA 224(BP), Y13 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPALIGNR $0x04, Y11, Y11, Y11 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x0c, Y3, Y3, Y3 + VMOVDQA Y15, 224(BP) + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VMOVDQA 224(BP), Y15 + VMOVDQA Y13, 224(BP) + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x0c, Y11, Y13 + VPSRLD $0x14, Y11, Y11 + VPXOR Y13, Y11, Y11 + VPADDD Y11, Y7, Y7 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y3, Y15, Y15 + VPXOR Y15, Y11, Y11 + VPSLLD $0x07, Y11, Y13 + VPSRLD $0x19, Y11, Y11 + VPXOR Y13, Y11, Y11 + VMOVDQA 224(BP), Y13 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x04, Y2, Y2, Y2 + VPALIGNR $0x0c, Y11, Y11, Y11 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x04, Y3, Y3, Y3 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + SUBQ $0x10, DI + MOVQ $0x00000009, CX + JMP sealAVX2InternalLoopStart sealAVX2MainLoop: - // Load state, increment counter blocks, store the incremented counters - VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 - VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 - VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 - MOVQ $10, itr1 + VMOVDQU ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA Y0, Y7 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA Y14, Y11 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA Y12, Y15 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VPADDD ·avx2IncMask<>+0(SB), Y2, Y3 + VMOVDQA Y4, 96(BP) + VMOVDQA Y1, 128(BP) + VMOVDQA Y2, 160(BP) + VMOVDQA Y3, 192(BP) + MOVQ $0x0000000a, CX sealAVX2InternalLoop: - polyAdd(0*8(oup)) - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - polyMulStage1_AVX2 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - polyMulStage2_AVX2 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - polyMulStage3_AVX2 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulReduceStage + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 sealAVX2InternalLoopStart: - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - polyAdd(2*8(oup)) - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - polyMulStage1_AVX2 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulStage2_AVX2 - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - polyMulStage3_AVX2 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - polyMulReduceStage - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - polyAdd(4*8(oup)) - LEAQ (6*8)(oup), oup - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulStage1_AVX2 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - polyMulStage2_AVX2 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - polyMulStage3_AVX2 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyMulReduceStage - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 - DECQ itr1 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x04, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPALIGNR $0x0c, Y3, Y3, Y3 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + ADDQ 32(DI), R10 + ADCQ 40(DI), R11 + ADCQ $0x01, R12 + LEAQ 48(DI), DI + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x0c, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + VPALIGNR $0x04, Y3, Y3, Y3 + DECQ CX JNE sealAVX2InternalLoop - - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 - VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 - VMOVDQA CC3, tmpStoreAVX2 + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD ·chacha20Constants<>+0(SB), Y7, Y7 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 32(BP), Y11, Y11 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD 64(BP), Y15, Y15 + VPADDD 96(BP), Y4, Y4 + VPADDD 128(BP), Y1, Y1 + VPADDD 160(BP), Y2, Y2 + VPADDD 192(BP), Y3, Y3 + VMOVDQA Y15, 224(BP) // We only hashed 480 of the 512 bytes available - hash the remaining 32 here - polyAdd(0*8(oup)) - polyMulAVX2 - LEAQ (4*8)(oup), oup - VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0 - VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0 - VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup) - VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 - VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 - VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI + VPERM2I128 $0x02, Y0, Y14, Y15 + VPERM2I128 $0x13, Y0, Y14, Y14 + VPERM2I128 $0x02, Y12, Y4, Y0 + VPERM2I128 $0x13, Y12, Y4, Y12 + VPXOR (SI), Y15, Y15 + VPXOR 32(SI), Y0, Y0 + VPXOR 64(SI), Y14, Y14 + VPXOR 96(SI), Y12, Y12 + VMOVDQU Y15, (DI) + VMOVDQU Y0, 32(DI) + VMOVDQU Y14, 64(DI) + VMOVDQU Y12, 96(DI) + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + VPXOR 128(SI), Y0, Y0 + VPXOR 160(SI), Y14, Y14 + VPXOR 192(SI), Y12, Y12 + VPXOR 224(SI), Y4, Y4 + VMOVDQU Y0, 128(DI) + VMOVDQU Y14, 160(DI) + VMOVDQU Y12, 192(DI) + VMOVDQU Y4, 224(DI) // and here - polyAdd(-2*8(oup)) - polyMulAVX2 - VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 - VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 - VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) - VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 - VPXOR (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0 - VMOVDQU AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup) - LEAQ (32*16)(inp), inp - SUBQ $(32*16), inl - CMPQ inl, $512 + ADDQ -16(DI), R10 + ADCQ -8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + VPXOR 256(SI), Y0, Y0 + VPXOR 288(SI), Y14, Y14 + VPXOR 320(SI), Y12, Y12 + VPXOR 352(SI), Y4, Y4 + VMOVDQU Y0, 256(DI) + VMOVDQU Y14, 288(DI) + VMOVDQU Y12, 320(DI) + VMOVDQU Y4, 352(DI) + VPERM2I128 $0x02, Y7, Y11, Y0 + VPERM2I128 $0x02, 224(BP), Y3, Y14 + VPERM2I128 $0x13, Y7, Y11, Y12 + VPERM2I128 $0x13, 224(BP), Y3, Y4 + VPXOR 384(SI), Y0, Y0 + VPXOR 416(SI), Y14, Y14 + VPXOR 448(SI), Y12, Y12 + VPXOR 480(SI), Y4, Y4 + VMOVDQU Y0, 384(DI) + VMOVDQU Y14, 416(DI) + VMOVDQU Y12, 448(DI) + VMOVDQU Y4, 480(DI) + LEAQ 512(SI), SI + SUBQ $0x00000200, BX + CMPQ BX, $0x00000200 JG sealAVX2MainLoop // Tail can only hash 480 bytes - polyAdd(0*8(oup)) - polyMulAVX2 - polyAdd(2*8(oup)) - polyMulAVX2 - LEAQ 32(oup), oup - - MOVQ $10, itr1 - MOVQ $0, itr2 - CMPQ inl, $128 - JBE sealAVX2Tail128 - CMPQ inl, $256 - JBE sealAVX2Tail256 - CMPQ inl, $384 - JBE sealAVX2Tail384 - JMP sealAVX2Tail512 - -// ---------------------------------------------------------------------------- -// Special optimization for buffers smaller than 193 bytes + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI + MOVQ $0x0000000a, CX + MOVQ $0x00000000, R9 + CMPQ BX, $0x80 + JBE sealAVX2Tail128 + CMPQ BX, $0x00000100 + JBE sealAVX2Tail256 + CMPQ BX, $0x00000180 + JBE sealAVX2Tail384 + JMP sealAVX2Tail512 + seal192AVX2: - // For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks - VMOVDQA AA0, AA1 - VMOVDQA BB0, BB1 - VMOVDQA CC0, CC1 - VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VMOVDQA AA0, AA2 - VMOVDQA BB0, BB2 - VMOVDQA CC0, CC2 - VMOVDQA DD0, DD2 - VMOVDQA DD1, TT3 - MOVQ $10, itr2 + VMOVDQA Y0, Y5 + VMOVDQA Y14, Y9 + VMOVDQA Y12, Y13 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y0, Y6 + VMOVDQA Y14, Y10 + VMOVDQA Y12, Y8 + VMOVDQA Y4, Y2 + VMOVDQA Y1, Y15 + MOVQ $0x0000000a, R9 sealAVX2192InnerCipherLoop: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 - DECQ itr2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + DECQ R9 JNE sealAVX2192InnerCipherLoop - VPADDD AA2, AA0, AA0; VPADDD AA2, AA1, AA1 - VPADDD BB2, BB0, BB0; VPADDD BB2, BB1, BB1 - VPADDD CC2, CC0, CC0; VPADDD CC2, CC1, CC1 - VPADDD DD2, DD0, DD0; VPADDD TT3, DD1, DD1 - VPERM2I128 $0x02, AA0, BB0, TT0 + VPADDD Y6, Y0, Y0 + VPADDD Y6, Y5, Y5 + VPADDD Y10, Y14, Y14 + VPADDD Y10, Y9, Y9 + VPADDD Y8, Y12, Y12 + VPADDD Y8, Y13, Y13 + VPADDD Y2, Y4, Y4 + VPADDD Y15, Y1, Y1 + VPERM2I128 $0x02, Y0, Y14, Y3 // Clamp and store poly key - VPAND ·polyClampMask<>(SB), TT0, TT0 - VMOVDQA TT0, rsStoreAVX2 + VPAND ·polyClampMask<>+0(SB), Y3, Y3 + VMOVDQA Y3, (BP) // Stream for up to 192 bytes - VPERM2I128 $0x13, AA0, BB0, AA0 - VPERM2I128 $0x13, CC0, DD0, BB0 - VPERM2I128 $0x02, AA1, BB1, CC0 - VPERM2I128 $0x02, CC1, DD1, DD0 - VPERM2I128 $0x13, AA1, BB1, AA1 - VPERM2I128 $0x13, CC1, DD1, BB1 + VPERM2I128 $0x13, Y0, Y14, Y0 + VPERM2I128 $0x13, Y12, Y4, Y14 + VPERM2I128 $0x02, Y5, Y9, Y12 + VPERM2I128 $0x02, Y13, Y1, Y4 + VPERM2I128 $0x13, Y5, Y9, Y5 + VPERM2I128 $0x13, Y13, Y1, Y9 sealAVX2ShortSeal: // Hash aad - MOVQ ad_len+80(FP), itr2 + MOVQ ad_len+80(FP), R9 CALL polyHashADInternal<>(SB) - XORQ itr1, itr1 + XORQ CX, CX sealAVX2SealHash: // itr1 holds the number of bytes encrypted but not yet hashed - CMPQ itr1, $16 - JB sealAVX2ShortSealLoop - polyAdd(0(oup)) - polyMul - SUBQ $16, itr1 - ADDQ $16, oup - JMP sealAVX2SealHash + CMPQ CX, $0x10 + JB sealAVX2ShortSealLoop + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + SUBQ $0x10, CX + ADDQ $0x10, DI + JMP sealAVX2SealHash sealAVX2ShortSealLoop: - CMPQ inl, $32 + CMPQ BX, $0x20 JB sealAVX2ShortTail32 - SUBQ $32, inl + SUBQ $0x20, BX // Load for encryption - VPXOR (inp), AA0, AA0 - VMOVDQU AA0, (oup) - LEAQ (1*32)(inp), inp + VPXOR (SI), Y0, Y0 + VMOVDQU Y0, (DI) + LEAQ 32(SI), SI // Now can hash - polyAdd(0*8(oup)) - polyMulAVX2 - polyAdd(2*8(oup)) - polyMulAVX2 - LEAQ (1*32)(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI // Shift stream left - VMOVDQA BB0, AA0 - VMOVDQA CC0, BB0 - VMOVDQA DD0, CC0 - VMOVDQA AA1, DD0 - VMOVDQA BB1, AA1 - VMOVDQA CC1, BB1 - VMOVDQA DD1, CC1 - VMOVDQA AA2, DD1 - VMOVDQA BB2, AA2 + VMOVDQA Y14, Y0 + VMOVDQA Y12, Y14 + VMOVDQA Y4, Y12 + VMOVDQA Y5, Y4 + VMOVDQA Y9, Y5 + VMOVDQA Y13, Y9 + VMOVDQA Y1, Y13 + VMOVDQA Y6, Y1 + VMOVDQA Y10, Y6 JMP sealAVX2ShortSealLoop sealAVX2ShortTail32: - CMPQ inl, $16 - VMOVDQA A0, A1 + CMPQ BX, $0x10 + VMOVDQA X0, X1 JB sealAVX2ShortDone - - SUBQ $16, inl + SUBQ $0x10, BX // Load for encryption - VPXOR (inp), A0, T0 - VMOVDQU T0, (oup) - LEAQ (1*16)(inp), inp + VPXOR (SI), X0, X12 + VMOVDQU X12, (DI) + LEAQ 16(SI), SI // Hash - polyAdd(0*8(oup)) - polyMulAVX2 - LEAQ (1*16)(oup), oup - VPERM2I128 $0x11, AA0, AA0, AA0 - VMOVDQA A0, A1 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI + VPERM2I128 $0x11, Y0, Y0, Y0 + VMOVDQA X0, X1 sealAVX2ShortDone: VZEROUPPER JMP sealSSETail -// ---------------------------------------------------------------------------- -// Special optimization for buffers smaller than 321 bytes seal320AVX2: - // For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks - VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2 - VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3 - MOVQ $10, itr2 + VMOVDQA Y0, Y5 + VMOVDQA Y14, Y9 + VMOVDQA Y12, Y13 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y0, Y6 + VMOVDQA Y14, Y10 + VMOVDQA Y12, Y8 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VMOVDQA Y14, Y7 + VMOVDQA Y12, Y11 + VMOVDQA Y4, Y15 + MOVQ $0x0000000a, R9 sealAVX2320InnerCipherLoop: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 - DECQ itr2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + DECQ R9 JNE sealAVX2320InnerCipherLoop - - VMOVDQA ·chacha20Constants<>(SB), TT0 - VPADDD TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2 - VPADDD TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2 - VPADDD TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2 - VMOVDQA ·avx2IncMask<>(SB), TT0 - VPADDD TT3, DD0, DD0; VPADDD TT0, TT3, TT3 - VPADDD TT3, DD1, DD1; VPADDD TT0, TT3, TT3 - VPADDD TT3, DD2, DD2 + VMOVDQA ·chacha20Constants<>+0(SB), Y3 + VPADDD Y3, Y0, Y0 + VPADDD Y3, Y5, Y5 + VPADDD Y3, Y6, Y6 + VPADDD Y7, Y14, Y14 + VPADDD Y7, Y9, Y9 + VPADDD Y7, Y10, Y10 + VPADDD Y11, Y12, Y12 + VPADDD Y11, Y13, Y13 + VPADDD Y11, Y8, Y8 + VMOVDQA ·avx2IncMask<>+0(SB), Y3 + VPADDD Y15, Y4, Y4 + VPADDD Y3, Y15, Y15 + VPADDD Y15, Y1, Y1 + VPADDD Y3, Y15, Y15 + VPADDD Y15, Y2, Y2 // Clamp and store poly key - VPERM2I128 $0x02, AA0, BB0, TT0 - VPAND ·polyClampMask<>(SB), TT0, TT0 - VMOVDQA TT0, rsStoreAVX2 + VPERM2I128 $0x02, Y0, Y14, Y3 + VPAND ·polyClampMask<>+0(SB), Y3, Y3 + VMOVDQA Y3, (BP) // Stream for up to 320 bytes - VPERM2I128 $0x13, AA0, BB0, AA0 - VPERM2I128 $0x13, CC0, DD0, BB0 - VPERM2I128 $0x02, AA1, BB1, CC0 - VPERM2I128 $0x02, CC1, DD1, DD0 - VPERM2I128 $0x13, AA1, BB1, AA1 - VPERM2I128 $0x13, CC1, DD1, BB1 - VPERM2I128 $0x02, AA2, BB2, CC1 - VPERM2I128 $0x02, CC2, DD2, DD1 - VPERM2I128 $0x13, AA2, BB2, AA2 - VPERM2I128 $0x13, CC2, DD2, BB2 + VPERM2I128 $0x13, Y0, Y14, Y0 + VPERM2I128 $0x13, Y12, Y4, Y14 + VPERM2I128 $0x02, Y5, Y9, Y12 + VPERM2I128 $0x02, Y13, Y1, Y4 + VPERM2I128 $0x13, Y5, Y9, Y5 + VPERM2I128 $0x13, Y13, Y1, Y9 + VPERM2I128 $0x02, Y6, Y10, Y13 + VPERM2I128 $0x02, Y8, Y2, Y1 + VPERM2I128 $0x13, Y6, Y10, Y6 + VPERM2I128 $0x13, Y8, Y2, Y10 JMP sealAVX2ShortSeal -// ---------------------------------------------------------------------------- -// Special optimization for the last 128 bytes of ciphertext sealAVX2Tail128: - // Need to decrypt up to 128 bytes - prepare two blocks - // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed - // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed - VMOVDQA ·chacha20Constants<>(SB), AA0 - VMOVDQA state1StoreAVX2, BB0 - VMOVDQA state2StoreAVX2, CC0 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0 - VMOVDQA DD0, DD1 + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA 32(BP), Y14 + VMOVDQA 64(BP), Y12 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VMOVDQA Y4, Y1 sealAVX2Tail128LoopA: - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealAVX2Tail128LoopB: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) - polyAdd(0(oup)) - polyMul - VPALIGNR $4, BB0, BB0, BB0 - VPALIGNR $8, CC0, CC0, CC0 - VPALIGNR $12, DD0, DD0, DD0 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) - polyAdd(16(oup)) - polyMul - LEAQ 32(oup), oup - VPALIGNR $12, BB0, BB0, BB0 - VPALIGNR $8, CC0, CC0, CC0 - VPALIGNR $4, DD0, DD0, DD0 - DECQ itr1 - JG sealAVX2Tail128LoopA - DECQ itr2 - JGE sealAVX2Tail128LoopB - - VPADDD ·chacha20Constants<>(SB), AA0, AA1 - VPADDD state1StoreAVX2, BB0, BB1 - VPADDD state2StoreAVX2, CC0, CC1 - VPADDD DD1, DD0, DD1 - - VPERM2I128 $0x02, AA1, BB1, AA0 - VPERM2I128 $0x02, CC1, DD1, BB0 - VPERM2I128 $0x13, AA1, BB1, CC0 - VPERM2I128 $0x13, CC1, DD1, DD0 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x04, Y4, Y4, Y4 + DECQ CX + JG sealAVX2Tail128LoopA + DECQ R9 + JGE sealAVX2Tail128LoopB + VPADDD ·chacha20Constants<>+0(SB), Y0, Y5 + VPADDD 32(BP), Y14, Y9 + VPADDD 64(BP), Y12, Y13 + VPADDD Y1, Y4, Y1 + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 JMP sealAVX2ShortSealLoop -// ---------------------------------------------------------------------------- -// Special optimization for the last 256 bytes of ciphertext sealAVX2Tail256: - // Need to decrypt up to 256 bytes - prepare two blocks - // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed - // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed - VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA ·chacha20Constants<>(SB), AA1 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA state1StoreAVX2, BB1 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA state2StoreAVX2, CC1 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD1 - VMOVDQA DD0, TT1 - VMOVDQA DD1, TT2 + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA ·chacha20Constants<>+0(SB), Y5 + VMOVDQA 32(BP), Y14 + VMOVDQA 32(BP), Y9 + VMOVDQA 64(BP), Y12 + VMOVDQA 64(BP), Y13 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VMOVDQA Y4, Y7 + VMOVDQA Y1, Y11 sealAVX2Tail256LoopA: - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealAVX2Tail256LoopB: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - polyAdd(0(oup)) - polyMul - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) - polyAdd(16(oup)) - polyMul - LEAQ 32(oup), oup - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 - DECQ itr1 - JG sealAVX2Tail256LoopA - DECQ itr2 - JGE sealAVX2Tail256LoopB - - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1 - VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1 - VPERM2I128 $0x02, AA0, BB0, TT0 - VPERM2I128 $0x02, CC0, DD0, TT1 - VPERM2I128 $0x13, AA0, BB0, TT2 - VPERM2I128 $0x13, CC0, DD0, TT3 - VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3 - VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup) - MOVQ $128, itr1 - LEAQ 128(inp), inp - SUBQ $128, inl - VPERM2I128 $0x02, AA1, BB1, AA0 - VPERM2I128 $0x02, CC1, DD1, BB0 - VPERM2I128 $0x13, AA1, BB1, CC0 - VPERM2I128 $0x13, CC1, DD1, DD0 - - JMP sealAVX2SealHash - -// ---------------------------------------------------------------------------- -// Special optimization for the last 384 bytes of ciphertext + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + DECQ CX + JG sealAVX2Tail256LoopA + DECQ R9 + JGE sealAVX2Tail256LoopB + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD Y7, Y4, Y4 + VPADDD Y11, Y1, Y1 + VPERM2I128 $0x02, Y0, Y14, Y3 + VPERM2I128 $0x02, Y12, Y4, Y7 + VPERM2I128 $0x13, Y0, Y14, Y11 + VPERM2I128 $0x13, Y12, Y4, Y15 + VPXOR (SI), Y3, Y3 + VPXOR 32(SI), Y7, Y7 + VPXOR 64(SI), Y11, Y11 + VPXOR 96(SI), Y15, Y15 + VMOVDQU Y3, (DI) + VMOVDQU Y7, 32(DI) + VMOVDQU Y11, 64(DI) + VMOVDQU Y15, 96(DI) + MOVQ $0x00000080, CX + LEAQ 128(SI), SI + SUBQ $0x80, BX + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + JMP sealAVX2SealHash + sealAVX2Tail384: - // Need to decrypt up to 384 bytes - prepare two blocks - // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed - // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed - VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2 - VMOVDQA DD0, TT1; VMOVDQA DD1, TT2; VMOVDQA DD2, TT3 + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VMOVDQA Y4, Y7 + VMOVDQA Y1, Y11 + VMOVDQA Y2, Y15 sealAVX2Tail384LoopA: - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealAVX2Tail384LoopB: - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - polyAdd(0(oup)) - polyMul - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 - chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) - polyAdd(16(oup)) - polyMul - LEAQ 32(oup), oup - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 - DECQ itr1 - JG sealAVX2Tail384LoopA - DECQ itr2 - JGE sealAVX2Tail384LoopB - - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2 - VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1; VPADDD TT3, DD2, DD2 - VPERM2I128 $0x02, AA0, BB0, TT0 - VPERM2I128 $0x02, CC0, DD0, TT1 - VPERM2I128 $0x13, AA0, BB0, TT2 - VPERM2I128 $0x13, CC0, DD0, TT3 - VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3 - VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup) - VPERM2I128 $0x02, AA1, BB1, TT0 - VPERM2I128 $0x02, CC1, DD1, TT1 - VPERM2I128 $0x13, AA1, BB1, TT2 - VPERM2I128 $0x13, CC1, DD1, TT3 - VPXOR (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3 - VMOVDQU TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup) - MOVQ $256, itr1 - LEAQ 256(inp), inp - SUBQ $256, inl - VPERM2I128 $0x02, AA2, BB2, AA0 - VPERM2I128 $0x02, CC2, DD2, BB0 - VPERM2I128 $0x13, AA2, BB2, CC0 - VPERM2I128 $0x13, CC2, DD2, DD0 - - JMP sealAVX2SealHash - -// ---------------------------------------------------------------------------- -// Special optimization for the last 512 bytes of ciphertext + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x0c, Y14, Y3 + VPSRLD $0x14, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y14, Y0, Y0 + VPXOR Y0, Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPADDD Y4, Y12, Y12 + VPXOR Y12, Y14, Y14 + VPSLLD $0x07, Y14, Y3 + VPSRLD $0x19, Y14, Y14 + VPXOR Y3, Y14, Y14 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x0c, Y9, Y3 + VPSRLD $0x14, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y9, Y5, Y5 + VPXOR Y5, Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPADDD Y1, Y13, Y13 + VPXOR Y13, Y9, Y9 + VPSLLD $0x07, Y9, Y3 + VPSRLD $0x19, Y9, Y9 + VPXOR Y3, Y9, Y9 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x0c, Y10, Y3 + VPSRLD $0x14, Y10, Y10 + VPXOR Y3, Y10, Y10 + VPADDD Y10, Y6, Y6 + VPXOR Y6, Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPADDD Y2, Y8, Y8 + VPXOR Y8, Y10, Y10 + VPSLLD $0x07, Y10, Y3 + VPSRLD $0x19, Y10, Y10 + VPXOR Y3, Y10, Y10 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + DECQ CX + JG sealAVX2Tail384LoopA + DECQ R9 + JGE sealAVX2Tail384LoopB + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD Y7, Y4, Y4 + VPADDD Y11, Y1, Y1 + VPADDD Y15, Y2, Y2 + VPERM2I128 $0x02, Y0, Y14, Y3 + VPERM2I128 $0x02, Y12, Y4, Y7 + VPERM2I128 $0x13, Y0, Y14, Y11 + VPERM2I128 $0x13, Y12, Y4, Y15 + VPXOR (SI), Y3, Y3 + VPXOR 32(SI), Y7, Y7 + VPXOR 64(SI), Y11, Y11 + VPXOR 96(SI), Y15, Y15 + VMOVDQU Y3, (DI) + VMOVDQU Y7, 32(DI) + VMOVDQU Y11, 64(DI) + VMOVDQU Y15, 96(DI) + VPERM2I128 $0x02, Y5, Y9, Y3 + VPERM2I128 $0x02, Y13, Y1, Y7 + VPERM2I128 $0x13, Y5, Y9, Y11 + VPERM2I128 $0x13, Y13, Y1, Y15 + VPXOR 128(SI), Y3, Y3 + VPXOR 160(SI), Y7, Y7 + VPXOR 192(SI), Y11, Y11 + VPXOR 224(SI), Y15, Y15 + VMOVDQU Y3, 128(DI) + VMOVDQU Y7, 160(DI) + VMOVDQU Y11, 192(DI) + VMOVDQU Y15, 224(DI) + MOVQ $0x00000100, CX + LEAQ 256(SI), SI + SUBQ $0x00000100, BX + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + JMP sealAVX2SealHash + sealAVX2Tail512: - // Need to decrypt up to 512 bytes - prepare two blocks - // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed - // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed - VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 - VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 - VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 - VMOVDQA ctr3StoreAVX2, DD0 - VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 - VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 + VMOVDQA ·chacha20Constants<>+0(SB), Y0 + VMOVDQA Y0, Y5 + VMOVDQA Y0, Y6 + VMOVDQA Y0, Y7 + VMOVDQA 32(BP), Y14 + VMOVDQA Y14, Y9 + VMOVDQA Y14, Y10 + VMOVDQA Y14, Y11 + VMOVDQA 64(BP), Y12 + VMOVDQA Y12, Y13 + VMOVDQA Y12, Y8 + VMOVDQA Y12, Y15 + VMOVDQA 192(BP), Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y4 + VPADDD ·avx2IncMask<>+0(SB), Y4, Y1 + VPADDD ·avx2IncMask<>+0(SB), Y1, Y2 + VPADDD ·avx2IncMask<>+0(SB), Y2, Y3 + VMOVDQA Y4, 96(BP) + VMOVDQA Y1, 128(BP) + VMOVDQA Y2, 160(BP) + VMOVDQA Y3, 192(BP) sealAVX2Tail512LoopA: - polyAdd(0(oup)) - polyMul - LEAQ 16(oup), oup + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), AX + MOVQ AX, R15 + MULQ R10 + MOVQ AX, R13 + MOVQ DX, R14 + MOVQ (BP), AX + MULQ R11 + IMULQ R12, R15 + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), AX + MOVQ AX, R8 + MULQ R10 + ADDQ AX, R14 + ADCQ $0x00, DX + MOVQ DX, R10 + MOVQ 8(BP), AX + MULQ R11 + ADDQ AX, R15 + ADCQ $0x00, DX + IMULQ R12, R8 + ADDQ R10, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 16(DI), DI sealAVX2Tail512LoopB: - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - polyAdd(0*8(oup)) - polyMulAVX2 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - polyAdd(2*8(oup)) - polyMulAVX2 - LEAQ (4*8)(oup), oup - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 - VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 - VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 - VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 - VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 - VMOVDQA CC3, tmpStoreAVX2 - VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 - VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 - VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 - VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 - VMOVDQA tmpStoreAVX2, CC3 - VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 - VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 - VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 - - DECQ itr1 - JG sealAVX2Tail512LoopA - DECQ itr2 - JGE sealAVX2Tail512LoopB - - VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 - VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 - VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 - VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 - VMOVDQA CC3, tmpStoreAVX2 - VPERM2I128 $0x02, AA0, BB0, CC3 - VPXOR (0*32)(inp), CC3, CC3 - VMOVDQU CC3, (0*32)(oup) - VPERM2I128 $0x02, CC0, DD0, CC3 - VPXOR (1*32)(inp), CC3, CC3 - VMOVDQU CC3, (1*32)(oup) - VPERM2I128 $0x13, AA0, BB0, CC3 - VPXOR (2*32)(inp), CC3, CC3 - VMOVDQU CC3, (2*32)(oup) - VPERM2I128 $0x13, CC0, DD0, CC3 - VPXOR (3*32)(inp), CC3, CC3 - VMOVDQU CC3, (3*32)(oup) - - VPERM2I128 $0x02, AA1, BB1, AA0 - VPERM2I128 $0x02, CC1, DD1, BB0 - VPERM2I128 $0x13, AA1, BB1, CC0 - VPERM2I128 $0x13, CC1, DD1, DD0 - VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 - VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) - - VPERM2I128 $0x02, AA2, BB2, AA0 - VPERM2I128 $0x02, CC2, DD2, BB0 - VPERM2I128 $0x13, AA2, BB2, CC0 - VPERM2I128 $0x13, CC2, DD2, DD0 - VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 - VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) - - MOVQ $384, itr1 - LEAQ 384(inp), inp - SUBQ $384, inl - VPERM2I128 $0x02, AA3, BB3, AA0 - VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0 - VPERM2I128 $0x13, AA3, BB3, CC0 - VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 - - JMP sealAVX2SealHash + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + ADDQ (DI), R10 + ADCQ 8(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + VPALIGNR $0x04, Y14, Y14, Y14 + VPALIGNR $0x04, Y9, Y9, Y9 + VPALIGNR $0x04, Y10, Y10, Y10 + VPALIGNR $0x04, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x0c, Y4, Y4, Y4 + VPALIGNR $0x0c, Y1, Y1, Y1 + VPALIGNR $0x0c, Y2, Y2, Y2 + VPALIGNR $0x0c, Y3, Y3, Y3 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol16<>+0(SB), Y4, Y4 + VPSHUFB ·rol16<>+0(SB), Y1, Y1 + VPSHUFB ·rol16<>+0(SB), Y2, Y2 + VPSHUFB ·rol16<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + ADDQ 16(DI), R10 + ADCQ 24(DI), R11 + ADCQ $0x01, R12 + MOVQ (BP), DX + MOVQ DX, R15 + MULXQ R10, R13, R14 + IMULQ R12, R15 + MULXQ R11, AX, DX + ADDQ AX, R14 + ADCQ DX, R15 + MOVQ 8(BP), DX + MULXQ R10, R10, AX + ADDQ R10, R14 + MULXQ R11, R11, R8 + ADCQ R11, R15 + ADCQ $0x00, R8 + IMULQ R12, DX + ADDQ AX, R15 + ADCQ DX, R8 + MOVQ R13, R10 + MOVQ R14, R11 + MOVQ R15, R12 + ANDQ $0x03, R12 + MOVQ R15, R13 + ANDQ $-4, R13 + MOVQ R8, R14 + SHRQ $0x02, R8, R15 + SHRQ $0x02, R8 + ADDQ R13, R10 + ADCQ R14, R11 + ADCQ $0x00, R12 + ADDQ R15, R10 + ADCQ R8, R11 + ADCQ $0x00, R12 + LEAQ 32(DI), DI + VMOVDQA Y15, 224(BP) + VPSLLD $0x0c, Y14, Y15 + VPSRLD $0x14, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x0c, Y9, Y15 + VPSRLD $0x14, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x0c, Y10, Y15 + VPSRLD $0x14, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x0c, Y11, Y15 + VPSRLD $0x14, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + VPADDD Y14, Y0, Y0 + VPADDD Y9, Y5, Y5 + VPADDD Y10, Y6, Y6 + VPADDD Y11, Y7, Y7 + VPXOR Y0, Y4, Y4 + VPXOR Y5, Y1, Y1 + VPXOR Y6, Y2, Y2 + VPXOR Y7, Y3, Y3 + VPSHUFB ·rol8<>+0(SB), Y4, Y4 + VPSHUFB ·rol8<>+0(SB), Y1, Y1 + VPSHUFB ·rol8<>+0(SB), Y2, Y2 + VPSHUFB ·rol8<>+0(SB), Y3, Y3 + VPADDD Y4, Y12, Y12 + VPADDD Y1, Y13, Y13 + VPADDD Y2, Y8, Y8 + VPADDD Y3, Y15, Y15 + VPXOR Y12, Y14, Y14 + VPXOR Y13, Y9, Y9 + VPXOR Y8, Y10, Y10 + VPXOR Y15, Y11, Y11 + VMOVDQA Y15, 224(BP) + VPSLLD $0x07, Y14, Y15 + VPSRLD $0x19, Y14, Y14 + VPXOR Y15, Y14, Y14 + VPSLLD $0x07, Y9, Y15 + VPSRLD $0x19, Y9, Y9 + VPXOR Y15, Y9, Y9 + VPSLLD $0x07, Y10, Y15 + VPSRLD $0x19, Y10, Y10 + VPXOR Y15, Y10, Y10 + VPSLLD $0x07, Y11, Y15 + VPSRLD $0x19, Y11, Y11 + VPXOR Y15, Y11, Y11 + VMOVDQA 224(BP), Y15 + VPALIGNR $0x0c, Y14, Y14, Y14 + VPALIGNR $0x0c, Y9, Y9, Y9 + VPALIGNR $0x0c, Y10, Y10, Y10 + VPALIGNR $0x0c, Y11, Y11, Y11 + VPALIGNR $0x08, Y12, Y12, Y12 + VPALIGNR $0x08, Y13, Y13, Y13 + VPALIGNR $0x08, Y8, Y8, Y8 + VPALIGNR $0x08, Y15, Y15, Y15 + VPALIGNR $0x04, Y4, Y4, Y4 + VPALIGNR $0x04, Y1, Y1, Y1 + VPALIGNR $0x04, Y2, Y2, Y2 + VPALIGNR $0x04, Y3, Y3, Y3 + DECQ CX + JG sealAVX2Tail512LoopA + DECQ R9 + JGE sealAVX2Tail512LoopB + VPADDD ·chacha20Constants<>+0(SB), Y0, Y0 + VPADDD ·chacha20Constants<>+0(SB), Y5, Y5 + VPADDD ·chacha20Constants<>+0(SB), Y6, Y6 + VPADDD ·chacha20Constants<>+0(SB), Y7, Y7 + VPADDD 32(BP), Y14, Y14 + VPADDD 32(BP), Y9, Y9 + VPADDD 32(BP), Y10, Y10 + VPADDD 32(BP), Y11, Y11 + VPADDD 64(BP), Y12, Y12 + VPADDD 64(BP), Y13, Y13 + VPADDD 64(BP), Y8, Y8 + VPADDD 64(BP), Y15, Y15 + VPADDD 96(BP), Y4, Y4 + VPADDD 128(BP), Y1, Y1 + VPADDD 160(BP), Y2, Y2 + VPADDD 192(BP), Y3, Y3 + VMOVDQA Y15, 224(BP) + VPERM2I128 $0x02, Y0, Y14, Y15 + VPXOR (SI), Y15, Y15 + VMOVDQU Y15, (DI) + VPERM2I128 $0x02, Y12, Y4, Y15 + VPXOR 32(SI), Y15, Y15 + VMOVDQU Y15, 32(DI) + VPERM2I128 $0x13, Y0, Y14, Y15 + VPXOR 64(SI), Y15, Y15 + VMOVDQU Y15, 64(DI) + VPERM2I128 $0x13, Y12, Y4, Y15 + VPXOR 96(SI), Y15, Y15 + VMOVDQU Y15, 96(DI) + VPERM2I128 $0x02, Y5, Y9, Y0 + VPERM2I128 $0x02, Y13, Y1, Y14 + VPERM2I128 $0x13, Y5, Y9, Y12 + VPERM2I128 $0x13, Y13, Y1, Y4 + VPXOR 128(SI), Y0, Y0 + VPXOR 160(SI), Y14, Y14 + VPXOR 192(SI), Y12, Y12 + VPXOR 224(SI), Y4, Y4 + VMOVDQU Y0, 128(DI) + VMOVDQU Y14, 160(DI) + VMOVDQU Y12, 192(DI) + VMOVDQU Y4, 224(DI) + VPERM2I128 $0x02, Y6, Y10, Y0 + VPERM2I128 $0x02, Y8, Y2, Y14 + VPERM2I128 $0x13, Y6, Y10, Y12 + VPERM2I128 $0x13, Y8, Y2, Y4 + VPXOR 256(SI), Y0, Y0 + VPXOR 288(SI), Y14, Y14 + VPXOR 320(SI), Y12, Y12 + VPXOR 352(SI), Y4, Y4 + VMOVDQU Y0, 256(DI) + VMOVDQU Y14, 288(DI) + VMOVDQU Y12, 320(DI) + VMOVDQU Y4, 352(DI) + MOVQ $0x00000180, CX + LEAQ 384(SI), SI + SUBQ $0x00000180, BX + VPERM2I128 $0x02, Y7, Y11, Y0 + VPERM2I128 $0x02, 224(BP), Y3, Y14 + VPERM2I128 $0x13, Y7, Y11, Y12 + VPERM2I128 $0x13, 224(BP), Y3, Y4 + JMP sealAVX2SealHash diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go index 333da285b3..bd896bdc76 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego +//go:build (!amd64 && !ppc64le && !ppc64 && !s390x) || !gc || purego package poly1305 diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s index e0d3c64756..133757384b 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s @@ -1,108 +1,93 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. +// Code generated by command: go run sum_amd64_asm.go -out ../sum_amd64.s -pkg poly1305. DO NOT EDIT. //go:build gc && !purego -#include "textflag.h" - -#define POLY1305_ADD(msg, h0, h1, h2) \ - ADDQ 0(msg), h0; \ - ADCQ 8(msg), h1; \ - ADCQ $1, h2; \ - LEAQ 16(msg), msg - -#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \ - MOVQ r0, AX; \ - MULQ h0; \ - MOVQ AX, t0; \ - MOVQ DX, t1; \ - MOVQ r0, AX; \ - MULQ h1; \ - ADDQ AX, t1; \ - ADCQ $0, DX; \ - MOVQ r0, t2; \ - IMULQ h2, t2; \ - ADDQ DX, t2; \ - \ - MOVQ r1, AX; \ - MULQ h0; \ - ADDQ AX, t1; \ - ADCQ $0, DX; \ - MOVQ DX, h0; \ - MOVQ r1, t3; \ - IMULQ h2, t3; \ - MOVQ r1, AX; \ - MULQ h1; \ - ADDQ AX, t2; \ - ADCQ DX, t3; \ - ADDQ h0, t2; \ - ADCQ $0, t3; \ - \ - MOVQ t0, h0; \ - MOVQ t1, h1; \ - MOVQ t2, h2; \ - ANDQ $3, h2; \ - MOVQ t2, t0; \ - ANDQ $0xFFFFFFFFFFFFFFFC, t0; \ - ADDQ t0, h0; \ - ADCQ t3, h1; \ - ADCQ $0, h2; \ - SHRQ $2, t3, t2; \ - SHRQ $2, t3; \ - ADDQ t2, h0; \ - ADCQ t3, h1; \ - ADCQ $0, h2 - -// func update(state *[7]uint64, msg []byte) +// func update(state *macState, msg []byte) TEXT ·update(SB), $0-32 MOVQ state+0(FP), DI MOVQ msg_base+8(FP), SI MOVQ msg_len+16(FP), R15 - - MOVQ 0(DI), R8 // h0 - MOVQ 8(DI), R9 // h1 - MOVQ 16(DI), R10 // h2 - MOVQ 24(DI), R11 // r0 - MOVQ 32(DI), R12 // r1 - - CMPQ R15, $16 + MOVQ (DI), R8 + MOVQ 8(DI), R9 + MOVQ 16(DI), R10 + MOVQ 24(DI), R11 + MOVQ 32(DI), R12 + CMPQ R15, $0x10 JB bytes_between_0_and_15 loop: - POLY1305_ADD(SI, R8, R9, R10) + ADDQ (SI), R8 + ADCQ 8(SI), R9 + ADCQ $0x01, R10 + LEAQ 16(SI), SI multiply: - POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) - SUBQ $16, R15 - CMPQ R15, $16 - JAE loop + MOVQ R11, AX + MULQ R8 + MOVQ AX, BX + MOVQ DX, CX + MOVQ R11, AX + MULQ R9 + ADDQ AX, CX + ADCQ $0x00, DX + MOVQ R11, R13 + IMULQ R10, R13 + ADDQ DX, R13 + MOVQ R12, AX + MULQ R8 + ADDQ AX, CX + ADCQ $0x00, DX + MOVQ DX, R8 + MOVQ R12, R14 + IMULQ R10, R14 + MOVQ R12, AX + MULQ R9 + ADDQ AX, R13 + ADCQ DX, R14 + ADDQ R8, R13 + ADCQ $0x00, R14 + MOVQ BX, R8 + MOVQ CX, R9 + MOVQ R13, R10 + ANDQ $0x03, R10 + MOVQ R13, BX + ANDQ $-4, BX + ADDQ BX, R8 + ADCQ R14, R9 + ADCQ $0x00, R10 + SHRQ $0x02, R14, R13 + SHRQ $0x02, R14 + ADDQ R13, R8 + ADCQ R14, R9 + ADCQ $0x00, R10 + SUBQ $0x10, R15 + CMPQ R15, $0x10 + JAE loop bytes_between_0_and_15: TESTQ R15, R15 JZ done - MOVQ $1, BX + MOVQ $0x00000001, BX XORQ CX, CX XORQ R13, R13 ADDQ R15, SI flush_buffer: - SHLQ $8, BX, CX - SHLQ $8, BX + SHLQ $0x08, BX, CX + SHLQ $0x08, BX MOVB -1(SI), R13 XORQ R13, BX DECQ SI DECQ R15 JNZ flush_buffer - ADDQ BX, R8 ADCQ CX, R9 - ADCQ $0, R10 - MOVQ $16, R15 + ADCQ $0x00, R10 + MOVQ $0x00000010, R15 JMP multiply done: - MOVQ R8, 0(DI) + MOVQ R8, (DI) MOVQ R9, 8(DI) MOVQ R10, 16(DI) RET diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go similarity index 95% rename from vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go rename to vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go index 4aec4874b5..1a1679aaad 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build gc && !purego +//go:build gc && !purego && (ppc64 || ppc64le) package poly1305 diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s similarity index 89% rename from vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s rename to vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s index b3c1699bff..6899a1dabc 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s @@ -2,15 +2,25 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build gc && !purego +//go:build gc && !purego && (ppc64 || ppc64le) #include "textflag.h" // This was ported from the amd64 implementation. +#ifdef GOARCH_ppc64le +#define LE_MOVD MOVD +#define LE_MOVWZ MOVWZ +#define LE_MOVHZ MOVHZ +#else +#define LE_MOVD MOVDBR +#define LE_MOVWZ MOVWBR +#define LE_MOVHZ MOVHBR +#endif + #define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \ - MOVD (msg), t0; \ - MOVD 8(msg), t1; \ + LE_MOVD (msg)( R0), t0; \ + LE_MOVD (msg)(R24), t1; \ MOVD $1, t2; \ ADDC t0, h0, h0; \ ADDE t1, h1, h1; \ @@ -50,10 +60,6 @@ ADDE t3, h1, h1; \ ADDZE h2 -DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF -DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC -GLOBL ·poly1305Mask<>(SB), RODATA, $16 - // func update(state *[7]uint64, msg []byte) TEXT ·update(SB), $0-32 MOVD state+0(FP), R3 @@ -66,6 +72,8 @@ TEXT ·update(SB), $0-32 MOVD 24(R3), R11 // r0 MOVD 32(R3), R12 // r1 + MOVD $8, R24 + CMP R5, $16 BLT bytes_between_0_and_15 @@ -94,7 +102,7 @@ flush_buffer: // Greater than 8 -- load the rightmost remaining bytes in msg // and put into R17 (h1) - MOVD (R4)(R21), R17 + LE_MOVD (R4)(R21), R17 MOVD $16, R22 // Find the offset to those bytes @@ -118,7 +126,7 @@ just1: BLT less8 // Exactly 8 - MOVD (R4), R16 + LE_MOVD (R4), R16 CMP R17, $0 @@ -133,7 +141,7 @@ less8: MOVD $0, R22 // shift count CMP R5, $4 BLT less4 - MOVWZ (R4), R16 + LE_MOVWZ (R4), R16 ADD $4, R4 ADD $-4, R5 MOVD $32, R22 @@ -141,7 +149,7 @@ less8: less4: CMP R5, $2 BLT less2 - MOVHZ (R4), R21 + LE_MOVHZ (R4), R21 SLD R22, R21, R21 OR R16, R21, R16 ADD $16, R22 diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s b/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s index fcce0234b6..3883e0ec22 100644 --- a/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s +++ b/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s @@ -1,880 +1,880 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. +// Code generated by command: go run salsa20_amd64_asm.go -out ../salsa20_amd64.s -pkg salsa. DO NOT EDIT. //go:build amd64 && !purego && gc -// This code was translated into a form compatible with 6a from the public -// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html +// func salsa2020XORKeyStream(out *byte, in *byte, n uint64, nonce *byte, key *byte) +// Requires: SSE2 +TEXT ·salsa2020XORKeyStream(SB), $456-40 + // This needs up to 64 bytes at 360(R12); hence the non-obvious frame size. + MOVQ out+0(FP), DI + MOVQ in+8(FP), SI + MOVQ n+16(FP), DX + MOVQ nonce+24(FP), CX + MOVQ key+32(FP), R8 + MOVQ SP, R12 + ADDQ $0x1f, R12 + ANDQ $-32, R12 + MOVQ DX, R9 + MOVQ CX, DX + MOVQ R8, R10 + CMPQ R9, $0x00 + JBE DONE + MOVL 20(R10), CX + MOVL (R10), R8 + MOVL (DX), AX + MOVL 16(R10), R11 + MOVL CX, (R12) + MOVL R8, 4(R12) + MOVL AX, 8(R12) + MOVL R11, 12(R12) + MOVL 8(DX), CX + MOVL 24(R10), R8 + MOVL 4(R10), AX + MOVL 4(DX), R11 + MOVL CX, 16(R12) + MOVL R8, 20(R12) + MOVL AX, 24(R12) + MOVL R11, 28(R12) + MOVL 12(DX), CX + MOVL 12(R10), DX + MOVL 28(R10), R8 + MOVL 8(R10), AX + MOVL DX, 32(R12) + MOVL CX, 36(R12) + MOVL R8, 40(R12) + MOVL AX, 44(R12) + MOVQ $0x61707865, DX + MOVQ $0x3320646e, CX + MOVQ $0x79622d32, R8 + MOVQ $0x6b206574, AX + MOVL DX, 48(R12) + MOVL CX, 52(R12) + MOVL R8, 56(R12) + MOVL AX, 60(R12) + CMPQ R9, $0x00000100 + JB BYTESBETWEEN1AND255 + MOVOA 48(R12), X0 + PSHUFL $0x55, X0, X1 + PSHUFL $0xaa, X0, X2 + PSHUFL $0xff, X0, X3 + PSHUFL $0x00, X0, X0 + MOVOA X1, 64(R12) + MOVOA X2, 80(R12) + MOVOA X3, 96(R12) + MOVOA X0, 112(R12) + MOVOA (R12), X0 + PSHUFL $0xaa, X0, X1 + PSHUFL $0xff, X0, X2 + PSHUFL $0x00, X0, X3 + PSHUFL $0x55, X0, X0 + MOVOA X1, 128(R12) + MOVOA X2, 144(R12) + MOVOA X3, 160(R12) + MOVOA X0, 176(R12) + MOVOA 16(R12), X0 + PSHUFL $0xff, X0, X1 + PSHUFL $0x55, X0, X2 + PSHUFL $0xaa, X0, X0 + MOVOA X1, 192(R12) + MOVOA X2, 208(R12) + MOVOA X0, 224(R12) + MOVOA 32(R12), X0 + PSHUFL $0x00, X0, X1 + PSHUFL $0xaa, X0, X2 + PSHUFL $0xff, X0, X0 + MOVOA X1, 240(R12) + MOVOA X2, 256(R12) + MOVOA X0, 272(R12) -// func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte) -// This needs up to 64 bytes at 360(R12); hence the non-obvious frame size. -TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment - MOVQ out+0(FP),DI - MOVQ in+8(FP),SI - MOVQ n+16(FP),DX - MOVQ nonce+24(FP),CX - MOVQ key+32(FP),R8 +BYTESATLEAST256: + MOVL 16(R12), DX + MOVL 36(R12), CX + MOVL DX, 288(R12) + MOVL CX, 304(R12) + SHLQ $0x20, CX + ADDQ CX, DX + ADDQ $0x01, DX + MOVQ DX, CX + SHRQ $0x20, CX + MOVL DX, 292(R12) + MOVL CX, 308(R12) + ADDQ $0x01, DX + MOVQ DX, CX + SHRQ $0x20, CX + MOVL DX, 296(R12) + MOVL CX, 312(R12) + ADDQ $0x01, DX + MOVQ DX, CX + SHRQ $0x20, CX + MOVL DX, 300(R12) + MOVL CX, 316(R12) + ADDQ $0x01, DX + MOVQ DX, CX + SHRQ $0x20, CX + MOVL DX, 16(R12) + MOVL CX, 36(R12) + MOVQ R9, 352(R12) + MOVQ $0x00000014, DX + MOVOA 64(R12), X0 + MOVOA 80(R12), X1 + MOVOA 96(R12), X2 + MOVOA 256(R12), X3 + MOVOA 272(R12), X4 + MOVOA 128(R12), X5 + MOVOA 144(R12), X6 + MOVOA 176(R12), X7 + MOVOA 192(R12), X8 + MOVOA 208(R12), X9 + MOVOA 224(R12), X10 + MOVOA 304(R12), X11 + MOVOA 112(R12), X12 + MOVOA 160(R12), X13 + MOVOA 240(R12), X14 + MOVOA 288(R12), X15 - MOVQ SP,R12 - ADDQ $31, R12 - ANDQ $~31, R12 +MAINLOOP1: + MOVOA X1, 320(R12) + MOVOA X2, 336(R12) + MOVOA X13, X1 + PADDL X12, X1 + MOVOA X1, X2 + PSLLL $0x07, X1 + PXOR X1, X14 + PSRLL $0x19, X2 + PXOR X2, X14 + MOVOA X7, X1 + PADDL X0, X1 + MOVOA X1, X2 + PSLLL $0x07, X1 + PXOR X1, X11 + PSRLL $0x19, X2 + PXOR X2, X11 + MOVOA X12, X1 + PADDL X14, X1 + MOVOA X1, X2 + PSLLL $0x09, X1 + PXOR X1, X15 + PSRLL $0x17, X2 + PXOR X2, X15 + MOVOA X0, X1 + PADDL X11, X1 + MOVOA X1, X2 + PSLLL $0x09, X1 + PXOR X1, X9 + PSRLL $0x17, X2 + PXOR X2, X9 + MOVOA X14, X1 + PADDL X15, X1 + MOVOA X1, X2 + PSLLL $0x0d, X1 + PXOR X1, X13 + PSRLL $0x13, X2 + PXOR X2, X13 + MOVOA X11, X1 + PADDL X9, X1 + MOVOA X1, X2 + PSLLL $0x0d, X1 + PXOR X1, X7 + PSRLL $0x13, X2 + PXOR X2, X7 + MOVOA X15, X1 + PADDL X13, X1 + MOVOA X1, X2 + PSLLL $0x12, X1 + PXOR X1, X12 + PSRLL $0x0e, X2 + PXOR X2, X12 + MOVOA 320(R12), X1 + MOVOA X12, 320(R12) + MOVOA X9, X2 + PADDL X7, X2 + MOVOA X2, X12 + PSLLL $0x12, X2 + PXOR X2, X0 + PSRLL $0x0e, X12 + PXOR X12, X0 + MOVOA X5, X2 + PADDL X1, X2 + MOVOA X2, X12 + PSLLL $0x07, X2 + PXOR X2, X3 + PSRLL $0x19, X12 + PXOR X12, X3 + MOVOA 336(R12), X2 + MOVOA X0, 336(R12) + MOVOA X6, X0 + PADDL X2, X0 + MOVOA X0, X12 + PSLLL $0x07, X0 + PXOR X0, X4 + PSRLL $0x19, X12 + PXOR X12, X4 + MOVOA X1, X0 + PADDL X3, X0 + MOVOA X0, X12 + PSLLL $0x09, X0 + PXOR X0, X10 + PSRLL $0x17, X12 + PXOR X12, X10 + MOVOA X2, X0 + PADDL X4, X0 + MOVOA X0, X12 + PSLLL $0x09, X0 + PXOR X0, X8 + PSRLL $0x17, X12 + PXOR X12, X8 + MOVOA X3, X0 + PADDL X10, X0 + MOVOA X0, X12 + PSLLL $0x0d, X0 + PXOR X0, X5 + PSRLL $0x13, X12 + PXOR X12, X5 + MOVOA X4, X0 + PADDL X8, X0 + MOVOA X0, X12 + PSLLL $0x0d, X0 + PXOR X0, X6 + PSRLL $0x13, X12 + PXOR X12, X6 + MOVOA X10, X0 + PADDL X5, X0 + MOVOA X0, X12 + PSLLL $0x12, X0 + PXOR X0, X1 + PSRLL $0x0e, X12 + PXOR X12, X1 + MOVOA 320(R12), X0 + MOVOA X1, 320(R12) + MOVOA X4, X1 + PADDL X0, X1 + MOVOA X1, X12 + PSLLL $0x07, X1 + PXOR X1, X7 + PSRLL $0x19, X12 + PXOR X12, X7 + MOVOA X8, X1 + PADDL X6, X1 + MOVOA X1, X12 + PSLLL $0x12, X1 + PXOR X1, X2 + PSRLL $0x0e, X12 + PXOR X12, X2 + MOVOA 336(R12), X12 + MOVOA X2, 336(R12) + MOVOA X14, X1 + PADDL X12, X1 + MOVOA X1, X2 + PSLLL $0x07, X1 + PXOR X1, X5 + PSRLL $0x19, X2 + PXOR X2, X5 + MOVOA X0, X1 + PADDL X7, X1 + MOVOA X1, X2 + PSLLL $0x09, X1 + PXOR X1, X10 + PSRLL $0x17, X2 + PXOR X2, X10 + MOVOA X12, X1 + PADDL X5, X1 + MOVOA X1, X2 + PSLLL $0x09, X1 + PXOR X1, X8 + PSRLL $0x17, X2 + PXOR X2, X8 + MOVOA X7, X1 + PADDL X10, X1 + MOVOA X1, X2 + PSLLL $0x0d, X1 + PXOR X1, X4 + PSRLL $0x13, X2 + PXOR X2, X4 + MOVOA X5, X1 + PADDL X8, X1 + MOVOA X1, X2 + PSLLL $0x0d, X1 + PXOR X1, X14 + PSRLL $0x13, X2 + PXOR X2, X14 + MOVOA X10, X1 + PADDL X4, X1 + MOVOA X1, X2 + PSLLL $0x12, X1 + PXOR X1, X0 + PSRLL $0x0e, X2 + PXOR X2, X0 + MOVOA 320(R12), X1 + MOVOA X0, 320(R12) + MOVOA X8, X0 + PADDL X14, X0 + MOVOA X0, X2 + PSLLL $0x12, X0 + PXOR X0, X12 + PSRLL $0x0e, X2 + PXOR X2, X12 + MOVOA X11, X0 + PADDL X1, X0 + MOVOA X0, X2 + PSLLL $0x07, X0 + PXOR X0, X6 + PSRLL $0x19, X2 + PXOR X2, X6 + MOVOA 336(R12), X2 + MOVOA X12, 336(R12) + MOVOA X3, X0 + PADDL X2, X0 + MOVOA X0, X12 + PSLLL $0x07, X0 + PXOR X0, X13 + PSRLL $0x19, X12 + PXOR X12, X13 + MOVOA X1, X0 + PADDL X6, X0 + MOVOA X0, X12 + PSLLL $0x09, X0 + PXOR X0, X15 + PSRLL $0x17, X12 + PXOR X12, X15 + MOVOA X2, X0 + PADDL X13, X0 + MOVOA X0, X12 + PSLLL $0x09, X0 + PXOR X0, X9 + PSRLL $0x17, X12 + PXOR X12, X9 + MOVOA X6, X0 + PADDL X15, X0 + MOVOA X0, X12 + PSLLL $0x0d, X0 + PXOR X0, X11 + PSRLL $0x13, X12 + PXOR X12, X11 + MOVOA X13, X0 + PADDL X9, X0 + MOVOA X0, X12 + PSLLL $0x0d, X0 + PXOR X0, X3 + PSRLL $0x13, X12 + PXOR X12, X3 + MOVOA X15, X0 + PADDL X11, X0 + MOVOA X0, X12 + PSLLL $0x12, X0 + PXOR X0, X1 + PSRLL $0x0e, X12 + PXOR X12, X1 + MOVOA X9, X0 + PADDL X3, X0 + MOVOA X0, X12 + PSLLL $0x12, X0 + PXOR X0, X2 + PSRLL $0x0e, X12 + PXOR X12, X2 + MOVOA 320(R12), X12 + MOVOA 336(R12), X0 + SUBQ $0x02, DX + JA MAINLOOP1 + PADDL 112(R12), X12 + PADDL 176(R12), X7 + PADDL 224(R12), X10 + PADDL 272(R12), X4 + MOVD X12, DX + MOVD X7, CX + MOVD X10, R8 + MOVD X4, R9 + PSHUFL $0x39, X12, X12 + PSHUFL $0x39, X7, X7 + PSHUFL $0x39, X10, X10 + PSHUFL $0x39, X4, X4 + XORL (SI), DX + XORL 4(SI), CX + XORL 8(SI), R8 + XORL 12(SI), R9 + MOVL DX, (DI) + MOVL CX, 4(DI) + MOVL R8, 8(DI) + MOVL R9, 12(DI) + MOVD X12, DX + MOVD X7, CX + MOVD X10, R8 + MOVD X4, R9 + PSHUFL $0x39, X12, X12 + PSHUFL $0x39, X7, X7 + PSHUFL $0x39, X10, X10 + PSHUFL $0x39, X4, X4 + XORL 64(SI), DX + XORL 68(SI), CX + XORL 72(SI), R8 + XORL 76(SI), R9 + MOVL DX, 64(DI) + MOVL CX, 68(DI) + MOVL R8, 72(DI) + MOVL R9, 76(DI) + MOVD X12, DX + MOVD X7, CX + MOVD X10, R8 + MOVD X4, R9 + PSHUFL $0x39, X12, X12 + PSHUFL $0x39, X7, X7 + PSHUFL $0x39, X10, X10 + PSHUFL $0x39, X4, X4 + XORL 128(SI), DX + XORL 132(SI), CX + XORL 136(SI), R8 + XORL 140(SI), R9 + MOVL DX, 128(DI) + MOVL CX, 132(DI) + MOVL R8, 136(DI) + MOVL R9, 140(DI) + MOVD X12, DX + MOVD X7, CX + MOVD X10, R8 + MOVD X4, R9 + XORL 192(SI), DX + XORL 196(SI), CX + XORL 200(SI), R8 + XORL 204(SI), R9 + MOVL DX, 192(DI) + MOVL CX, 196(DI) + MOVL R8, 200(DI) + MOVL R9, 204(DI) + PADDL 240(R12), X14 + PADDL 64(R12), X0 + PADDL 128(R12), X5 + PADDL 192(R12), X8 + MOVD X14, DX + MOVD X0, CX + MOVD X5, R8 + MOVD X8, R9 + PSHUFL $0x39, X14, X14 + PSHUFL $0x39, X0, X0 + PSHUFL $0x39, X5, X5 + PSHUFL $0x39, X8, X8 + XORL 16(SI), DX + XORL 20(SI), CX + XORL 24(SI), R8 + XORL 28(SI), R9 + MOVL DX, 16(DI) + MOVL CX, 20(DI) + MOVL R8, 24(DI) + MOVL R9, 28(DI) + MOVD X14, DX + MOVD X0, CX + MOVD X5, R8 + MOVD X8, R9 + PSHUFL $0x39, X14, X14 + PSHUFL $0x39, X0, X0 + PSHUFL $0x39, X5, X5 + PSHUFL $0x39, X8, X8 + XORL 80(SI), DX + XORL 84(SI), CX + XORL 88(SI), R8 + XORL 92(SI), R9 + MOVL DX, 80(DI) + MOVL CX, 84(DI) + MOVL R8, 88(DI) + MOVL R9, 92(DI) + MOVD X14, DX + MOVD X0, CX + MOVD X5, R8 + MOVD X8, R9 + PSHUFL $0x39, X14, X14 + PSHUFL $0x39, X0, X0 + PSHUFL $0x39, X5, X5 + PSHUFL $0x39, X8, X8 + XORL 144(SI), DX + XORL 148(SI), CX + XORL 152(SI), R8 + XORL 156(SI), R9 + MOVL DX, 144(DI) + MOVL CX, 148(DI) + MOVL R8, 152(DI) + MOVL R9, 156(DI) + MOVD X14, DX + MOVD X0, CX + MOVD X5, R8 + MOVD X8, R9 + XORL 208(SI), DX + XORL 212(SI), CX + XORL 216(SI), R8 + XORL 220(SI), R9 + MOVL DX, 208(DI) + MOVL CX, 212(DI) + MOVL R8, 216(DI) + MOVL R9, 220(DI) + PADDL 288(R12), X15 + PADDL 304(R12), X11 + PADDL 80(R12), X1 + PADDL 144(R12), X6 + MOVD X15, DX + MOVD X11, CX + MOVD X1, R8 + MOVD X6, R9 + PSHUFL $0x39, X15, X15 + PSHUFL $0x39, X11, X11 + PSHUFL $0x39, X1, X1 + PSHUFL $0x39, X6, X6 + XORL 32(SI), DX + XORL 36(SI), CX + XORL 40(SI), R8 + XORL 44(SI), R9 + MOVL DX, 32(DI) + MOVL CX, 36(DI) + MOVL R8, 40(DI) + MOVL R9, 44(DI) + MOVD X15, DX + MOVD X11, CX + MOVD X1, R8 + MOVD X6, R9 + PSHUFL $0x39, X15, X15 + PSHUFL $0x39, X11, X11 + PSHUFL $0x39, X1, X1 + PSHUFL $0x39, X6, X6 + XORL 96(SI), DX + XORL 100(SI), CX + XORL 104(SI), R8 + XORL 108(SI), R9 + MOVL DX, 96(DI) + MOVL CX, 100(DI) + MOVL R8, 104(DI) + MOVL R9, 108(DI) + MOVD X15, DX + MOVD X11, CX + MOVD X1, R8 + MOVD X6, R9 + PSHUFL $0x39, X15, X15 + PSHUFL $0x39, X11, X11 + PSHUFL $0x39, X1, X1 + PSHUFL $0x39, X6, X6 + XORL 160(SI), DX + XORL 164(SI), CX + XORL 168(SI), R8 + XORL 172(SI), R9 + MOVL DX, 160(DI) + MOVL CX, 164(DI) + MOVL R8, 168(DI) + MOVL R9, 172(DI) + MOVD X15, DX + MOVD X11, CX + MOVD X1, R8 + MOVD X6, R9 + XORL 224(SI), DX + XORL 228(SI), CX + XORL 232(SI), R8 + XORL 236(SI), R9 + MOVL DX, 224(DI) + MOVL CX, 228(DI) + MOVL R8, 232(DI) + MOVL R9, 236(DI) + PADDL 160(R12), X13 + PADDL 208(R12), X9 + PADDL 256(R12), X3 + PADDL 96(R12), X2 + MOVD X13, DX + MOVD X9, CX + MOVD X3, R8 + MOVD X2, R9 + PSHUFL $0x39, X13, X13 + PSHUFL $0x39, X9, X9 + PSHUFL $0x39, X3, X3 + PSHUFL $0x39, X2, X2 + XORL 48(SI), DX + XORL 52(SI), CX + XORL 56(SI), R8 + XORL 60(SI), R9 + MOVL DX, 48(DI) + MOVL CX, 52(DI) + MOVL R8, 56(DI) + MOVL R9, 60(DI) + MOVD X13, DX + MOVD X9, CX + MOVD X3, R8 + MOVD X2, R9 + PSHUFL $0x39, X13, X13 + PSHUFL $0x39, X9, X9 + PSHUFL $0x39, X3, X3 + PSHUFL $0x39, X2, X2 + XORL 112(SI), DX + XORL 116(SI), CX + XORL 120(SI), R8 + XORL 124(SI), R9 + MOVL DX, 112(DI) + MOVL CX, 116(DI) + MOVL R8, 120(DI) + MOVL R9, 124(DI) + MOVD X13, DX + MOVD X9, CX + MOVD X3, R8 + MOVD X2, R9 + PSHUFL $0x39, X13, X13 + PSHUFL $0x39, X9, X9 + PSHUFL $0x39, X3, X3 + PSHUFL $0x39, X2, X2 + XORL 176(SI), DX + XORL 180(SI), CX + XORL 184(SI), R8 + XORL 188(SI), R9 + MOVL DX, 176(DI) + MOVL CX, 180(DI) + MOVL R8, 184(DI) + MOVL R9, 188(DI) + MOVD X13, DX + MOVD X9, CX + MOVD X3, R8 + MOVD X2, R9 + XORL 240(SI), DX + XORL 244(SI), CX + XORL 248(SI), R8 + XORL 252(SI), R9 + MOVL DX, 240(DI) + MOVL CX, 244(DI) + MOVL R8, 248(DI) + MOVL R9, 252(DI) + MOVQ 352(R12), R9 + SUBQ $0x00000100, R9 + ADDQ $0x00000100, SI + ADDQ $0x00000100, DI + CMPQ R9, $0x00000100 + JAE BYTESATLEAST256 + CMPQ R9, $0x00 + JBE DONE - MOVQ DX,R9 - MOVQ CX,DX - MOVQ R8,R10 - CMPQ R9,$0 - JBE DONE - START: - MOVL 20(R10),CX - MOVL 0(R10),R8 - MOVL 0(DX),AX - MOVL 16(R10),R11 - MOVL CX,0(R12) - MOVL R8, 4 (R12) - MOVL AX, 8 (R12) - MOVL R11, 12 (R12) - MOVL 8(DX),CX - MOVL 24(R10),R8 - MOVL 4(R10),AX - MOVL 4(DX),R11 - MOVL CX,16(R12) - MOVL R8, 20 (R12) - MOVL AX, 24 (R12) - MOVL R11, 28 (R12) - MOVL 12(DX),CX - MOVL 12(R10),DX - MOVL 28(R10),R8 - MOVL 8(R10),AX - MOVL DX,32(R12) - MOVL CX, 36 (R12) - MOVL R8, 40 (R12) - MOVL AX, 44 (R12) - MOVQ $1634760805,DX - MOVQ $857760878,CX - MOVQ $2036477234,R8 - MOVQ $1797285236,AX - MOVL DX,48(R12) - MOVL CX, 52 (R12) - MOVL R8, 56 (R12) - MOVL AX, 60 (R12) - CMPQ R9,$256 - JB BYTESBETWEEN1AND255 - MOVOA 48(R12),X0 - PSHUFL $0X55,X0,X1 - PSHUFL $0XAA,X0,X2 - PSHUFL $0XFF,X0,X3 - PSHUFL $0X00,X0,X0 - MOVOA X1,64(R12) - MOVOA X2,80(R12) - MOVOA X3,96(R12) - MOVOA X0,112(R12) - MOVOA 0(R12),X0 - PSHUFL $0XAA,X0,X1 - PSHUFL $0XFF,X0,X2 - PSHUFL $0X00,X0,X3 - PSHUFL $0X55,X0,X0 - MOVOA X1,128(R12) - MOVOA X2,144(R12) - MOVOA X3,160(R12) - MOVOA X0,176(R12) - MOVOA 16(R12),X0 - PSHUFL $0XFF,X0,X1 - PSHUFL $0X55,X0,X2 - PSHUFL $0XAA,X0,X0 - MOVOA X1,192(R12) - MOVOA X2,208(R12) - MOVOA X0,224(R12) - MOVOA 32(R12),X0 - PSHUFL $0X00,X0,X1 - PSHUFL $0XAA,X0,X2 - PSHUFL $0XFF,X0,X0 - MOVOA X1,240(R12) - MOVOA X2,256(R12) - MOVOA X0,272(R12) - BYTESATLEAST256: - MOVL 16(R12),DX - MOVL 36 (R12),CX - MOVL DX,288(R12) - MOVL CX,304(R12) - SHLQ $32,CX - ADDQ CX,DX - ADDQ $1,DX - MOVQ DX,CX - SHRQ $32,CX - MOVL DX, 292 (R12) - MOVL CX, 308 (R12) - ADDQ $1,DX - MOVQ DX,CX - SHRQ $32,CX - MOVL DX, 296 (R12) - MOVL CX, 312 (R12) - ADDQ $1,DX - MOVQ DX,CX - SHRQ $32,CX - MOVL DX, 300 (R12) - MOVL CX, 316 (R12) - ADDQ $1,DX - MOVQ DX,CX - SHRQ $32,CX - MOVL DX,16(R12) - MOVL CX, 36 (R12) - MOVQ R9,352(R12) - MOVQ $20,DX - MOVOA 64(R12),X0 - MOVOA 80(R12),X1 - MOVOA 96(R12),X2 - MOVOA 256(R12),X3 - MOVOA 272(R12),X4 - MOVOA 128(R12),X5 - MOVOA 144(R12),X6 - MOVOA 176(R12),X7 - MOVOA 192(R12),X8 - MOVOA 208(R12),X9 - MOVOA 224(R12),X10 - MOVOA 304(R12),X11 - MOVOA 112(R12),X12 - MOVOA 160(R12),X13 - MOVOA 240(R12),X14 - MOVOA 288(R12),X15 - MAINLOOP1: - MOVOA X1,320(R12) - MOVOA X2,336(R12) - MOVOA X13,X1 - PADDL X12,X1 - MOVOA X1,X2 - PSLLL $7,X1 - PXOR X1,X14 - PSRLL $25,X2 - PXOR X2,X14 - MOVOA X7,X1 - PADDL X0,X1 - MOVOA X1,X2 - PSLLL $7,X1 - PXOR X1,X11 - PSRLL $25,X2 - PXOR X2,X11 - MOVOA X12,X1 - PADDL X14,X1 - MOVOA X1,X2 - PSLLL $9,X1 - PXOR X1,X15 - PSRLL $23,X2 - PXOR X2,X15 - MOVOA X0,X1 - PADDL X11,X1 - MOVOA X1,X2 - PSLLL $9,X1 - PXOR X1,X9 - PSRLL $23,X2 - PXOR X2,X9 - MOVOA X14,X1 - PADDL X15,X1 - MOVOA X1,X2 - PSLLL $13,X1 - PXOR X1,X13 - PSRLL $19,X2 - PXOR X2,X13 - MOVOA X11,X1 - PADDL X9,X1 - MOVOA X1,X2 - PSLLL $13,X1 - PXOR X1,X7 - PSRLL $19,X2 - PXOR X2,X7 - MOVOA X15,X1 - PADDL X13,X1 - MOVOA X1,X2 - PSLLL $18,X1 - PXOR X1,X12 - PSRLL $14,X2 - PXOR X2,X12 - MOVOA 320(R12),X1 - MOVOA X12,320(R12) - MOVOA X9,X2 - PADDL X7,X2 - MOVOA X2,X12 - PSLLL $18,X2 - PXOR X2,X0 - PSRLL $14,X12 - PXOR X12,X0 - MOVOA X5,X2 - PADDL X1,X2 - MOVOA X2,X12 - PSLLL $7,X2 - PXOR X2,X3 - PSRLL $25,X12 - PXOR X12,X3 - MOVOA 336(R12),X2 - MOVOA X0,336(R12) - MOVOA X6,X0 - PADDL X2,X0 - MOVOA X0,X12 - PSLLL $7,X0 - PXOR X0,X4 - PSRLL $25,X12 - PXOR X12,X4 - MOVOA X1,X0 - PADDL X3,X0 - MOVOA X0,X12 - PSLLL $9,X0 - PXOR X0,X10 - PSRLL $23,X12 - PXOR X12,X10 - MOVOA X2,X0 - PADDL X4,X0 - MOVOA X0,X12 - PSLLL $9,X0 - PXOR X0,X8 - PSRLL $23,X12 - PXOR X12,X8 - MOVOA X3,X0 - PADDL X10,X0 - MOVOA X0,X12 - PSLLL $13,X0 - PXOR X0,X5 - PSRLL $19,X12 - PXOR X12,X5 - MOVOA X4,X0 - PADDL X8,X0 - MOVOA X0,X12 - PSLLL $13,X0 - PXOR X0,X6 - PSRLL $19,X12 - PXOR X12,X6 - MOVOA X10,X0 - PADDL X5,X0 - MOVOA X0,X12 - PSLLL $18,X0 - PXOR X0,X1 - PSRLL $14,X12 - PXOR X12,X1 - MOVOA 320(R12),X0 - MOVOA X1,320(R12) - MOVOA X4,X1 - PADDL X0,X1 - MOVOA X1,X12 - PSLLL $7,X1 - PXOR X1,X7 - PSRLL $25,X12 - PXOR X12,X7 - MOVOA X8,X1 - PADDL X6,X1 - MOVOA X1,X12 - PSLLL $18,X1 - PXOR X1,X2 - PSRLL $14,X12 - PXOR X12,X2 - MOVOA 336(R12),X12 - MOVOA X2,336(R12) - MOVOA X14,X1 - PADDL X12,X1 - MOVOA X1,X2 - PSLLL $7,X1 - PXOR X1,X5 - PSRLL $25,X2 - PXOR X2,X5 - MOVOA X0,X1 - PADDL X7,X1 - MOVOA X1,X2 - PSLLL $9,X1 - PXOR X1,X10 - PSRLL $23,X2 - PXOR X2,X10 - MOVOA X12,X1 - PADDL X5,X1 - MOVOA X1,X2 - PSLLL $9,X1 - PXOR X1,X8 - PSRLL $23,X2 - PXOR X2,X8 - MOVOA X7,X1 - PADDL X10,X1 - MOVOA X1,X2 - PSLLL $13,X1 - PXOR X1,X4 - PSRLL $19,X2 - PXOR X2,X4 - MOVOA X5,X1 - PADDL X8,X1 - MOVOA X1,X2 - PSLLL $13,X1 - PXOR X1,X14 - PSRLL $19,X2 - PXOR X2,X14 - MOVOA X10,X1 - PADDL X4,X1 - MOVOA X1,X2 - PSLLL $18,X1 - PXOR X1,X0 - PSRLL $14,X2 - PXOR X2,X0 - MOVOA 320(R12),X1 - MOVOA X0,320(R12) - MOVOA X8,X0 - PADDL X14,X0 - MOVOA X0,X2 - PSLLL $18,X0 - PXOR X0,X12 - PSRLL $14,X2 - PXOR X2,X12 - MOVOA X11,X0 - PADDL X1,X0 - MOVOA X0,X2 - PSLLL $7,X0 - PXOR X0,X6 - PSRLL $25,X2 - PXOR X2,X6 - MOVOA 336(R12),X2 - MOVOA X12,336(R12) - MOVOA X3,X0 - PADDL X2,X0 - MOVOA X0,X12 - PSLLL $7,X0 - PXOR X0,X13 - PSRLL $25,X12 - PXOR X12,X13 - MOVOA X1,X0 - PADDL X6,X0 - MOVOA X0,X12 - PSLLL $9,X0 - PXOR X0,X15 - PSRLL $23,X12 - PXOR X12,X15 - MOVOA X2,X0 - PADDL X13,X0 - MOVOA X0,X12 - PSLLL $9,X0 - PXOR X0,X9 - PSRLL $23,X12 - PXOR X12,X9 - MOVOA X6,X0 - PADDL X15,X0 - MOVOA X0,X12 - PSLLL $13,X0 - PXOR X0,X11 - PSRLL $19,X12 - PXOR X12,X11 - MOVOA X13,X0 - PADDL X9,X0 - MOVOA X0,X12 - PSLLL $13,X0 - PXOR X0,X3 - PSRLL $19,X12 - PXOR X12,X3 - MOVOA X15,X0 - PADDL X11,X0 - MOVOA X0,X12 - PSLLL $18,X0 - PXOR X0,X1 - PSRLL $14,X12 - PXOR X12,X1 - MOVOA X9,X0 - PADDL X3,X0 - MOVOA X0,X12 - PSLLL $18,X0 - PXOR X0,X2 - PSRLL $14,X12 - PXOR X12,X2 - MOVOA 320(R12),X12 - MOVOA 336(R12),X0 - SUBQ $2,DX - JA MAINLOOP1 - PADDL 112(R12),X12 - PADDL 176(R12),X7 - PADDL 224(R12),X10 - PADDL 272(R12),X4 - MOVD X12,DX - MOVD X7,CX - MOVD X10,R8 - MOVD X4,R9 - PSHUFL $0X39,X12,X12 - PSHUFL $0X39,X7,X7 - PSHUFL $0X39,X10,X10 - PSHUFL $0X39,X4,X4 - XORL 0(SI),DX - XORL 4(SI),CX - XORL 8(SI),R8 - XORL 12(SI),R9 - MOVL DX,0(DI) - MOVL CX,4(DI) - MOVL R8,8(DI) - MOVL R9,12(DI) - MOVD X12,DX - MOVD X7,CX - MOVD X10,R8 - MOVD X4,R9 - PSHUFL $0X39,X12,X12 - PSHUFL $0X39,X7,X7 - PSHUFL $0X39,X10,X10 - PSHUFL $0X39,X4,X4 - XORL 64(SI),DX - XORL 68(SI),CX - XORL 72(SI),R8 - XORL 76(SI),R9 - MOVL DX,64(DI) - MOVL CX,68(DI) - MOVL R8,72(DI) - MOVL R9,76(DI) - MOVD X12,DX - MOVD X7,CX - MOVD X10,R8 - MOVD X4,R9 - PSHUFL $0X39,X12,X12 - PSHUFL $0X39,X7,X7 - PSHUFL $0X39,X10,X10 - PSHUFL $0X39,X4,X4 - XORL 128(SI),DX - XORL 132(SI),CX - XORL 136(SI),R8 - XORL 140(SI),R9 - MOVL DX,128(DI) - MOVL CX,132(DI) - MOVL R8,136(DI) - MOVL R9,140(DI) - MOVD X12,DX - MOVD X7,CX - MOVD X10,R8 - MOVD X4,R9 - XORL 192(SI),DX - XORL 196(SI),CX - XORL 200(SI),R8 - XORL 204(SI),R9 - MOVL DX,192(DI) - MOVL CX,196(DI) - MOVL R8,200(DI) - MOVL R9,204(DI) - PADDL 240(R12),X14 - PADDL 64(R12),X0 - PADDL 128(R12),X5 - PADDL 192(R12),X8 - MOVD X14,DX - MOVD X0,CX - MOVD X5,R8 - MOVD X8,R9 - PSHUFL $0X39,X14,X14 - PSHUFL $0X39,X0,X0 - PSHUFL $0X39,X5,X5 - PSHUFL $0X39,X8,X8 - XORL 16(SI),DX - XORL 20(SI),CX - XORL 24(SI),R8 - XORL 28(SI),R9 - MOVL DX,16(DI) - MOVL CX,20(DI) - MOVL R8,24(DI) - MOVL R9,28(DI) - MOVD X14,DX - MOVD X0,CX - MOVD X5,R8 - MOVD X8,R9 - PSHUFL $0X39,X14,X14 - PSHUFL $0X39,X0,X0 - PSHUFL $0X39,X5,X5 - PSHUFL $0X39,X8,X8 - XORL 80(SI),DX - XORL 84(SI),CX - XORL 88(SI),R8 - XORL 92(SI),R9 - MOVL DX,80(DI) - MOVL CX,84(DI) - MOVL R8,88(DI) - MOVL R9,92(DI) - MOVD X14,DX - MOVD X0,CX - MOVD X5,R8 - MOVD X8,R9 - PSHUFL $0X39,X14,X14 - PSHUFL $0X39,X0,X0 - PSHUFL $0X39,X5,X5 - PSHUFL $0X39,X8,X8 - XORL 144(SI),DX - XORL 148(SI),CX - XORL 152(SI),R8 - XORL 156(SI),R9 - MOVL DX,144(DI) - MOVL CX,148(DI) - MOVL R8,152(DI) - MOVL R9,156(DI) - MOVD X14,DX - MOVD X0,CX - MOVD X5,R8 - MOVD X8,R9 - XORL 208(SI),DX - XORL 212(SI),CX - XORL 216(SI),R8 - XORL 220(SI),R9 - MOVL DX,208(DI) - MOVL CX,212(DI) - MOVL R8,216(DI) - MOVL R9,220(DI) - PADDL 288(R12),X15 - PADDL 304(R12),X11 - PADDL 80(R12),X1 - PADDL 144(R12),X6 - MOVD X15,DX - MOVD X11,CX - MOVD X1,R8 - MOVD X6,R9 - PSHUFL $0X39,X15,X15 - PSHUFL $0X39,X11,X11 - PSHUFL $0X39,X1,X1 - PSHUFL $0X39,X6,X6 - XORL 32(SI),DX - XORL 36(SI),CX - XORL 40(SI),R8 - XORL 44(SI),R9 - MOVL DX,32(DI) - MOVL CX,36(DI) - MOVL R8,40(DI) - MOVL R9,44(DI) - MOVD X15,DX - MOVD X11,CX - MOVD X1,R8 - MOVD X6,R9 - PSHUFL $0X39,X15,X15 - PSHUFL $0X39,X11,X11 - PSHUFL $0X39,X1,X1 - PSHUFL $0X39,X6,X6 - XORL 96(SI),DX - XORL 100(SI),CX - XORL 104(SI),R8 - XORL 108(SI),R9 - MOVL DX,96(DI) - MOVL CX,100(DI) - MOVL R8,104(DI) - MOVL R9,108(DI) - MOVD X15,DX - MOVD X11,CX - MOVD X1,R8 - MOVD X6,R9 - PSHUFL $0X39,X15,X15 - PSHUFL $0X39,X11,X11 - PSHUFL $0X39,X1,X1 - PSHUFL $0X39,X6,X6 - XORL 160(SI),DX - XORL 164(SI),CX - XORL 168(SI),R8 - XORL 172(SI),R9 - MOVL DX,160(DI) - MOVL CX,164(DI) - MOVL R8,168(DI) - MOVL R9,172(DI) - MOVD X15,DX - MOVD X11,CX - MOVD X1,R8 - MOVD X6,R9 - XORL 224(SI),DX - XORL 228(SI),CX - XORL 232(SI),R8 - XORL 236(SI),R9 - MOVL DX,224(DI) - MOVL CX,228(DI) - MOVL R8,232(DI) - MOVL R9,236(DI) - PADDL 160(R12),X13 - PADDL 208(R12),X9 - PADDL 256(R12),X3 - PADDL 96(R12),X2 - MOVD X13,DX - MOVD X9,CX - MOVD X3,R8 - MOVD X2,R9 - PSHUFL $0X39,X13,X13 - PSHUFL $0X39,X9,X9 - PSHUFL $0X39,X3,X3 - PSHUFL $0X39,X2,X2 - XORL 48(SI),DX - XORL 52(SI),CX - XORL 56(SI),R8 - XORL 60(SI),R9 - MOVL DX,48(DI) - MOVL CX,52(DI) - MOVL R8,56(DI) - MOVL R9,60(DI) - MOVD X13,DX - MOVD X9,CX - MOVD X3,R8 - MOVD X2,R9 - PSHUFL $0X39,X13,X13 - PSHUFL $0X39,X9,X9 - PSHUFL $0X39,X3,X3 - PSHUFL $0X39,X2,X2 - XORL 112(SI),DX - XORL 116(SI),CX - XORL 120(SI),R8 - XORL 124(SI),R9 - MOVL DX,112(DI) - MOVL CX,116(DI) - MOVL R8,120(DI) - MOVL R9,124(DI) - MOVD X13,DX - MOVD X9,CX - MOVD X3,R8 - MOVD X2,R9 - PSHUFL $0X39,X13,X13 - PSHUFL $0X39,X9,X9 - PSHUFL $0X39,X3,X3 - PSHUFL $0X39,X2,X2 - XORL 176(SI),DX - XORL 180(SI),CX - XORL 184(SI),R8 - XORL 188(SI),R9 - MOVL DX,176(DI) - MOVL CX,180(DI) - MOVL R8,184(DI) - MOVL R9,188(DI) - MOVD X13,DX - MOVD X9,CX - MOVD X3,R8 - MOVD X2,R9 - XORL 240(SI),DX - XORL 244(SI),CX - XORL 248(SI),R8 - XORL 252(SI),R9 - MOVL DX,240(DI) - MOVL CX,244(DI) - MOVL R8,248(DI) - MOVL R9,252(DI) - MOVQ 352(R12),R9 - SUBQ $256,R9 - ADDQ $256,SI - ADDQ $256,DI - CMPQ R9,$256 - JAE BYTESATLEAST256 - CMPQ R9,$0 - JBE DONE - BYTESBETWEEN1AND255: - CMPQ R9,$64 - JAE NOCOPY - MOVQ DI,DX - LEAQ 360(R12),DI - MOVQ R9,CX +BYTESBETWEEN1AND255: + CMPQ R9, $0x40 + JAE NOCOPY + MOVQ DI, DX + LEAQ 360(R12), DI + MOVQ R9, CX REP; MOVSB - LEAQ 360(R12),DI - LEAQ 360(R12),SI - NOCOPY: - MOVQ R9,352(R12) - MOVOA 48(R12),X0 - MOVOA 0(R12),X1 - MOVOA 16(R12),X2 - MOVOA 32(R12),X3 - MOVOA X1,X4 - MOVQ $20,CX - MAINLOOP2: - PADDL X0,X4 - MOVOA X0,X5 - MOVOA X4,X6 - PSLLL $7,X4 - PSRLL $25,X6 - PXOR X4,X3 - PXOR X6,X3 - PADDL X3,X5 - MOVOA X3,X4 - MOVOA X5,X6 - PSLLL $9,X5 - PSRLL $23,X6 - PXOR X5,X2 - PSHUFL $0X93,X3,X3 - PXOR X6,X2 - PADDL X2,X4 - MOVOA X2,X5 - MOVOA X4,X6 - PSLLL $13,X4 - PSRLL $19,X6 - PXOR X4,X1 - PSHUFL $0X4E,X2,X2 - PXOR X6,X1 - PADDL X1,X5 - MOVOA X3,X4 - MOVOA X5,X6 - PSLLL $18,X5 - PSRLL $14,X6 - PXOR X5,X0 - PSHUFL $0X39,X1,X1 - PXOR X6,X0 - PADDL X0,X4 - MOVOA X0,X5 - MOVOA X4,X6 - PSLLL $7,X4 - PSRLL $25,X6 - PXOR X4,X1 - PXOR X6,X1 - PADDL X1,X5 - MOVOA X1,X4 - MOVOA X5,X6 - PSLLL $9,X5 - PSRLL $23,X6 - PXOR X5,X2 - PSHUFL $0X93,X1,X1 - PXOR X6,X2 - PADDL X2,X4 - MOVOA X2,X5 - MOVOA X4,X6 - PSLLL $13,X4 - PSRLL $19,X6 - PXOR X4,X3 - PSHUFL $0X4E,X2,X2 - PXOR X6,X3 - PADDL X3,X5 - MOVOA X1,X4 - MOVOA X5,X6 - PSLLL $18,X5 - PSRLL $14,X6 - PXOR X5,X0 - PSHUFL $0X39,X3,X3 - PXOR X6,X0 - PADDL X0,X4 - MOVOA X0,X5 - MOVOA X4,X6 - PSLLL $7,X4 - PSRLL $25,X6 - PXOR X4,X3 - PXOR X6,X3 - PADDL X3,X5 - MOVOA X3,X4 - MOVOA X5,X6 - PSLLL $9,X5 - PSRLL $23,X6 - PXOR X5,X2 - PSHUFL $0X93,X3,X3 - PXOR X6,X2 - PADDL X2,X4 - MOVOA X2,X5 - MOVOA X4,X6 - PSLLL $13,X4 - PSRLL $19,X6 - PXOR X4,X1 - PSHUFL $0X4E,X2,X2 - PXOR X6,X1 - PADDL X1,X5 - MOVOA X3,X4 - MOVOA X5,X6 - PSLLL $18,X5 - PSRLL $14,X6 - PXOR X5,X0 - PSHUFL $0X39,X1,X1 - PXOR X6,X0 - PADDL X0,X4 - MOVOA X0,X5 - MOVOA X4,X6 - PSLLL $7,X4 - PSRLL $25,X6 - PXOR X4,X1 - PXOR X6,X1 - PADDL X1,X5 - MOVOA X1,X4 - MOVOA X5,X6 - PSLLL $9,X5 - PSRLL $23,X6 - PXOR X5,X2 - PSHUFL $0X93,X1,X1 - PXOR X6,X2 - PADDL X2,X4 - MOVOA X2,X5 - MOVOA X4,X6 - PSLLL $13,X4 - PSRLL $19,X6 - PXOR X4,X3 - PSHUFL $0X4E,X2,X2 - PXOR X6,X3 - SUBQ $4,CX - PADDL X3,X5 - MOVOA X1,X4 - MOVOA X5,X6 - PSLLL $18,X5 - PXOR X7,X7 - PSRLL $14,X6 - PXOR X5,X0 - PSHUFL $0X39,X3,X3 - PXOR X6,X0 - JA MAINLOOP2 - PADDL 48(R12),X0 - PADDL 0(R12),X1 - PADDL 16(R12),X2 - PADDL 32(R12),X3 - MOVD X0,CX - MOVD X1,R8 - MOVD X2,R9 - MOVD X3,AX - PSHUFL $0X39,X0,X0 - PSHUFL $0X39,X1,X1 - PSHUFL $0X39,X2,X2 - PSHUFL $0X39,X3,X3 - XORL 0(SI),CX - XORL 48(SI),R8 - XORL 32(SI),R9 - XORL 16(SI),AX - MOVL CX,0(DI) - MOVL R8,48(DI) - MOVL R9,32(DI) - MOVL AX,16(DI) - MOVD X0,CX - MOVD X1,R8 - MOVD X2,R9 - MOVD X3,AX - PSHUFL $0X39,X0,X0 - PSHUFL $0X39,X1,X1 - PSHUFL $0X39,X2,X2 - PSHUFL $0X39,X3,X3 - XORL 20(SI),CX - XORL 4(SI),R8 - XORL 52(SI),R9 - XORL 36(SI),AX - MOVL CX,20(DI) - MOVL R8,4(DI) - MOVL R9,52(DI) - MOVL AX,36(DI) - MOVD X0,CX - MOVD X1,R8 - MOVD X2,R9 - MOVD X3,AX - PSHUFL $0X39,X0,X0 - PSHUFL $0X39,X1,X1 - PSHUFL $0X39,X2,X2 - PSHUFL $0X39,X3,X3 - XORL 40(SI),CX - XORL 24(SI),R8 - XORL 8(SI),R9 - XORL 56(SI),AX - MOVL CX,40(DI) - MOVL R8,24(DI) - MOVL R9,8(DI) - MOVL AX,56(DI) - MOVD X0,CX - MOVD X1,R8 - MOVD X2,R9 - MOVD X3,AX - XORL 60(SI),CX - XORL 44(SI),R8 - XORL 28(SI),R9 - XORL 12(SI),AX - MOVL CX,60(DI) - MOVL R8,44(DI) - MOVL R9,28(DI) - MOVL AX,12(DI) - MOVQ 352(R12),R9 - MOVL 16(R12),CX - MOVL 36 (R12),R8 - ADDQ $1,CX - SHLQ $32,R8 - ADDQ R8,CX - MOVQ CX,R8 - SHRQ $32,R8 - MOVL CX,16(R12) - MOVL R8, 36 (R12) - CMPQ R9,$64 - JA BYTESATLEAST65 - JAE BYTESATLEAST64 - MOVQ DI,SI - MOVQ DX,DI - MOVQ R9,CX + LEAQ 360(R12), DI + LEAQ 360(R12), SI + +NOCOPY: + MOVQ R9, 352(R12) + MOVOA 48(R12), X0 + MOVOA (R12), X1 + MOVOA 16(R12), X2 + MOVOA 32(R12), X3 + MOVOA X1, X4 + MOVQ $0x00000014, CX + +MAINLOOP2: + PADDL X0, X4 + MOVOA X0, X5 + MOVOA X4, X6 + PSLLL $0x07, X4 + PSRLL $0x19, X6 + PXOR X4, X3 + PXOR X6, X3 + PADDL X3, X5 + MOVOA X3, X4 + MOVOA X5, X6 + PSLLL $0x09, X5 + PSRLL $0x17, X6 + PXOR X5, X2 + PSHUFL $0x93, X3, X3 + PXOR X6, X2 + PADDL X2, X4 + MOVOA X2, X5 + MOVOA X4, X6 + PSLLL $0x0d, X4 + PSRLL $0x13, X6 + PXOR X4, X1 + PSHUFL $0x4e, X2, X2 + PXOR X6, X1 + PADDL X1, X5 + MOVOA X3, X4 + MOVOA X5, X6 + PSLLL $0x12, X5 + PSRLL $0x0e, X6 + PXOR X5, X0 + PSHUFL $0x39, X1, X1 + PXOR X6, X0 + PADDL X0, X4 + MOVOA X0, X5 + MOVOA X4, X6 + PSLLL $0x07, X4 + PSRLL $0x19, X6 + PXOR X4, X1 + PXOR X6, X1 + PADDL X1, X5 + MOVOA X1, X4 + MOVOA X5, X6 + PSLLL $0x09, X5 + PSRLL $0x17, X6 + PXOR X5, X2 + PSHUFL $0x93, X1, X1 + PXOR X6, X2 + PADDL X2, X4 + MOVOA X2, X5 + MOVOA X4, X6 + PSLLL $0x0d, X4 + PSRLL $0x13, X6 + PXOR X4, X3 + PSHUFL $0x4e, X2, X2 + PXOR X6, X3 + PADDL X3, X5 + MOVOA X1, X4 + MOVOA X5, X6 + PSLLL $0x12, X5 + PSRLL $0x0e, X6 + PXOR X5, X0 + PSHUFL $0x39, X3, X3 + PXOR X6, X0 + PADDL X0, X4 + MOVOA X0, X5 + MOVOA X4, X6 + PSLLL $0x07, X4 + PSRLL $0x19, X6 + PXOR X4, X3 + PXOR X6, X3 + PADDL X3, X5 + MOVOA X3, X4 + MOVOA X5, X6 + PSLLL $0x09, X5 + PSRLL $0x17, X6 + PXOR X5, X2 + PSHUFL $0x93, X3, X3 + PXOR X6, X2 + PADDL X2, X4 + MOVOA X2, X5 + MOVOA X4, X6 + PSLLL $0x0d, X4 + PSRLL $0x13, X6 + PXOR X4, X1 + PSHUFL $0x4e, X2, X2 + PXOR X6, X1 + PADDL X1, X5 + MOVOA X3, X4 + MOVOA X5, X6 + PSLLL $0x12, X5 + PSRLL $0x0e, X6 + PXOR X5, X0 + PSHUFL $0x39, X1, X1 + PXOR X6, X0 + PADDL X0, X4 + MOVOA X0, X5 + MOVOA X4, X6 + PSLLL $0x07, X4 + PSRLL $0x19, X6 + PXOR X4, X1 + PXOR X6, X1 + PADDL X1, X5 + MOVOA X1, X4 + MOVOA X5, X6 + PSLLL $0x09, X5 + PSRLL $0x17, X6 + PXOR X5, X2 + PSHUFL $0x93, X1, X1 + PXOR X6, X2 + PADDL X2, X4 + MOVOA X2, X5 + MOVOA X4, X6 + PSLLL $0x0d, X4 + PSRLL $0x13, X6 + PXOR X4, X3 + PSHUFL $0x4e, X2, X2 + PXOR X6, X3 + SUBQ $0x04, CX + PADDL X3, X5 + MOVOA X1, X4 + MOVOA X5, X6 + PSLLL $0x12, X5 + PXOR X7, X7 + PSRLL $0x0e, X6 + PXOR X5, X0 + PSHUFL $0x39, X3, X3 + PXOR X6, X0 + JA MAINLOOP2 + PADDL 48(R12), X0 + PADDL (R12), X1 + PADDL 16(R12), X2 + PADDL 32(R12), X3 + MOVD X0, CX + MOVD X1, R8 + MOVD X2, R9 + MOVD X3, AX + PSHUFL $0x39, X0, X0 + PSHUFL $0x39, X1, X1 + PSHUFL $0x39, X2, X2 + PSHUFL $0x39, X3, X3 + XORL (SI), CX + XORL 48(SI), R8 + XORL 32(SI), R9 + XORL 16(SI), AX + MOVL CX, (DI) + MOVL R8, 48(DI) + MOVL R9, 32(DI) + MOVL AX, 16(DI) + MOVD X0, CX + MOVD X1, R8 + MOVD X2, R9 + MOVD X3, AX + PSHUFL $0x39, X0, X0 + PSHUFL $0x39, X1, X1 + PSHUFL $0x39, X2, X2 + PSHUFL $0x39, X3, X3 + XORL 20(SI), CX + XORL 4(SI), R8 + XORL 52(SI), R9 + XORL 36(SI), AX + MOVL CX, 20(DI) + MOVL R8, 4(DI) + MOVL R9, 52(DI) + MOVL AX, 36(DI) + MOVD X0, CX + MOVD X1, R8 + MOVD X2, R9 + MOVD X3, AX + PSHUFL $0x39, X0, X0 + PSHUFL $0x39, X1, X1 + PSHUFL $0x39, X2, X2 + PSHUFL $0x39, X3, X3 + XORL 40(SI), CX + XORL 24(SI), R8 + XORL 8(SI), R9 + XORL 56(SI), AX + MOVL CX, 40(DI) + MOVL R8, 24(DI) + MOVL R9, 8(DI) + MOVL AX, 56(DI) + MOVD X0, CX + MOVD X1, R8 + MOVD X2, R9 + MOVD X3, AX + XORL 60(SI), CX + XORL 44(SI), R8 + XORL 28(SI), R9 + XORL 12(SI), AX + MOVL CX, 60(DI) + MOVL R8, 44(DI) + MOVL R9, 28(DI) + MOVL AX, 12(DI) + MOVQ 352(R12), R9 + MOVL 16(R12), CX + MOVL 36(R12), R8 + ADDQ $0x01, CX + SHLQ $0x20, R8 + ADDQ R8, CX + MOVQ CX, R8 + SHRQ $0x20, R8 + MOVL CX, 16(R12) + MOVL R8, 36(R12) + CMPQ R9, $0x40 + JA BYTESATLEAST65 + JAE BYTESATLEAST64 + MOVQ DI, SI + MOVQ DX, DI + MOVQ R9, CX REP; MOVSB - BYTESATLEAST64: - DONE: + +BYTESATLEAST64: +DONE: RET - BYTESATLEAST65: - SUBQ $64,R9 - ADDQ $64,DI - ADDQ $64,SI - JMP BYTESBETWEEN1AND255 + +BYTESATLEAST65: + SUBQ $0x40, R9 + ADDQ $0x40, DI + ADDQ $0x40, SI + JMP BYTESBETWEEN1AND255 diff --git a/vendor/golang.org/x/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go index 7e02309070..bbf391fe6e 100644 --- a/vendor/golang.org/x/crypto/sha3/doc.go +++ b/vendor/golang.org/x/crypto/sha3/doc.go @@ -5,6 +5,10 @@ // Package sha3 implements the SHA-3 fixed-output-length hash functions and // the SHAKE variable-output-length hash functions defined by FIPS-202. // +// All types in this package also implement [encoding.BinaryMarshaler], +// [encoding.BinaryAppender] and [encoding.BinaryUnmarshaler] to marshal and +// unmarshal the internal state of the hash. +// // Both types of hash function use the "sponge" construction and the Keccak // permutation. For a detailed specification see http://keccak.noekeon.org/ // diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go index c544b29e5f..31fffbe044 100644 --- a/vendor/golang.org/x/crypto/sha3/hashes.go +++ b/vendor/golang.org/x/crypto/sha3/hashes.go @@ -48,33 +48,52 @@ func init() { crypto.RegisterHash(crypto.SHA3_512, New512) } +const ( + dsbyteSHA3 = 0b00000110 + dsbyteKeccak = 0b00000001 + dsbyteShake = 0b00011111 + dsbyteCShake = 0b00000100 + + // rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in + // bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits. + rateK256 = (1600 - 256) / 8 + rateK448 = (1600 - 448) / 8 + rateK512 = (1600 - 512) / 8 + rateK768 = (1600 - 768) / 8 + rateK1024 = (1600 - 1024) / 8 +) + func new224Generic() *state { - return &state{rate: 144, outputLen: 28, dsbyte: 0x06} + return &state{rate: rateK448, outputLen: 28, dsbyte: dsbyteSHA3} } func new256Generic() *state { - return &state{rate: 136, outputLen: 32, dsbyte: 0x06} + return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteSHA3} } func new384Generic() *state { - return &state{rate: 104, outputLen: 48, dsbyte: 0x06} + return &state{rate: rateK768, outputLen: 48, dsbyte: dsbyteSHA3} } func new512Generic() *state { - return &state{rate: 72, outputLen: 64, dsbyte: 0x06} + return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteSHA3} } // NewLegacyKeccak256 creates a new Keccak-256 hash. // // Only use this function if you require compatibility with an existing cryptosystem // that uses non-standard padding. All other users should use New256 instead. -func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } +func NewLegacyKeccak256() hash.Hash { + return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak} +} // NewLegacyKeccak512 creates a new Keccak-512 hash. // // Only use this function if you require compatibility with an existing cryptosystem // that uses non-standard padding. All other users should use New512 instead. -func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } +func NewLegacyKeccak512() hash.Hash { + return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak} +} // Sum224 returns the SHA3-224 digest of the data. func Sum224(data []byte) (digest [28]byte) { diff --git a/vendor/golang.org/x/crypto/sha3/sha3.go b/vendor/golang.org/x/crypto/sha3/sha3.go index afedde5abf..6658c44479 100644 --- a/vendor/golang.org/x/crypto/sha3/sha3.go +++ b/vendor/golang.org/x/crypto/sha3/sha3.go @@ -4,6 +4,15 @@ package sha3 +import ( + "crypto/subtle" + "encoding/binary" + "errors" + "unsafe" + + "golang.org/x/sys/cpu" +) + // spongeDirection indicates the direction bytes are flowing through the sponge. type spongeDirection int @@ -14,16 +23,13 @@ const ( spongeSqueezing ) -const ( - // maxRate is the maximum size of the internal buffer. SHAKE-256 - // currently needs the largest buffer. - maxRate = 168 -) - type state struct { - // Generic sponge components. - a [25]uint64 // main state of the hash - rate int // the number of bytes of state to use + a [1600 / 8]byte // main state of the hash + + // a[n:rate] is the buffer. If absorbing, it's the remaining space to XOR + // into before running the permutation. If squeezing, it's the remaining + // output to produce before running the permutation. + n, rate int // dsbyte contains the "domain separation" bits and the first bit of // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the @@ -39,10 +45,6 @@ type state struct { // Extendable-Output Functions (May 2014)" dsbyte byte - i, n int // storage[i:n] is the buffer, i is only used while squeezing - storage [maxRate]byte - - // Specific to SHA-3 and SHAKE. outputLen int // the default output size in bytes state spongeDirection // whether the sponge is absorbing or squeezing } @@ -61,7 +63,7 @@ func (d *state) Reset() { d.a[i] = 0 } d.state = spongeAbsorbing - d.i, d.n = 0, 0 + d.n = 0 } func (d *state) clone() *state { @@ -69,22 +71,25 @@ func (d *state) clone() *state { return &ret } -// permute applies the KeccakF-1600 permutation. It handles -// any input-output buffering. +// permute applies the KeccakF-1600 permutation. func (d *state) permute() { - switch d.state { - case spongeAbsorbing: - // If we're absorbing, we need to xor the input into the state - // before applying the permutation. - xorIn(d, d.storage[:d.rate]) - d.n = 0 - keccakF1600(&d.a) - case spongeSqueezing: - // If we're squeezing, we need to apply the permutation before - // copying more output. - keccakF1600(&d.a) - d.i = 0 - copyOut(d, d.storage[:d.rate]) + var a *[25]uint64 + if cpu.IsBigEndian { + a = new([25]uint64) + for i := range a { + a[i] = binary.LittleEndian.Uint64(d.a[i*8:]) + } + } else { + a = (*[25]uint64)(unsafe.Pointer(&d.a)) + } + + keccakF1600(a) + d.n = 0 + + if cpu.IsBigEndian { + for i := range a { + binary.LittleEndian.PutUint64(d.a[i*8:], a[i]) + } } } @@ -92,53 +97,36 @@ func (d *state) permute() { // the multi-bitrate 10..1 padding rule, and permutes the state. func (d *state) padAndPermute() { // Pad with this instance's domain-separator bits. We know that there's - // at least one byte of space in d.buf because, if it were full, + // at least one byte of space in the sponge because, if it were full, // permute would have been called to empty it. dsbyte also contains the // first one bit for the padding. See the comment in the state struct. - d.storage[d.n] = d.dsbyte - d.n++ - for d.n < d.rate { - d.storage[d.n] = 0 - d.n++ - } + d.a[d.n] ^= d.dsbyte // This adds the final one bit for the padding. Because of the way that // bits are numbered from the LSB upwards, the final bit is the MSB of // the last byte. - d.storage[d.rate-1] ^= 0x80 + d.a[d.rate-1] ^= 0x80 // Apply the permutation d.permute() d.state = spongeSqueezing - d.n = d.rate - copyOut(d, d.storage[:d.rate]) } // Write absorbs more data into the hash's state. It panics if any // output has already been read. -func (d *state) Write(p []byte) (written int, err error) { +func (d *state) Write(p []byte) (n int, err error) { if d.state != spongeAbsorbing { panic("sha3: Write after Read") } - written = len(p) + + n = len(p) for len(p) > 0 { - if d.n == 0 && len(p) >= d.rate { - // The fast path; absorb a full "rate" bytes of input and apply the permutation. - xorIn(d, p[:d.rate]) - p = p[d.rate:] - keccakF1600(&d.a) - } else { - // The slow path; buffer the input until we can fill the sponge, and then xor it in. - todo := d.rate - d.n - if todo > len(p) { - todo = len(p) - } - d.n += copy(d.storage[d.n:], p[:todo]) - p = p[todo:] - - // If the sponge is full, apply the permutation. - if d.n == d.rate { - d.permute() - } + x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p) + d.n += x + p = p[x:] + + // If the sponge is full, apply the permutation. + if d.n == d.rate { + d.permute() } } @@ -156,14 +144,14 @@ func (d *state) Read(out []byte) (n int, err error) { // Now, do the squeezing. for len(out) > 0 { - n := copy(out, d.storage[d.i:d.n]) - d.i += n - out = out[n:] - // Apply the permutation if we've squeezed the sponge dry. - if d.i == d.rate { + if d.n == d.rate { d.permute() } + + x := copy(out, d.a[d.n:d.rate]) + d.n += x + out = out[x:] } return @@ -183,3 +171,74 @@ func (d *state) Sum(in []byte) []byte { dup.Read(hash) return append(in, hash...) } + +const ( + magicSHA3 = "sha\x08" + magicShake = "sha\x09" + magicCShake = "sha\x0a" + magicKeccak = "sha\x0b" + // magic || rate || main state || n || sponge direction + marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1 +) + +func (d *state) MarshalBinary() ([]byte, error) { + return d.AppendBinary(make([]byte, 0, marshaledSize)) +} + +func (d *state) AppendBinary(b []byte) ([]byte, error) { + switch d.dsbyte { + case dsbyteSHA3: + b = append(b, magicSHA3...) + case dsbyteShake: + b = append(b, magicShake...) + case dsbyteCShake: + b = append(b, magicCShake...) + case dsbyteKeccak: + b = append(b, magicKeccak...) + default: + panic("unknown dsbyte") + } + // rate is at most 168, and n is at most rate. + b = append(b, byte(d.rate)) + b = append(b, d.a[:]...) + b = append(b, byte(d.n), byte(d.state)) + return b, nil +} + +func (d *state) UnmarshalBinary(b []byte) error { + if len(b) != marshaledSize { + return errors.New("sha3: invalid hash state") + } + + magic := string(b[:len(magicSHA3)]) + b = b[len(magicSHA3):] + switch { + case magic == magicSHA3 && d.dsbyte == dsbyteSHA3: + case magic == magicShake && d.dsbyte == dsbyteShake: + case magic == magicCShake && d.dsbyte == dsbyteCShake: + case magic == magicKeccak && d.dsbyte == dsbyteKeccak: + default: + return errors.New("sha3: invalid hash state identifier") + } + + rate := int(b[0]) + b = b[1:] + if rate != d.rate { + return errors.New("sha3: invalid hash state function") + } + + copy(d.a[:], b) + b = b[len(d.a):] + + n, state := int(b[0]), spongeDirection(b[1]) + if n > d.rate { + return errors.New("sha3: invalid hash state") + } + d.n = n + if state != spongeAbsorbing && state != spongeSqueezing { + return errors.New("sha3: invalid hash state") + } + d.state = state + + return nil +} diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go index 1ea9275b8b..a6b3a4281f 100644 --- a/vendor/golang.org/x/crypto/sha3/shake.go +++ b/vendor/golang.org/x/crypto/sha3/shake.go @@ -16,9 +16,12 @@ package sha3 // [2] https://doi.org/10.6028/NIST.SP.800-185 import ( + "bytes" "encoding/binary" + "errors" "hash" "io" + "math/bits" ) // ShakeHash defines the interface to hash functions that support @@ -50,44 +53,36 @@ type cshakeState struct { initBlock []byte } -// Consts for configuring initial SHA-3 state -const ( - dsbyteShake = 0x1f - dsbyteCShake = 0x04 - rate128 = 168 - rate256 = 136 -) +func bytepad(data []byte, rate int) []byte { + out := make([]byte, 0, 9+len(data)+rate-1) + out = append(out, leftEncode(uint64(rate))...) + out = append(out, data...) + if padlen := rate - len(out)%rate; padlen < rate { + out = append(out, make([]byte, padlen)...) + } + return out +} -func bytepad(input []byte, w int) []byte { - // leftEncode always returns max 9 bytes - buf := make([]byte, 0, 9+len(input)+w) - buf = append(buf, leftEncode(uint64(w))...) - buf = append(buf, input...) - padlen := w - (len(buf) % w) - return append(buf, make([]byte, padlen)...) -} - -func leftEncode(value uint64) []byte { - var b [9]byte - binary.BigEndian.PutUint64(b[1:], value) - // Trim all but last leading zero bytes - i := byte(1) - for i < 8 && b[i] == 0 { - i++ +func leftEncode(x uint64) []byte { + // Let n be the smallest positive integer for which 2^(8n) > x. + n := (bits.Len64(x) + 7) / 8 + if n == 0 { + n = 1 } - // Prepend number of encoded bytes - b[i-1] = 9 - i - return b[i-1:] + // Return n || x with n as a byte and x an n bytes in big-endian order. + b := make([]byte, 9) + binary.BigEndian.PutUint64(b[1:], x) + b = b[9-n-1:] + b[0] = byte(n) + return b } func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash { c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}} - - // leftEncode returns max 9 bytes - c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) - c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...) + c.initBlock = make([]byte, 0, 9+len(N)+9+len(S)) // leftEncode returns max 9 bytes + c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...) c.initBlock = append(c.initBlock, N...) - c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...) c.initBlock = append(c.initBlock, S...) c.Write(bytepad(c.initBlock, c.rate)) return &c @@ -111,6 +106,30 @@ func (c *state) Clone() ShakeHash { return c.clone() } +func (c *cshakeState) MarshalBinary() ([]byte, error) { + return c.AppendBinary(make([]byte, 0, marshaledSize+len(c.initBlock))) +} + +func (c *cshakeState) AppendBinary(b []byte) ([]byte, error) { + b, err := c.state.AppendBinary(b) + if err != nil { + return nil, err + } + b = append(b, c.initBlock...) + return b, nil +} + +func (c *cshakeState) UnmarshalBinary(b []byte) error { + if len(b) <= marshaledSize { + return errors.New("sha3: invalid hash state") + } + if err := c.state.UnmarshalBinary(b[:marshaledSize]); err != nil { + return err + } + c.initBlock = bytes.Clone(b[marshaledSize:]) + return nil +} + // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. // Its generic security strength is 128 bits against all attacks if at // least 32 bytes of its output are used. @@ -126,11 +145,11 @@ func NewShake256() ShakeHash { } func newShake128Generic() *state { - return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake} + return &state{rate: rateK256, outputLen: 32, dsbyte: dsbyteShake} } func newShake256Generic() *state { - return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake} + return &state{rate: rateK512, outputLen: 64, dsbyte: dsbyteShake} } // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, @@ -143,7 +162,7 @@ func NewCShake128(N, S []byte) ShakeHash { if len(N) == 0 && len(S) == 0 { return NewShake128() } - return newCShake(N, S, rate128, 32, dsbyteCShake) + return newCShake(N, S, rateK256, 32, dsbyteCShake) } // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, @@ -156,7 +175,7 @@ func NewCShake256(N, S []byte) ShakeHash { if len(N) == 0 && len(S) == 0 { return NewShake256() } - return newCShake(N, S, rate256, 64, dsbyteCShake) + return newCShake(N, S, rateK512, 64, dsbyteCShake) } // ShakeSum128 writes an arbitrary-length digest of data into hash. diff --git a/vendor/golang.org/x/crypto/sha3/xor.go b/vendor/golang.org/x/crypto/sha3/xor.go deleted file mode 100644 index 6ada5c9574..0000000000 --- a/vendor/golang.org/x/crypto/sha3/xor.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -import ( - "crypto/subtle" - "encoding/binary" - "unsafe" - - "golang.org/x/sys/cpu" -) - -// xorIn xors the bytes in buf into the state. -func xorIn(d *state, buf []byte) { - if cpu.IsBigEndian { - for i := 0; len(buf) >= 8; i++ { - a := binary.LittleEndian.Uint64(buf) - d.a[i] ^= a - buf = buf[8:] - } - } else { - ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a)) - subtle.XORBytes(ab[:], ab[:], buf) - } -} - -// copyOut copies uint64s to a byte buffer. -func copyOut(d *state, b []byte) { - if cpu.IsBigEndian { - for i := 0; len(b) >= 8; i++ { - binary.LittleEndian.PutUint64(b, d.a[i]) - b = b[8:] - } - } else { - ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a)) - copy(b, ab[:]) - } -} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go deleted file mode 100644 index a4d1919a9e..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package terminal provides support functions for dealing with terminals, as -// commonly found on UNIX systems. -// -// Deprecated: this package moved to golang.org/x/term. -package terminal - -import ( - "io" - - "golang.org/x/term" -) - -// EscapeCodes contains escape sequences that can be written to the terminal in -// order to achieve different styles of text. -type EscapeCodes = term.EscapeCodes - -// Terminal contains the state for running a VT100 terminal that is capable of -// reading lines of input. -type Terminal = term.Terminal - -// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is -// a local terminal, that terminal must first have been put into raw mode. -// prompt is a string that is written at the start of each input line (i.e. -// "> "). -func NewTerminal(c io.ReadWriter, prompt string) *Terminal { - return term.NewTerminal(c, prompt) -} - -// ErrPasteIndicator may be returned from ReadLine as the error, in addition -// to valid line data. It indicates that bracketed paste mode is enabled and -// that the returned line consists only of pasted data. Programs may wish to -// interpret pasted data more literally than typed data. -var ErrPasteIndicator = term.ErrPasteIndicator - -// State contains the state of a terminal. -type State = term.State - -// IsTerminal returns whether the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - return term.IsTerminal(fd) -} - -// ReadPassword reads a line of input from a terminal without local echo. This -// is commonly used for inputting passwords and other sensitive data. The slice -// returned does not include the \n. -func ReadPassword(fd int) ([]byte, error) { - return term.ReadPassword(fd) -} - -// MakeRaw puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd int) (*State, error) { - return term.MakeRaw(fd) -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func Restore(fd int, oldState *State) error { - return term.Restore(fd, oldState) -} - -// GetState returns the current state of a terminal which may be useful to -// restore the terminal after a signal. -func GetState(fd int) (*State, error) { - return term.GetState(fd) -} - -// GetSize returns the dimensions of the given terminal. -func GetSize(fd int) (width, height int, err error) { - return term.GetSize(fd) -} diff --git a/vendor/golang.org/x/image/AUTHORS b/vendor/golang.org/x/image/AUTHORS deleted file mode 100644 index 15167cd746..0000000000 --- a/vendor/golang.org/x/image/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/image/CONTRIBUTORS b/vendor/golang.org/x/image/CONTRIBUTORS deleted file mode 100644 index 1c4577e968..0000000000 --- a/vendor/golang.org/x/image/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/image/LICENSE b/vendor/golang.org/x/image/LICENSE index 6a66aea5ea..2a7cf70da6 100644 --- a/vendor/golang.org/x/image/LICENSE +++ b/vendor/golang.org/x/image/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer. copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google Inc. nor the names of its + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/vendor/golang.org/x/image/bmp/reader.go b/vendor/golang.org/x/image/bmp/reader.go index 52e25205c0..1939c1120c 100644 --- a/vendor/golang.org/x/image/bmp/reader.go +++ b/vendor/golang.org/x/image/bmp/reader.go @@ -85,7 +85,7 @@ func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) { // decodeNRGBA reads a 32 bit-per-pixel BMP image from r. // If topDown is false, the image rows will be read bottom-up. -func decodeNRGBA(r io.Reader, c image.Config, topDown bool) (image.Image, error) { +func decodeNRGBA(r io.Reader, c image.Config, topDown, allowAlpha bool) (image.Image, error) { rgba := image.NewNRGBA(image.Rect(0, 0, c.Width, c.Height)) if c.Width == 0 || c.Height == 0 { return rgba, nil @@ -102,6 +102,9 @@ func decodeNRGBA(r io.Reader, c image.Config, topDown bool) (image.Image, error) for i := 0; i < len(p); i += 4 { // BMP images are stored in BGRA order rather than RGBA order. p[i+0], p[i+2] = p[i+2], p[i+0] + if !allowAlpha { + p[i+3] = 0xFF + } } } return rgba, nil @@ -110,7 +113,7 @@ func decodeNRGBA(r io.Reader, c image.Config, topDown bool) (image.Image, error) // Decode reads a BMP image from r and returns it as an image.Image. // Limitation: The file must be 8, 24 or 32 bits per pixel. func Decode(r io.Reader) (image.Image, error) { - c, bpp, topDown, err := decodeConfig(r) + c, bpp, topDown, allowAlpha, err := decodeConfig(r) if err != nil { return nil, err } @@ -120,7 +123,7 @@ func Decode(r io.Reader) (image.Image, error) { case 24: return decodeRGB(r, c, topDown) case 32: - return decodeNRGBA(r, c, topDown) + return decodeNRGBA(r, c, topDown, allowAlpha) } panic("unreachable") } @@ -129,13 +132,15 @@ func Decode(r io.Reader) (image.Image, error) { // decoding the entire image. // Limitation: The file must be 8, 24 or 32 bits per pixel. func DecodeConfig(r io.Reader) (image.Config, error) { - config, _, _, err := decodeConfig(r) + config, _, _, _, err := decodeConfig(r) return config, err } -func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, err error) { - // We only support those BMP images that are a BITMAPFILEHEADER - // immediately followed by a BITMAPINFOHEADER. +func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, allowAlpha bool, err error) { + // We only support those BMP images with one of the following DIB headers: + // - BITMAPINFOHEADER (40 bytes) + // - BITMAPV4HEADER (108 bytes) + // - BITMAPV5HEADER (124 bytes) const ( fileHeaderLen = 14 infoHeaderLen = 40 @@ -147,21 +152,21 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b if err == io.EOF { err = io.ErrUnexpectedEOF } - return image.Config{}, 0, false, err + return image.Config{}, 0, false, false, err } if string(b[:2]) != "BM" { - return image.Config{}, 0, false, errors.New("bmp: invalid format") + return image.Config{}, 0, false, false, errors.New("bmp: invalid format") } offset := readUint32(b[10:14]) infoLen := readUint32(b[14:18]) if infoLen != infoHeaderLen && infoLen != v4InfoHeaderLen && infoLen != v5InfoHeaderLen { - return image.Config{}, 0, false, ErrUnsupported + return image.Config{}, 0, false, false, ErrUnsupported } if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } - return image.Config{}, 0, false, err + return image.Config{}, 0, false, false, err } width := int(int32(readUint32(b[18:22]))) height := int(int32(readUint32(b[22:26]))) @@ -169,12 +174,12 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b height, topDown = -height, true } if width < 0 || height < 0 { - return image.Config{}, 0, false, ErrUnsupported + return image.Config{}, 0, false, false, ErrUnsupported } // We only support 1 plane and 8, 24 or 32 bits per pixel and no // compression. planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34]) - // if compression is set to BITFIELDS, but the bitmask is set to the default bitmask + // if compression is set to BI_BITFIELDS, but the bitmask is set to the default bitmask // that would be used if compression was set to 0, we can continue as if compression was 0 if compression == 3 && infoLen > infoHeaderLen && readUint32(b[54:58]) == 0xff0000 && readUint32(b[58:62]) == 0xff00 && @@ -182,36 +187,65 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b compression = 0 } if planes != 1 || compression != 0 { - return image.Config{}, 0, false, ErrUnsupported + return image.Config{}, 0, false, false, ErrUnsupported } switch bpp { case 8: - if offset != fileHeaderLen+infoLen+256*4 { - return image.Config{}, 0, false, ErrUnsupported + colorUsed := readUint32(b[46:50]) + // If colorUsed is 0, it is set to the maximum number of colors for the given bpp, which is 2^bpp. + if colorUsed == 0 { + colorUsed = 256 + } else if colorUsed > 256 { + return image.Config{}, 0, false, false, ErrUnsupported + } + + if offset != fileHeaderLen+infoLen+colorUsed*4 { + return image.Config{}, 0, false, false, ErrUnsupported } - _, err = io.ReadFull(r, b[:256*4]) + _, err = io.ReadFull(r, b[:colorUsed*4]) if err != nil { - return image.Config{}, 0, false, err + return image.Config{}, 0, false, false, err } - pcm := make(color.Palette, 256) + pcm := make(color.Palette, colorUsed) for i := range pcm { // BMP images are stored in BGR order rather than RGB order. // Every 4th byte is padding. pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF} } - return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, nil + return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, false, nil case 24: if offset != fileHeaderLen+infoLen { - return image.Config{}, 0, false, ErrUnsupported + return image.Config{}, 0, false, false, ErrUnsupported } - return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, nil + return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, false, nil case 32: if offset != fileHeaderLen+infoLen { - return image.Config{}, 0, false, ErrUnsupported + return image.Config{}, 0, false, false, ErrUnsupported } - return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, nil - } - return image.Config{}, 0, false, ErrUnsupported + // 32 bits per pixel is possibly RGBX (X is padding) or RGBA (A is + // alpha transparency). However, for BMP images, "Alpha is a + // poorly-documented and inconsistently-used feature" says + // https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc;l=621 + // + // That goes on to say "BITMAPV3HEADER+ have an alpha bitmask in the + // info header... so we respect it at all times... [For earlier + // (smaller) headers we] ignore alpha in Windows V3 BMPs except inside + // ICO files". + // + // "Ignore" means to always set alpha to 0xFF (fully opaque): + // https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h;l=272 + // + // Confusingly, "Windows V3" does not correspond to BITMAPV3HEADER, but + // instead corresponds to the earlier (smaller) BITMAPINFOHEADER: + // https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc;l=258 + // + // This Go package does not support ICO files and the (infoLen > + // infoHeaderLen) condition distinguishes BITMAPINFOHEADER (40 bytes) + // vs later (larger) headers. + allowAlpha = infoLen > infoHeaderLen + return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, allowAlpha, nil + } + return image.Config{}, 0, false, false, ErrUnsupported } func init() { diff --git a/vendor/golang.org/x/image/draw/draw.go b/vendor/golang.org/x/image/draw/draw.go index cd5aaba647..42d5d7e099 100644 --- a/vendor/golang.org/x/image/draw/draw.go +++ b/vendor/golang.org/x/image/draw/draw.go @@ -47,6 +47,12 @@ func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp ima // Image is an image.Image with a Set method to change a single pixel. type Image = draw.Image +// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a +// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to +// calling Set, but it can avoid allocations from converting concrete color +// types to the color.Color interface type. +type RGBA64Image = draw.RGBA64Image + // Op is a Porter-Duff compositing operator. type Op = draw.Op diff --git a/vendor/golang.org/x/image/draw/impl.go b/vendor/golang.org/x/image/draw/impl.go index 75498adbd9..fcd19943c4 100644 --- a/vendor/golang.org/x/image/draw/impl.go +++ b/vendor/golang.org/x/image/draw/impl.go @@ -59,9 +59,16 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o) case *image.RGBA: z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o) + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Over(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Over(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -91,9 +98,16 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr case image.YCbCrSubsampleRatio440: z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o) } + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Src(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Src(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -170,9 +184,16 @@ func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr i z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) case *image.RGBA: z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -202,9 +223,16 @@ func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr i case image.YCbCrSubsampleRatio440: z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -502,6 +530,45 @@ func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rec } } +func (nnInterpolator) scale_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (nnInterpolator) scale_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (nnInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { dw2 := uint64(dr.Dx()) * 2 dh2 := uint64(dr.Dy()) * 2 @@ -541,6 +608,86 @@ func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectan } } +func (nnInterpolator) scale_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (nnInterpolator) scale_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + func (nnInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { dw2 := uint64(dr.Dx()) * 2 dh2 := uint64(dr.Dy()) * 2 @@ -631,8 +778,8 @@ func (nnInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rec d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -653,8 +800,8 @@ func (nnInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.R d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -678,8 +825,8 @@ func (nnInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -702,8 +849,8 @@ func (nnInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -727,8 +874,8 @@ func (nnInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rec d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -751,8 +898,8 @@ func (nnInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -795,8 +942,8 @@ func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -839,8 +986,8 @@ func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -883,8 +1030,8 @@ func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -921,14 +1068,55 @@ func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image } } +func (nnInterpolator) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (nnInterpolator) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (nnInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -948,8 +1136,8 @@ func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -962,6 +1150,88 @@ func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Re } } +func (nnInterpolator) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (nnInterpolator) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { srcMask, smp := opts.SrcMask, opts.SrcMaskP dstMask, dmp := opts.DstMask, opts.DstMaskP @@ -971,8 +1241,8 @@ func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectan dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -1011,8 +1281,8 @@ func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectang dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -1097,9 +1367,16 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o) case *image.RGBA: z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o) + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Over(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Over(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -1129,9 +1406,16 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s case image.YCbCrSubsampleRatio440: z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o) } + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Src(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Src(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -1208,9 +1492,16 @@ func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) case *image.RGBA: z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -1240,9 +1531,16 @@ func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr case image.YCbCrSubsampleRatio440: z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -1261,7 +1559,7 @@ func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectan swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1279,7 +1577,7 @@ func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectan d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1298,15 +1596,15 @@ func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectan s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X) s10ru := uint32(src.Pix[s10i]) * 0x101 s10r := float64(s10ru) - s10r = xFrac1*s00r + xFrac0*s10r + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X) s01ru := uint32(src.Pix[s01i]) * 0x101 s01r := float64(s01ru) s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X) s11ru := uint32(src.Pix[s11i]) * 0x101 s11r := float64(s11ru) - s11r = xFrac1*s01r + xFrac0*s11r - s11r = yFrac1*s10r + yFrac0*s11r + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) pr := uint32(s11r) out := uint8(pr >> 8) dst.Pix[d+0] = out @@ -1325,7 +1623,7 @@ func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rect swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1343,7 +1641,7 @@ func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rect d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1374,10 +1672,10 @@ func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rect s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4 s01au := uint32(src.Pix[s01i+3]) * 0x101 s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff @@ -1396,14 +1694,14 @@ func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rect s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -1425,7 +1723,7 @@ func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Recta swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1443,7 +1741,7 @@ func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Recta d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1474,10 +1772,10 @@ func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Recta s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4 s01au := uint32(src.Pix[s01i+3]) * 0x101 s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff @@ -1496,14 +1794,14 @@ func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Recta s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -1524,7 +1822,7 @@ func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Recta swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1542,7 +1840,7 @@ func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Recta d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1573,10 +1871,10 @@ func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Recta s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4 s01ru := uint32(src.Pix[s01i+0]) * 0x101 s01gu := uint32(src.Pix[s01i+1]) * 0x101 @@ -1595,14 +1893,14 @@ func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Recta s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -1624,7 +1922,7 @@ func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectan swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1642,7 +1940,7 @@ func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectan d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1673,10 +1971,10 @@ func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectan s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4 s01ru := uint32(src.Pix[s01i+0]) * 0x101 s01gu := uint32(src.Pix[s01i+1]) * 0x101 @@ -1695,14 +1993,14 @@ func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectan s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -1723,7 +2021,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1741,7 +2039,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1812,9 +2110,9 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X) s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X) @@ -1873,12 +2171,12 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -1898,7 +2196,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -1916,7 +2214,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -1987,9 +2285,9 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X) s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2) @@ -2048,12 +2346,12 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2073,7 +2371,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -2091,7 +2389,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -2162,9 +2460,9 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X) s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2) @@ -2223,12 +2521,12 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2248,7 +2546,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -2266,7 +2564,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -2337,9 +2635,9 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X) s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X) @@ -2398,12 +2696,12 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2415,6 +2713,167 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re } } +func (ablInterpolator) scale_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := float64((float64(dy)+0.5)*yscale) - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := float64((float64(dx)+0.5)*xscale) - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (ablInterpolator) scale_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := float64((float64(dy)+0.5)*yscale) - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := float64((float64(dx)+0.5)*xscale) - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { sw := int32(sr.Dx()) sh := int32(sr.Dy()) @@ -2423,7 +2882,7 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -2441,7 +2900,7 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -2464,10 +2923,10 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() s01r := float64(s01ru) s01g := float64(s01gu) @@ -2478,14 +2937,14 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2507,7 +2966,7 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta swMinus1, shMinus1 := sw-1, sh-1 for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -2525,7 +2984,7 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -2548,10 +3007,10 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() s01r := float64(s01ru) s01g := float64(s01gu) @@ -2562,14 +3021,14 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2582,7 +3041,7 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta } } -func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { +func (ablInterpolator) scale_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { sw := int32(sr.Dx()) sh := int32(sr.Dy()) yscale := float64(sh) / float64(dr.Dy()) @@ -2590,11 +3049,10 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle swMinus1, shMinus1 := sw-1, sh-1 srcMask, smp := opts.SrcMask, opts.SrcMaskP dstMask, dmp := opts.DstMask, opts.DstMaskP - dstColorRGBA64 := &color.RGBA64{} - dstColor := color.Color(dstColorRGBA64) + dstColorRGBA64 := color.RGBA64{} for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -2611,7 +3069,7 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle } for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -2624,39 +3082,282 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle xFrac0, xFrac1 = 1, 0 } - s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() - s00ru = s00ru * ma / 0xffff - s00gu = s00gu * ma / 0xffff - s00bu = s00bu * ma / 0xffff - s00au = s00au * ma / 0xffff - } - s00r := float64(s00ru) - s00g := float64(s00gu) - s00b := float64(s00bu) - s00a := float64(s00au) - s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() - s10ru = s10ru * ma / 0xffff - s10gu = s10gu * ma / 0xffff - s10bu = s10bu * ma / 0xffff - s10au = s10au * ma / 0xffff - } - s10r := float64(s10ru) - s10g := float64(s10gu) - s10b := float64(s10bu) - s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a - s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() - s01ru = s01ru * ma / 0xffff - s01gu = s01gu * ma / 0xffff + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (ablInterpolator) scale_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := float64((float64(dy)+0.5)*yscale) - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := float64((float64(dx)+0.5)*xscale) - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + +func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := &color.RGBA64{} + dstColor := color.Color(dstColorRGBA64) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := float64((float64(dy)+0.5)*yscale) - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := float64((float64(dx)+0.5)*xscale) - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s00ru = s00ru * ma / 0xffff + s00gu = s00gu * ma / 0xffff + s00bu = s00bu * ma / 0xffff + s00au = s00au * ma / 0xffff + } + s00r := float64(s00ru) + s00g := float64(s00gu) + s00b := float64(s00bu) + s00a := float64(s00au) + s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s10ru = s10ru * ma / 0xffff + s10gu = s10gu * ma / 0xffff + s10bu = s10bu * ma / 0xffff + s10au = s10au * ma / 0xffff + } + s10r := float64(s10ru) + s10g := float64(s10gu) + s10b := float64(s10bu) + s10a := float64(s10au) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s01ru = s01ru * ma / 0xffff + s01gu = s01gu * ma / 0xffff s01bu = s01bu * ma / 0xffff s01au = s01au * ma / 0xffff } @@ -2676,14 +3377,14 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2718,7 +3419,7 @@ func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, dstColor := color.Color(dstColorRGBA64) for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - sy := (float64(dy)+0.5)*yscale - 0.5 + sy := float64((float64(dy)+0.5)*yscale) - 0.5 // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for // sx, below. @@ -2735,7 +3436,7 @@ func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, } for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { - sx := (float64(dx)+0.5)*xscale - 0.5 + sx := float64((float64(dx)+0.5)*xscale) - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) xFrac1 := 1 - xFrac0 @@ -2772,10 +3473,10 @@ func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() @@ -2800,14 +3501,14 @@ func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -2842,8 +3543,8 @@ func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -2882,15 +3583,15 @@ func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Re s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X) s10ru := uint32(src.Pix[s10i]) * 0x101 s10r := float64(s10ru) - s10r = xFrac1*s00r + xFrac0*s10r + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X) s01ru := uint32(src.Pix[s01i]) * 0x101 s01r := float64(s01ru) s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X) s11ru := uint32(src.Pix[s11i]) * 0x101 s11r := float64(s11ru) - s11r = xFrac1*s01r + xFrac0*s11r - s11r = yFrac1*s10r + yFrac0*s11r + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) pr := uint32(s11r) out := uint8(pr >> 8) dst.Pix[d+0] = out @@ -2907,8 +3608,8 @@ func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image. d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -2959,10 +3660,10 @@ func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image. s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4 s01au := uint32(src.Pix[s01i+3]) * 0x101 s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff @@ -2981,14 +3682,14 @@ func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image. s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3008,8 +3709,8 @@ func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.R d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3060,10 +3761,10 @@ func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.R s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4 s01au := uint32(src.Pix[s01i+3]) * 0x101 s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff @@ -3082,14 +3783,14 @@ func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.R s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3108,8 +3809,8 @@ func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.R d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3160,10 +3861,10 @@ func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.R s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4 s01ru := uint32(src.Pix[s01i+0]) * 0x101 s01gu := uint32(src.Pix[s01i+1]) * 0x101 @@ -3182,14 +3883,14 @@ func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.R s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3209,8 +3910,8 @@ func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Re d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3261,10 +3962,10 @@ func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Re s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4 s01ru := uint32(src.Pix[s01i+0]) * 0x101 s01gu := uint32(src.Pix[s01i+1]) * 0x101 @@ -3283,14 +3984,14 @@ func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Re s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3309,8 +4010,8 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3401,9 +4102,9 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X) s01j := (sy1-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X) @@ -3462,12 +4163,12 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3485,8 +4186,8 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3577,9 +4278,9 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X) s01j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2) @@ -3638,12 +4339,12 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3661,8 +4362,8 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3753,9 +4454,9 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X) s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2) @@ -3814,12 +4515,12 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -3837,8 +4538,8 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -3929,9 +4630,9 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X) s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X) @@ -3990,12 +4691,12 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -4007,14 +4708,177 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag } } +func (ablInterpolator) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sx0, sy0) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sx0, sy1) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (ablInterpolator) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sx0, sy0) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sx0, sy1) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -4057,10 +4921,10 @@ func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image. s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA() s01r := float64(s01ru) s01g := float64(s01gu) @@ -4071,14 +4935,14 @@ func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image. s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -4098,8 +4962,8 @@ func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.R d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -4142,10 +5006,10 @@ func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.R s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA() s01r := float64(s01ru) s01g := float64(s01gu) @@ -4156,14 +5020,14 @@ func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.R s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -4176,17 +5040,17 @@ func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.R } } -func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { +func (ablInterpolator) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { srcMask, smp := opts.SrcMask, opts.SrcMaskP dstMask, dmp := opts.DstMask, opts.DstMaskP - dstColorRGBA64 := &color.RGBA64{} - dstColor := color.Color(dstColorRGBA64) + dstColorRGBA64 := color.RGBA64{} + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -4219,66 +5083,312 @@ func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Recta yFrac0, yFrac1 = 1, 0 } - s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA() + s00u := src.RGBA64At(sx0, sy0) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() - s00ru = s00ru * ma / 0xffff - s00gu = s00gu * ma / 0xffff - s00bu = s00bu * ma / 0xffff - s00au = s00au * ma / 0xffff - } - s00r := float64(s00ru) - s00g := float64(s00gu) - s00b := float64(s00bu) - s00a := float64(s00au) - s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA() - s10ru = s10ru * ma / 0xffff - s10gu = s10gu * ma / 0xffff - s10bu = s10bu * ma / 0xffff - s10au = s10au * ma / 0xffff - } - s10r := float64(s10ru) - s10g := float64(s10gu) - s10b := float64(s10bu) - s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a - s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sx0, sy1) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA() - s01ru = s01ru * ma / 0xffff - s01gu = s01gu * ma / 0xffff - s01bu = s01bu * ma / 0xffff - s01au = s01au * ma / 0xffff - } - s01r := float64(s01ru) - s01g := float64(s01gu) - s01b := float64(s01bu) - s01a := float64(s01au) - s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA() - s11ru = s11ru * ma / 0xffff - s11gu = s11gu * ma / 0xffff - s11bu = s11bu * ma / 0xffff - s11au = s11au * ma / 0xffff - } - s11r := float64(s11ru) - s11g := float64(s11gu) - s11b := float64(s11bu) + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (ablInterpolator) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sx0, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01u := src.RGBA64At(sx0, sy1) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + +func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := &color.RGBA64{} + dstColor := color.Color(dstColorRGBA64) + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + s00ru = s00ru * ma / 0xffff + s00gu = s00gu * ma / 0xffff + s00bu = s00bu * ma / 0xffff + s00au = s00au * ma / 0xffff + } + s00r := float64(s00ru) + s00g := float64(s00gu) + s00b := float64(s00bu) + s00a := float64(s00au) + s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA() + s10ru = s10ru * ma / 0xffff + s10gu = s10gu * ma / 0xffff + s10bu = s10bu * ma / 0xffff + s10au = s10au * ma / 0xffff + } + s10r := float64(s10ru) + s10g := float64(s10gu) + s10b := float64(s10bu) + s10a := float64(s10au) + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) + s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA() + s01ru = s01ru * ma / 0xffff + s01gu = s01gu * ma / 0xffff + s01bu = s01bu * ma / 0xffff + s01au = s01au * ma / 0xffff + } + s01r := float64(s01ru) + s01g := float64(s01gu) + s01b := float64(s01bu) + s01a := float64(s01au) + s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA() + s11ru = s11ru * ma / 0xffff + s11gu = s11gu * ma / 0xffff + s11bu = s11bu * ma / 0xffff + s11au = s11au * ma / 0xffff + } + s11r := float64(s11ru) + s11g := float64(s11gu) + s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -4310,8 +5420,8 @@ func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectan dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -4368,10 +5478,10 @@ func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectan s10g := float64(s10gu) s10b := float64(s10bu) s10a := float64(s10au) - s10r = xFrac1*s00r + xFrac0*s10r - s10g = xFrac1*s00g + xFrac0*s10g - s10b = xFrac1*s00b + xFrac0*s10b - s10a = xFrac1*s00a + xFrac0*s10a + s10r = float64(xFrac1*s00r) + float64(xFrac0*s10r) + s10g = float64(xFrac1*s00g) + float64(xFrac0*s10g) + s10b = float64(xFrac1*s00b) + float64(xFrac0*s10b) + s10a = float64(xFrac1*s00a) + float64(xFrac0*s10a) s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA() if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA() @@ -4396,14 +5506,14 @@ func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectan s11g := float64(s11gu) s11b := float64(s11bu) s11a := float64(s11au) - s11r = xFrac1*s01r + xFrac0*s11r - s11g = xFrac1*s01g + xFrac0*s11g - s11b = xFrac1*s01b + xFrac0*s11b - s11a = xFrac1*s01a + xFrac0*s11a - s11r = yFrac1*s10r + yFrac0*s11r - s11g = yFrac1*s10g + yFrac0*s11g - s11b = yFrac1*s10b + yFrac0*s11b - s11a = yFrac1*s10a + yFrac0*s11a + s11r = float64(xFrac1*s01r) + float64(xFrac0*s11r) + s11g = float64(xFrac1*s01g) + float64(xFrac0*s11g) + s11b = float64(xFrac1*s01b) + float64(xFrac0*s11b) + s11a = float64(xFrac1*s01a) + float64(xFrac0*s11a) + s11r = float64(yFrac1*s10r) + float64(yFrac0*s11r) + s11g = float64(yFrac1*s10g) + float64(yFrac0*s11g) + s11b = float64(yFrac1*s10b) + float64(yFrac0*s11b) + s11a = float64(yFrac1*s10a) + float64(yFrac0*s11a) pr := uint32(s11r) pg := uint32(s11g) pb := uint32(s11b) @@ -4500,6 +5610,8 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr case image.YCbCrSubsampleRatio440: z.scaleX_YCbCr440(tmp, src, sr, &o) } + case image.RGBA64Image: + z.scaleX_RGBA64Image(tmp, src, sr, &o) default: z.scaleX_Image(tmp, src, sr, &o) } @@ -4518,6 +5630,8 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr switch dst := dst.(type) { case *image.RGBA: z.scaleY_RGBA_Over(dst, dr, adr, tmp, &o) + case RGBA64Image: + z.scaleY_RGBA64Image_Over(dst, dr, adr, tmp, &o) default: z.scaleY_Image_Over(dst, dr, adr, tmp, &o) } @@ -4525,6 +5639,8 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr switch dst := dst.(type) { case *image.RGBA: z.scaleY_RGBA_Src(dst, dr, adr, tmp, &o) + case RGBA64Image: + z.scaleY_RGBA64Image_Src(dst, dr, adr, tmp, &o) default: z.scaleY_Image_Src(dst, dr, adr, tmp, &o) } @@ -4600,9 +5716,16 @@ func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Re q.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) case *image.RGBA: q.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) + case image.RGBA64Image: + q.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) default: q.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + q.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) + } default: switch src := src.(type) { default: @@ -4632,9 +5755,16 @@ func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Re case image.YCbCrSubsampleRatio440: q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) } + case image.RGBA64Image: + q.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) default: q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + q.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) + } default: switch src := src.(type) { default: @@ -4653,7 +5783,7 @@ func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.R for _, c := range z.horizontal.contribs[s.i:s.j] { pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(c.coord) - src.Rect.Min.X) pru := uint32(src.Pix[pi]) * 0x101 - pr += float64(pru) * c.weight + pr += float64(float64(pru) * c.weight) } pr *= s.invTotalWeightFFFF tmp[t] = [4]float64{ @@ -4678,10 +5808,10 @@ func (z *kernelScaler) scaleX_NRGBA(tmp [][4]float64, src *image.NRGBA, sr image pru := uint32(src.Pix[pi+0]) * pau / 0xff pgu := uint32(src.Pix[pi+1]) * pau / 0xff pbu := uint32(src.Pix[pi+2]) * pau / 0xff - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight - pa += float64(pau) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) + pa += float64(float64(pau) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4705,10 +5835,10 @@ func (z *kernelScaler) scaleX_RGBA(tmp [][4]float64, src *image.RGBA, sr image.R pgu := uint32(src.Pix[pi+1]) * 0x101 pbu := uint32(src.Pix[pi+2]) * 0x101 pau := uint32(src.Pix[pi+3]) * 0x101 - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight - pa += float64(pau) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) + pa += float64(float64(pau) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4753,9 +5883,9 @@ func (z *kernelScaler) scaleX_YCbCr444(tmp [][4]float64, src *image.YCbCr, sr im pbu = 0xffff } - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4800,9 +5930,9 @@ func (z *kernelScaler) scaleX_YCbCr422(tmp [][4]float64, src *image.YCbCr, sr im pbu = 0xffff } - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4847,9 +5977,9 @@ func (z *kernelScaler) scaleX_YCbCr420(tmp [][4]float64, src *image.YCbCr, sr im pbu = 0xffff } - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4894,9 +6024,9 @@ func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr im pbu = 0xffff } - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4909,6 +6039,37 @@ func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr im } } +func (z *kernelScaler) scaleX_RGBA64Image(tmp [][4]float64, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + t := 0 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + for y := int32(0); y < z.sh; y++ { + for _, s := range z.horizontal.sources { + var pr, pg, pb, pa float64 + for _, c := range z.horizontal.contribs[s.i:s.j] { + pu := src.RGBA64At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA() + pu.R = uint16(uint32(pu.R) * ma / 0xffff) + pu.G = uint16(uint32(pu.G) * ma / 0xffff) + pu.B = uint16(uint32(pu.B) * ma / 0xffff) + pu.A = uint16(uint32(pu.A) * ma / 0xffff) + } + pr += float64(float64(pu.R) * c.weight) + pg += float64(float64(pu.G) * c.weight) + pb += float64(float64(pu.B) * c.weight) + pa += float64(float64(pu.A) * c.weight) + } + tmp[t] = [4]float64{ + pr * s.invTotalWeightFFFF, + pg * s.invTotalWeightFFFF, + pb * s.invTotalWeightFFFF, + pa * s.invTotalWeightFFFF, + } + t++ + } + } +} + func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle, opts *Options) { t := 0 srcMask, smp := opts.SrcMask, opts.SrcMaskP @@ -4924,10 +6085,10 @@ func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image. pbu = pbu * ma / 0xffff pau = pau * ma / 0xffff } - pr += float64(pru) * c.weight - pg += float64(pgu) * c.weight - pb += float64(pbu) * c.weight - pa += float64(pau) * c.weight + pr += float64(float64(pru) * c.weight) + pg += float64(float64(pgu) * c.weight) + pb += float64(float64(pbu) * c.weight) + pa += float64(float64(pau) * c.weight) } tmp[t] = [4]float64{ pr * s.invTotalWeightFFFF, @@ -4947,10 +6108,10 @@ func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle var pr, pg, pb, pa float64 for _, c := range z.vertical.contribs[s.i:s.j] { p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + pr += float64(p[0] * c.weight) + pg += float64(p[1] * c.weight) + pb += float64(p[2] * c.weight) + pa += float64(p[3] * c.weight) } if pr > pa { @@ -4984,10 +6145,10 @@ func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, var pr, pg, pb, pa float64 for _, c := range z.vertical.contribs[s.i:s.j] { p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + pr += float64(p[0] * c.weight) + pg += float64(p[1] * c.weight) + pb += float64(p[2] * c.weight) + pa += float64(p[3] * c.weight) } if pr > pa { @@ -5009,6 +6170,102 @@ func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, } } +func (z *kernelScaler) scaleY_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += float64(p[0] * c.weight) + pg += float64(p[1] * c.weight) + pb += float64(p[2] * c.weight) + pa += float64(p[3] * c.weight) + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)) + pr0 := uint32(ftou(pr * s.invTotalWeight)) + pg0 := uint32(ftou(pg * s.invTotalWeight)) + pb0 := uint32(ftou(pb * s.invTotalWeight)) + pa0 := uint32(ftou(pa * s.invTotalWeight)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr0 = pr0 * ma / 0xffff + pg0 = pg0 * ma / 0xffff + pb0 = pb0 * ma / 0xffff + pa0 = pa0 * ma / 0xffff + } + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa0) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64) + } + } +} + +func (z *kernelScaler) scaleY_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += float64(p[0] * c.weight) + pg += float64(p[1] * c.weight) + pb += float64(p[2] * c.weight) + pa += float64(p[3] * c.weight) + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff + pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff + pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff + pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64) + } else { + dstColorRGBA64.R = ftou(pr * s.invTotalWeight) + dstColorRGBA64.G = ftou(pg * s.invTotalWeight) + dstColorRGBA64.B = ftou(pb * s.invTotalWeight) + dstColorRGBA64.A = ftou(pa * s.invTotalWeight) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64) + } + } + } +} + func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { dstMask, dmp := opts.DstMask, opts.DstMaskP dstColorRGBA64 := &color.RGBA64{} @@ -5018,10 +6275,10 @@ func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp var pr, pg, pb, pa float64 for _, c := range z.vertical.contribs[s.i:s.j] { p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + pr += float64(p[0] * c.weight) + pg += float64(p[1] * c.weight) + pb += float64(p[2] * c.weight) + pa += float64(p[3] * c.weight) } if pr > pa { @@ -5065,10 +6322,10 @@ func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp var pr, pg, pb, pa float64 for _, c := range z.vertical.contribs[s.i:s.j] { p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + pr += float64(p[0] * c.weight) + pg += float64(p[1] * c.weight) + pb += float64(p[2] * c.weight) + pa += float64(p[3] * c.weight) } if pr > pa { @@ -5127,8 +6384,8 @@ func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangl d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5190,7 +6447,7 @@ func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangl if w := xWeights[kx-ix] * yWeight; w != 0 { pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X) pru := uint32(src.Pix[pi]) * 0x101 - pr += float64(pru) * w + pr += float64(float64(pru) * w) } } } @@ -5226,8 +6483,8 @@ func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectan d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5292,10 +6549,10 @@ func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectan pru := uint32(src.Pix[pi+0]) * pau / 0xff pgu := uint32(src.Pix[pi+1]) * pau / 0xff pbu := uint32(src.Pix[pi+2]) * pau / 0xff - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) } } } @@ -5346,8 +6603,8 @@ func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectang d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5412,10 +6669,10 @@ func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectang pru := uint32(src.Pix[pi+0]) * pau / 0xff pgu := uint32(src.Pix[pi+1]) * pau / 0xff pbu := uint32(src.Pix[pi+2]) * pau / 0xff - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) } } } @@ -5461,8 +6718,8 @@ func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectang d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5527,10 +6784,10 @@ func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectang pgu := uint32(src.Pix[pi+1]) * 0x101 pbu := uint32(src.Pix[pi+2]) * 0x101 pau := uint32(src.Pix[pi+3]) * 0x101 - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) } } } @@ -5581,8 +6838,8 @@ func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangl d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5647,10 +6904,10 @@ func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangl pgu := uint32(src.Pix[pi+1]) * 0x101 pbu := uint32(src.Pix[pi+2]) * 0x101 pau := uint32(src.Pix[pi+3]) * 0x101 - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) } } } @@ -5696,8 +6953,8 @@ func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rect d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5783,9 +7040,9 @@ func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rect pbu = 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) } } } @@ -5820,8 +7077,8 @@ func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rect d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -5907,9 +7164,9 @@ func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rect pbu = 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) } } } @@ -5944,8 +7201,8 @@ func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rect d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -6031,9 +7288,9 @@ func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rect pbu = 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) } } } @@ -6068,8 +7325,8 @@ func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rect d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -6155,9 +7412,9 @@ func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rect pbu = 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) } } } @@ -6170,7 +7427,7 @@ func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rect } } -func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -6192,8 +7449,8 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -6253,11 +7510,11 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pru, pgu, pbu, pau := src.At(kx, ky).RGBA() - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pu := src.RGBA64At(kx, ky) + pr += float64(float64(pu.R) * w) + pg += float64(float64(pu.G) * w) + pb += float64(float64(pu.B) * w) + pa += float64(float64(pu.A) * w) } } } @@ -6286,7 +7543,7 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan } } -func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -6308,8 +7565,8 @@ func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectang d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -6369,11 +7626,11 @@ func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectang if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pru, pgu, pbu, pau := src.At(kx, ky).RGBA() - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pu := src.RGBA64At(kx, ky) + pr += float64(float64(pu.R) * w) + pg += float64(float64(pu.G) * w) + pb += float64(float64(pu.B) * w) + pa += float64(float64(pu.A) * w) } } } @@ -6397,6 +7654,505 @@ func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectang } } +func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr, pg, pb, pa float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pru, pgu, pbu, pau := src.At(kx, ky).RGBA() + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) + } + } + } + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) + } + } +} + +func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr, pg, pb, pa float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pru, pgu, pbu, pau := src.At(kx, ky).RGBA() + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) + } + } + } + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) + dst.Pix[d+1] = uint8(fffftou(pg) >> 8) + dst.Pix[d+2] = uint8(fffftou(pb) >> 8) + dst.Pix[d+3] = uint8(fffftou(pa) >> 8) + } + } +} + +func (q *Kernel) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr, pg, pb, pa float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pu := src.RGBA64At(kx, ky) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA() + pu.R = uint16(uint32(pu.R) * ma / 0xffff) + pu.G = uint16(uint32(pu.G) * ma / 0xffff) + pu.B = uint16(uint32(pu.B) * ma / 0xffff) + pu.A = uint16(uint32(pu.A) * ma / 0xffff) + } + pr += float64(float64(pu.R) * w) + pg += float64(float64(pu.G) * w) + pb += float64(float64(pu.B) * w) + pa += float64(float64(pu.A) * w) + } + } + } + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + pr0 = pr0 * ma / 0xffff + pg0 = pg0 * ma / 0xffff + pb0 = pb0 * ma / 0xffff + pa0 = pa0 * ma / 0xffff + } + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa0) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (q *Kernel) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr, pg, pb, pa float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pu := src.RGBA64At(kx, ky) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA() + pu.R = uint16(uint32(pu.R) * ma / 0xffff) + pu.G = uint16(uint32(pu.G) * ma / 0xffff) + pu.B = uint16(uint32(pu.B) * ma / 0xffff) + pu.A = uint16(uint32(pu.A) * ma / 0xffff) + } + pr += float64(float64(pu.R) * w) + pg += float64(float64(pu.G) * w) + pb += float64(float64(pu.B) * w) + pa += float64(float64(pu.A) * w) + } + } + } + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + pr := uint32(fffftou(pr)) * ma / 0xffff + pg := uint32(fffftou(pg)) * ma / 0xffff + pb := uint32(fffftou(pb)) * ma / 0xffff + pa := uint32(fffftou(pa)) * ma / 0xffff + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dstColorRGBA64.R = fffftou(pr) + dstColorRGBA64.G = fffftou(pg) + dstColorRGBA64.B = fffftou(pb) + dstColorRGBA64.A = fffftou(pa) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } + } +} + func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. @@ -6422,8 +8178,8 @@ func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -6491,10 +8247,10 @@ func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, pbu = pbu * ma / 0xffff pau = pau * ma / 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) } } } @@ -6557,8 +8313,8 @@ func (q *Kernel) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] - sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + sx := float64(d2s[0]*dxf) + float64(d2s[1]*dyf) + d2s[2] + sy := float64(d2s[3]*dxf) + float64(d2s[4]*dyf) + d2s[5] if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { continue } @@ -6626,10 +8382,10 @@ func (q *Kernel) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d pbu = pbu * ma / 0xffff pau = pau * ma / 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pr += float64(float64(pru) * w) + pg += float64(float64(pgu) * w) + pb += float64(float64(pbu) * w) + pa += float64(float64(pau) * w) } } } diff --git a/vendor/golang.org/x/image/draw/scale.go b/vendor/golang.org/x/image/draw/scale.go index 00121a129d..aef200b228 100644 --- a/vendor/golang.org/x/image/draw/scale.go +++ b/vendor/golang.org/x/image/draw/scale.go @@ -46,8 +46,8 @@ type Scaler interface { // // For example, if m is the matrix // -// m00 m01 m02 -// m10 m11 m12 +// m00 m01 m02 +// m10 m11 m12 // // then the src-space point (sx, sy) maps to the dst-space point // (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12). @@ -98,9 +98,9 @@ type Options struct { // have a 1:1 correspondence. // // Of the interpolators provided by this package: -// - NearestNeighbor is fast but usually looks worst. -// - CatmullRom is slow but usually looks best. -// - ApproxBiLinear has reasonable speed and quality. +// - NearestNeighbor is fast but usually looks worst. +// - CatmullRom is slow but usually looks best. +// - ApproxBiLinear has reasonable speed and quality. // // The time taken depends on the size of dr. For kernel interpolators, the // speed also depends on the size of sr, and so are often slower than @@ -182,9 +182,9 @@ var ( // Computer Graphics", Computer Graphics, Vol. 22, No. 4, pp. 221-228. CatmullRom = &Kernel{2, func(t float64) float64 { if t < 1 { - return (1.5*t-2.5)*t*t + 1 + return float64((float64(1.5*t)-2.5)*t*t) + 1 } - return ((-0.5*t+2.5)*t-4)*t + 2 + return float64((float64(float64(float64(-0.5*t)+2.5)*t)-4)*t) + 2 }} // TODO: a Kaiser-Bessel kernel? @@ -247,7 +247,7 @@ func newDistrib(q *Kernel, dw, sw int32) distrib { // source column or row. n, sources := int32(0), make([]source, dw) for x := range sources { - center := (float64(x)+0.5)*scale - 0.5 + center := float64((float64(x)+0.5)*scale) - 0.5 i := int32(math.Floor(center - halfWidth)) if i < 0 { i = 0 @@ -302,7 +302,7 @@ func abs(f float64) float64 { // ftou converts the range [0.0, 1.0] to [0, 0xffff]. func ftou(f float64) uint16 { - i := int32(0xffff*f + 0.5) + i := int32(float64(0xffff*f) + 0.5) if i > 0xffff { return 0xffff } @@ -332,12 +332,12 @@ func fffftou(f float64) uint16 { func invert(m *f64.Aff3) f64.Aff3 { m00 := +m[3*1+1] m01 := -m[3*0+1] - m02 := +m[3*1+2]*m[3*0+1] - m[3*1+1]*m[3*0+2] + m02 := +float64(m[3*1+2]*m[3*0+1]) - float64(m[3*1+1]*m[3*0+2]) m10 := -m[3*1+0] m11 := +m[3*0+0] - m12 := +m[3*1+0]*m[3*0+2] - m[3*1+2]*m[3*0+0] + m12 := +float64(m[3*1+0]*m[3*0+2]) - float64(m[3*1+2]*m[3*0+0]) - det := m00*m11 - m10*m01 + det := float64(m00*m11) - float64(m10*m01) return f64.Aff3{ m00 / det, @@ -351,12 +351,12 @@ func invert(m *f64.Aff3) f64.Aff3 { func matMul(p, q *f64.Aff3) f64.Aff3 { return f64.Aff3{ - p[3*0+0]*q[3*0+0] + p[3*0+1]*q[3*1+0], - p[3*0+0]*q[3*0+1] + p[3*0+1]*q[3*1+1], - p[3*0+0]*q[3*0+2] + p[3*0+1]*q[3*1+2] + p[3*0+2], - p[3*1+0]*q[3*0+0] + p[3*1+1]*q[3*1+0], - p[3*1+0]*q[3*0+1] + p[3*1+1]*q[3*1+1], - p[3*1+0]*q[3*0+2] + p[3*1+1]*q[3*1+2] + p[3*1+2], + float64(p[3*0+0]*q[3*0+0]) + float64(p[3*0+1]*q[3*1+0]), + float64(p[3*0+0]*q[3*0+1]) + float64(p[3*0+1]*q[3*1+1]), + float64(p[3*0+0]*q[3*0+2]) + float64(p[3*0+1]*q[3*1+2]) + p[3*0+2], + float64(p[3*1+0]*q[3*0+0]) + float64(p[3*1+1]*q[3*1+0]), + float64(p[3*1+0]*q[3*0+1]) + float64(p[3*1+1]*q[3*1+1]), + float64(p[3*1+0]*q[3*0+2]) + float64(p[3*1+1]*q[3*1+2]) + p[3*1+2], } } @@ -371,8 +371,8 @@ func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) { for i, p := range ps { sxf := float64(p.X) syf := float64(p.Y) - dx := int(math.Floor(s2d[0]*sxf + s2d[1]*syf + s2d[2])) - dy := int(math.Floor(s2d[3]*sxf + s2d[4]*syf + s2d[5])) + dx := int(math.Floor(float64(s2d[0]*sxf) + float64(s2d[1]*syf) + s2d[2])) + dy := int(math.Floor(float64(s2d[3]*sxf) + float64(s2d[4]*syf) + s2d[5])) // The +1 adjustments below are because an image.Rectangle is inclusive // on the low end but exclusive on the high end. @@ -428,8 +428,8 @@ func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *i d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy)) for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -450,8 +450,8 @@ func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *i dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -479,8 +479,8 @@ func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *i d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy)) for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } @@ -505,8 +505,8 @@ func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *i dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 - sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X - sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + sx0 := int(float64(d2s[0]*dxf)+float64(d2s[1]*dyf)+d2s[2]) + bias.X + sy0 := int(float64(d2s[3]*dxf)+float64(d2s[4]*dyf)+d2s[5]) + bias.Y if !(image.Point{sx0, sy0}).In(sr) { continue } diff --git a/vendor/golang.org/x/image/font/basicfont/basicfont.go b/vendor/golang.org/x/image/font/basicfont/basicfont.go index 15503818ff..173c0610f5 100644 --- a/vendor/golang.org/x/image/font/basicfont/basicfont.go +++ b/vendor/golang.org/x/image/font/basicfont/basicfont.go @@ -89,41 +89,50 @@ func (f *Face) Metrics() font.Metrics { func (f *Face) Glyph(dot fixed.Point26_6, r rune) ( dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { -loop: - for _, rr := range [2]rune{r, '\ufffd'} { - for _, rng := range f.Ranges { - if rr < rng.Low || rng.High <= rr { - continue - } - maskp.Y = (int(rr-rng.Low) + rng.Offset) * (f.Ascent + f.Descent) - ok = true - break loop + if found, rng := f.find(r); rng != nil { + maskp.Y = (int(found-rng.Low) + rng.Offset) * (f.Ascent + f.Descent) + x := int(dot.X+32)>>6 + f.Left + y := int(dot.Y+32) >> 6 + dr = image.Rectangle{ + Min: image.Point{ + X: x, + Y: y - f.Ascent, + }, + Max: image.Point{ + X: x + f.Width, + Y: y + f.Descent, + }, } - } - if !ok { - return image.Rectangle{}, nil, image.Point{}, 0, false - } - x := int(dot.X+32)>>6 + f.Left - y := int(dot.Y+32) >> 6 - dr = image.Rectangle{ - Min: image.Point{ - X: x, - Y: y - f.Ascent, - }, - Max: image.Point{ - X: x + f.Width, - Y: y + f.Descent, - }, + return dr, f.Mask, maskp, fixed.I(f.Advance), r == found } - - return dr, f.Mask, maskp, fixed.I(f.Advance), true + return image.Rectangle{}, nil, image.Point{}, 0, false } func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), true + if found, rng := f.find(r); rng != nil { + return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), r == found + } + return fixed.Rectangle26_6{}, 0, false } func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - return fixed.I(f.Advance), true + if found, rng := f.find(r); rng != nil { + return fixed.I(f.Advance), r == found + } + return 0, false +} + +func (f *Face) find(r rune) (rune, *Range) { + for { + for i, rng := range f.Ranges { + if (rng.Low <= r) && (r < rng.High) { + return r, &f.Ranges[i] + } + } + if r == '\ufffd' { + return 0, nil + } + r = '\ufffd' + } } diff --git a/vendor/golang.org/x/image/font/font.go b/vendor/golang.org/x/image/font/font.go index d1a75350d9..6b9b9bc89c 100644 --- a/vendor/golang.org/x/image/font/font.go +++ b/vendor/golang.org/x/image/font/font.go @@ -38,7 +38,10 @@ type Face interface { // glyph at the sub-pixel destination location dot, and that glyph's // advance width. // - // It returns !ok if the face does not contain a glyph for r. + // It returns !ok if the face does not contain a glyph for r. This includes + // returning !ok for a fallback glyph (such as substituting a U+FFFD glyph + // or OpenType's .notdef glyph), in which case the other return values may + // still be non-zero. // // The contents of the mask image returned by one Glyph call may change // after the next Glyph call. Callers that want to cache the mask must make @@ -49,7 +52,10 @@ type Face interface { // GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal // to the origin, and that glyph's advance width. // - // It returns !ok if the face does not contain a glyph for r. + // It returns !ok if the face does not contain a glyph for r. This includes + // returning !ok for a fallback glyph (such as substituting a U+FFFD glyph + // or OpenType's .notdef glyph), in which case the other return values may + // still be non-zero. // // The glyph's ascent and descent are equal to -bounds.Min.Y and // +bounds.Max.Y. The glyph's left-side and right-side bearings are equal @@ -60,7 +66,10 @@ type Face interface { // GlyphAdvance returns the advance width of r's glyph. // - // It returns !ok if the face does not contain a glyph for r. + // It returns !ok if the face does not contain a glyph for r. This includes + // returning !ok for a fallback glyph (such as substituting a U+FFFD glyph + // or OpenType's .notdef glyph), in which case the other return values may + // still be non-zero. GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) // Kern returns the horizontal adjustment for the kerning pair (r0, r1). A @@ -150,14 +159,10 @@ func (d *Drawer) DrawBytes(s []byte) { if prevC >= 0 { d.Dot.X += d.Face.Kern(prevC, c) } - dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c) + if !dr.Empty() { + draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) } - draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) d.Dot.X += advance prevC = c } @@ -170,14 +175,10 @@ func (d *Drawer) DrawString(s string) { if prevC >= 0 { d.Dot.X += d.Face.Kern(prevC, c) } - dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c) + if !dr.Empty() { + draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) } - draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) d.Dot.X += advance prevC = c } @@ -227,16 +228,12 @@ func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int if prevC >= 0 { advance += f.Kern(prevC, c) } - b, a, ok := f.GlyphBounds(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + b, a, _ := f.GlyphBounds(c) + if !b.Empty() { + b.Min.X += advance + b.Max.X += advance + bounds = bounds.Union(b) } - b.Min.X += advance - b.Max.X += advance - bounds = bounds.Union(b) advance += a prevC = c } @@ -251,16 +248,12 @@ func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.In if prevC >= 0 { advance += f.Kern(prevC, c) } - b, a, ok := f.GlyphBounds(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + b, a, _ := f.GlyphBounds(c) + if !b.Empty() { + b.Min.X += advance + b.Max.X += advance + bounds = bounds.Union(b) } - b.Min.X += advance - b.Max.X += advance - bounds = bounds.Union(b) advance += a prevC = c } @@ -278,13 +271,7 @@ func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) { if prevC >= 0 { advance += f.Kern(prevC, c) } - a, ok := f.GlyphAdvance(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue - } + a, _ := f.GlyphAdvance(c) advance += a prevC = c } @@ -298,13 +285,7 @@ func MeasureString(f Face, s string) (advance fixed.Int26_6) { if prevC >= 0 { advance += f.Kern(prevC, c) } - a, ok := f.GlyphAdvance(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue - } + a, _ := f.GlyphAdvance(c) advance += a prevC = c } diff --git a/vendor/golang.org/x/image/font/opentype/opentype.go b/vendor/golang.org/x/image/font/opentype/opentype.go index 231fdbea97..694ac47bfe 100644 --- a/vendor/golang.org/x/image/font/opentype/opentype.go +++ b/vendor/golang.org/x/image/font/opentype/opentype.go @@ -133,8 +133,8 @@ func (f *Face) Metrics() font.Metrics { // Kern satisfies the font.Face interface. func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 { - x0 := f.index(r0) - x1 := f.index(r1) + x0, _ := f.f.GlyphIndex(&f.buf, r0) + x1, _ := f.f.GlyphIndex(&f.buf, r1) k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting) if err != nil { return 0 @@ -251,22 +251,19 @@ func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask imag } f.rast.Draw(&f.mask, f.mask.Bounds(), image.Opaque, image.Point{}) - return dr, &f.mask, f.mask.Rect.Min, advance, true + return dr, &f.mask, f.mask.Rect.Min, advance, x != 0 } // GlyphBounds satisfies the font.Face interface. func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - bounds, advance, err := f.f.GlyphBounds(&f.buf, f.index(r), f.scale, f.hinting) - return bounds, advance, err == nil + x, _ := f.f.GlyphIndex(&f.buf, r) + bounds, advance, err := f.f.GlyphBounds(&f.buf, x, f.scale, f.hinting) + return bounds, advance, (err == nil) && (x != 0) } // GlyphAdvance satisfies the font.Face interface. func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - advance, err := f.f.GlyphAdvance(&f.buf, f.index(r), f.scale, f.hinting) - return advance, err == nil -} - -func (f *Face) index(r rune) sfnt.GlyphIndex { x, _ := f.f.GlyphIndex(&f.buf, r) - return x + advance, err := f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting) + return advance, (err == nil) && (x != 0) } diff --git a/vendor/golang.org/x/image/font/sfnt/cmap.go b/vendor/golang.org/x/image/font/sfnt/cmap.go index 55b4eadf41..2035ea9b59 100644 --- a/vendor/golang.org/x/image/font/sfnt/cmap.go +++ b/vendor/golang.org/x/image/font/sfnt/cmap.go @@ -186,6 +186,9 @@ func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([ if offset > indexesLength || offset+2 > indexesLength { return 0, errInvalidCmapTable } + if b == nil { + b = &Buffer{} + } x, err := b.view(&f.src, int(indexesBase+offset), 2) if err != nil { return 0, err diff --git a/vendor/golang.org/x/image/font/sfnt/gpos.go b/vendor/golang.org/x/image/font/sfnt/gpos.go index e0aafa5c8a..e0e339c4c4 100644 --- a/vendor/golang.org/x/image/font/sfnt/gpos.go +++ b/vendor/golang.org/x/image/font/sfnt/gpos.go @@ -14,7 +14,7 @@ const ( hexFeatureKern = uint32(0x6b65726e) // kern ) -//kernFunc returns the unscaled kerning value for kerning pair a+b. +// kernFunc returns the unscaled kerning value for kerning pair a+b. // Returns ErrNotFound if no kerning is specified for this pair. type kernFunc func(a, b GlyphIndex) (int16, error) @@ -437,7 +437,7 @@ func makeCachedCoverageRange(buf []byte) indexLookupFunc { // pairs: 130=0, 131=1, 132=2, 133=3, 134=4, 135=5, 137=6 // ranges: 130, 135, 0 137, 137, 6 // startCoverageIndex is used to calculate the index without counting - // the length of the preceeding ranges + // the length of the preceding ranges idx := sort.Search(num, func(i int) bool { return gi <= GlyphIndex(u16(ranges[i*6:])) diff --git a/vendor/golang.org/x/image/font/sfnt/postscript.go b/vendor/golang.org/x/image/font/sfnt/postscript.go index b686e60ac6..2a21997489 100644 --- a/vendor/golang.org/x/image/font/sfnt/postscript.go +++ b/vendor/golang.org/x/image/font/sfnt/postscript.go @@ -795,6 +795,18 @@ func (p *psInterpreter) parseNumber() (hasResult bool, err error) { } number, hasResult = int32(u32(p.instructions[1:])), true p.instructions = p.instructions[5:] + // 5177.Type2.pdf section 3.2 "Charstring Number Encoding" says "If the + // charstring byte contains the value 255... [this] number is + // interpreted as a Fixed; that is, a signed number with 16 bits of + // fraction". + // + // TODO: change the psType2CharstringsData.b.segments and + // psInterpreter.argStack data structures to optionally hold fixed + // point values, not just integer values. That's a substantial + // re-design, though. Until then, just round the 16.16 fixed point + // number to the closest integer value. This isn't just "number = + // ((number + 0x8000) >> 16)" because of potential overflow. + number = (number >> 16) + (1 & (number >> 15)) } if hasResult { diff --git a/vendor/golang.org/x/image/font/sfnt/sfnt.go b/vendor/golang.org/x/image/font/sfnt/sfnt.go index d693886d47..8ed19e21a9 100644 --- a/vendor/golang.org/x/image/font/sfnt/sfnt.go +++ b/vendor/golang.org/x/image/font/sfnt/sfnt.go @@ -153,30 +153,30 @@ type NameID uint16 const ( NameIDCopyright NameID = 0 - NameIDFamily = 1 - NameIDSubfamily = 2 - NameIDUniqueIdentifier = 3 - NameIDFull = 4 - NameIDVersion = 5 - NameIDPostScript = 6 - NameIDTrademark = 7 - NameIDManufacturer = 8 - NameIDDesigner = 9 - NameIDDescription = 10 - NameIDVendorURL = 11 - NameIDDesignerURL = 12 - NameIDLicense = 13 - NameIDLicenseURL = 14 - NameIDTypographicFamily = 16 - NameIDTypographicSubfamily = 17 - NameIDCompatibleFull = 18 - NameIDSampleText = 19 - NameIDPostScriptCID = 20 - NameIDWWSFamily = 21 - NameIDWWSSubfamily = 22 - NameIDLightBackgroundPalette = 23 - NameIDDarkBackgroundPalette = 24 - NameIDVariationsPostScriptPrefix = 25 + NameIDFamily NameID = 1 + NameIDSubfamily NameID = 2 + NameIDUniqueIdentifier NameID = 3 + NameIDFull NameID = 4 + NameIDVersion NameID = 5 + NameIDPostScript NameID = 6 + NameIDTrademark NameID = 7 + NameIDManufacturer NameID = 8 + NameIDDesigner NameID = 9 + NameIDDescription NameID = 10 + NameIDVendorURL NameID = 11 + NameIDDesignerURL NameID = 12 + NameIDLicense NameID = 13 + NameIDLicenseURL NameID = 14 + NameIDTypographicFamily NameID = 16 + NameIDTypographicSubfamily NameID = 17 + NameIDCompatibleFull NameID = 18 + NameIDSampleText NameID = 19 + NameIDPostScriptCID NameID = 20 + NameIDWWSFamily NameID = 21 + NameIDWWSSubfamily NameID = 22 + NameIDLightBackgroundPalette NameID = 23 + NameIDDarkBackgroundPalette NameID = 24 + NameIDVariationsPostScriptPrefix NameID = 25 ) // Units are an integral number of abstract, scalable "font units". The em @@ -745,7 +745,7 @@ func (f *Font) initialize(offset int, isDfont bool) error { f.cached.xHeight = xHeight if !hasXHeightCapHeight { - xh, ch, err := f.initOS2Version1() + xh, ch, err := f.initOS2VersionBelow2() if err != nil { return err } @@ -1201,7 +1201,7 @@ func (f *Font) glyphTopOS2(b *Buffer, ppem fixed.Int26_6, r rune) (int32, error) return int32(min), nil } -func (f *Font) initOS2Version1() (xHeight, capHeight int32, err error) { +func (f *Font) initOS2VersionBelow2() (xHeight, capHeight int32, err error) { ppem := fixed.Int26_6(f.UnitsPerEm()) var b Buffer @@ -1235,12 +1235,14 @@ func (f *Font) parseOS2(buf []byte) (buf1 []byte, hasXHeightCapHeight bool, xHei if err != nil { return nil, false, 0, 0, err } - if vers <= 1 { - const headerSize = 86 + if vers < 2 { + // "The original TrueType specification had this table at 68 bytes long." + // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html + const headerSize = 68 if f.os2.length < headerSize { return nil, false, 0, 0, errInvalidOS2Table } - // Will resolve xHeight and capHeight later, see initOS2Version1. + // Will resolve xHeight and capHeight later, see initOS2VersionBelow2. return buf, false, 0, 0, nil } const headerSize = 96 diff --git a/vendor/golang.org/x/image/font/sfnt/truetype.go b/vendor/golang.org/x/image/font/sfnt/truetype.go index ffa753ff60..0d0b309bd3 100644 --- a/vendor/golang.org/x/image/font/sfnt/truetype.go +++ b/vendor/golang.org/x/image/font/sfnt/truetype.go @@ -152,9 +152,10 @@ func loadGlyf(f *Font, b *Buffer, x GlyphIndex, stackBottom, recursionDepth uint xIndex: xIndex, yIndex: yIndex, endIndex: glyfHeaderLen, - // The -1 is because the contour-end index in the file format is - // inclusive, but Go's slice[:index] semantics are exclusive. + // The -1 on prevEnd and finalEnd are because the contour-end index in + // the file format is inclusive, but Go's slice[:index] is exclusive. prevEnd: -1, + finalEnd: int32(numPoints - 1), numContours: int32(numContours), } for g.nextContour() { @@ -334,9 +335,11 @@ type glyfIter struct { yIndex int32 // endIndex points to the uint16 that is the inclusive point index of the - // current contour's end. prevEnd is the previous contour's end. + // current contour's end. prevEnd is the previous contour's end. finalEnd + // should match the final contour's end. endIndex int32 prevEnd int32 + finalEnd int32 // c and p count the current contour and point, up to numContours and // numPoints. @@ -386,13 +389,16 @@ type glyfIter struct { func (g *glyfIter) nextContour() (ok bool) { if g.c == g.numContours { + if g.prevEnd != g.finalEnd { + g.err = errInvalidGlyphData + } return false } g.c++ end := int32(u16(g.data[g.endIndex:])) g.endIndex += 2 - if end <= g.prevEnd { + if (end <= g.prevEnd) || (g.finalEnd < end) { g.err = errInvalidGlyphData return false } diff --git a/vendor/golang.org/x/image/vector/acc_amd64.go b/vendor/golang.org/x/image/vector/acc_amd64.go index a6fa0ca263..5b148c5859 100644 --- a/vendor/golang.org/x/image/vector/acc_amd64.go +++ b/vendor/golang.org/x/image/vector/acc_amd64.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !appengine && gc && !noasm -// +build !appengine,gc,!noasm package vector diff --git a/vendor/golang.org/x/image/vector/acc_other.go b/vendor/golang.org/x/image/vector/acc_other.go index 39022691b9..e383d52c73 100644 --- a/vendor/golang.org/x/image/vector/acc_other.go +++ b/vendor/golang.org/x/image/vector/acc_other.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm package vector diff --git a/vendor/golang.org/x/image/vector/raster_fixed.go b/vendor/golang.org/x/image/vector/raster_fixed.go index 5b0fe7a7eb..12330da8a9 100644 --- a/vendor/golang.org/x/image/vector/raster_fixed.go +++ b/vendor/golang.org/x/image/vector/raster_fixed.go @@ -32,8 +32,11 @@ type int1ϕ int32 // The Rasterizer's bufU32 field, nominally of type []uint32 (since that slice // is also used by other code), can be thought of as a []int2ϕ during the // fixedLineTo method. Lines of code that are actually like: +// // buf[i] += uint32(etc) // buf has type []uint32. +// // can be thought of as +// // buf[i] += int2ϕ(etc) // buf has type []int2ϕ. type int2ϕ int32 diff --git a/vendor/golang.org/x/image/webp/decode.go b/vendor/golang.org/x/image/webp/decode.go index d6eefd596b..e211c7d57b 100644 --- a/vendor/golang.org/x/image/webp/decode.go +++ b/vendor/golang.org/x/image/webp/decode.go @@ -39,6 +39,7 @@ func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) { alpha []byte alphaStride int wantAlpha bool + seenVP8X bool widthMinusOne uint32 heightMinusOne uint32 buf [10]byte @@ -113,6 +114,10 @@ func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) { return m, image.Config{}, err case fccVP8X: + if seenVP8X { + return nil, image.Config{}, errInvalidFormat + } + seenVP8X = true if chunkLen != 10 { return nil, image.Config{}, errInvalidFormat } diff --git a/vendor/golang.org/x/mod/modfile/read.go b/vendor/golang.org/x/mod/modfile/read.go index de1b98211a..2d7486804f 100644 --- a/vendor/golang.org/x/mod/modfile/read.go +++ b/vendor/golang.org/x/mod/modfile/read.go @@ -877,6 +877,11 @@ func (in *input) parseLineBlock(start Position, token []string, lparen token) *L in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune)) case ')': rparen := in.lex() + // Don't preserve blank lines (denoted by a single empty comment, added above) + // at the end of the block. + if len(comments) == 1 && comments[0] == (Comment{}) { + comments = nil + } x.RParen.Before = comments x.RParen.Pos = rparen.pos if !in.peek().isEOL() { diff --git a/vendor/golang.org/x/net/html/doc.go b/vendor/golang.org/x/net/html/doc.go index 3a7e5ab176..885c4c5936 100644 --- a/vendor/golang.org/x/net/html/doc.go +++ b/vendor/golang.org/x/net/html/doc.go @@ -78,16 +78,11 @@ example, to process each anchor node in depth-first order: if err != nil { // ... } - var f func(*html.Node) - f = func(n *html.Node) { + for n := range doc.Descendants() { if n.Type == html.ElementNode && n.Data == "a" { // Do something with n... } - for c := n.FirstChild; c != nil; c = c.NextSibling { - f(c) - } } - f(doc) The relevant specifications include: https://html.spec.whatwg.org/multipage/syntax.html and diff --git a/vendor/golang.org/x/net/html/doctype.go b/vendor/golang.org/x/net/html/doctype.go index c484e5a94f..bca3ae9a0c 100644 --- a/vendor/golang.org/x/net/html/doctype.go +++ b/vendor/golang.org/x/net/html/doctype.go @@ -87,7 +87,7 @@ func parseDoctype(s string) (n *Node, quirks bool) { } } if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && - strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { + strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") { quirks = true } } diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go index 9da9e9dc42..e8515d8e88 100644 --- a/vendor/golang.org/x/net/html/foreign.go +++ b/vendor/golang.org/x/net/html/foreign.go @@ -40,8 +40,7 @@ func htmlIntegrationPoint(n *Node) bool { if n.Data == "annotation-xml" { for _, a := range n.Attr { if a.Key == "encoding" { - val := strings.ToLower(a.Val) - if val == "text/html" || val == "application/xhtml+xml" { + if strings.EqualFold(a.Val, "text/html") || strings.EqualFold(a.Val, "application/xhtml+xml") { return true } } diff --git a/vendor/golang.org/x/net/html/iter.go b/vendor/golang.org/x/net/html/iter.go new file mode 100644 index 0000000000..54be8fd30f --- /dev/null +++ b/vendor/golang.org/x/net/html/iter.go @@ -0,0 +1,56 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.23 + +package html + +import "iter" + +// Ancestors returns an iterator over the ancestors of n, starting with n.Parent. +// +// Mutating a Node or its parents while iterating may have unexpected results. +func (n *Node) Ancestors() iter.Seq[*Node] { + _ = n.Parent // eager nil check + + return func(yield func(*Node) bool) { + for p := n.Parent; p != nil && yield(p); p = p.Parent { + } + } +} + +// ChildNodes returns an iterator over the immediate children of n, +// starting with n.FirstChild. +// +// Mutating a Node or its children while iterating may have unexpected results. +func (n *Node) ChildNodes() iter.Seq[*Node] { + _ = n.FirstChild // eager nil check + + return func(yield func(*Node) bool) { + for c := n.FirstChild; c != nil && yield(c); c = c.NextSibling { + } + } + +} + +// Descendants returns an iterator over all nodes recursively beneath +// n, excluding n itself. Nodes are visited in depth-first preorder. +// +// Mutating a Node or its descendants while iterating may have unexpected results. +func (n *Node) Descendants() iter.Seq[*Node] { + _ = n.FirstChild // eager nil check + + return func(yield func(*Node) bool) { + n.descendants(yield) + } +} + +func (n *Node) descendants(yield func(*Node) bool) bool { + for c := range n.ChildNodes() { + if !yield(c) || !c.descendants(yield) { + return false + } + } + return true +} diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 1350eef22c..77741a1950 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -38,6 +38,10 @@ var scopeMarker = Node{Type: scopeMarkerNode} // that it looks like "a off4 { + // Calculate how many bytes of the address to copy: + // either full IPv4 length or the available length. + n := off4 + ipv4Len + if sockAddrLen < n { + n = sockAddrLen + } + copy(a.IP[:], b[off4:n]) + } return a, nil case syscall.AF_INET6: - if len(b) < sizeofSockaddrInet6 { + if len(b) < int(b[0]) { return nil, errInvalidAddr } - a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))} - copy(a.IP[:], b[8:24]) - if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) { - // KAME based IPv6 protocol stack usually - // embeds the interface index in the - // interface-local or link-local address as - // the kernel-internal form. - id := int(bigEndian.Uint16(a.IP[2:4])) - if id != 0 { - a.ZoneID = id - a.IP[2], a.IP[3] = 0, 0 + sockAddrLen := int(b[0]) + a := &Inet6Addr{} + // sockAddrLen of 0 is valid and represents :: + if sockAddrLen > off6 { + n := off6 + ipv6Len + if sockAddrLen < n { + n = sockAddrLen + } + if sockAddrLen == sizeofSockaddrInet6 { + a.ZoneID = int(nativeEndian.Uint32(b[24:28])) + } + copy(a.IP[:], b[off6:n]) + if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) { + // KAME based IPv6 protocol stack usually + // embeds the interface index in the + // interface-local or link-local address as + // the kernel-internal form. + id := int(bigEndian.Uint16(a.IP[2:4])) + if id != 0 { + a.ZoneID = id + a.IP[2], a.IP[3] = 0, 0 + } } } return a, nil diff --git a/vendor/golang.org/x/net/route/sys_netbsd.go b/vendor/golang.org/x/net/route/sys_netbsd.go index be4460e13f..c6bb6bc8a2 100644 --- a/vendor/golang.org/x/net/route/sys_netbsd.go +++ b/vendor/golang.org/x/net/route/sys_netbsd.go @@ -25,7 +25,7 @@ func (m *RouteMessage) Sys() []Sys { } } -// RouteMetrics represents route metrics. +// InterfaceMetrics represents route metrics. type InterfaceMetrics struct { Type int // interface type MTU int // maximum transmission unit diff --git a/vendor/golang.org/x/net/route/zsys_darwin.go b/vendor/golang.org/x/net/route/zsys_darwin.go index 56a0c66f44..adaa460026 100644 --- a/vendor/golang.org/x/net/route/zsys_darwin.go +++ b/vendor/golang.org/x/net/route/zsys_darwin.go @@ -9,14 +9,10 @@ const ( sizeofIfmaMsghdrDarwin15 = 0x10 sizeofIfMsghdr2Darwin15 = 0xa0 sizeofIfmaMsghdr2Darwin15 = 0x14 - sizeofIfDataDarwin15 = 0x60 - sizeofIfData64Darwin15 = 0x80 sizeofRtMsghdrDarwin15 = 0x5c sizeofRtMsghdr2Darwin15 = 0x5c - sizeofRtMetricsDarwin15 = 0x38 - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_dragonfly.go b/vendor/golang.org/x/net/route/zsys_dragonfly.go index f7c7a60cd6..209cb20af8 100644 --- a/vendor/golang.org/x/net/route/zsys_dragonfly.go +++ b/vendor/golang.org/x/net/route/zsys_dragonfly.go @@ -11,10 +11,8 @@ const ( sizeofIfaMsghdrDragonFlyBSD58 = 0x18 - sizeofRtMsghdrDragonFlyBSD4 = 0x98 - sizeofRtMetricsDragonFlyBSD4 = 0x70 + sizeofRtMsghdrDragonFlyBSD4 = 0x98 - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/vendor/golang.org/x/net/route/zsys_freebsd_386.go index 3f985c7ee9..ec617772b2 100644 --- a/vendor/golang.org/x/net/route/zsys_freebsd_386.go +++ b/vendor/golang.org/x/net/route/zsys_freebsd_386.go @@ -6,7 +6,6 @@ package route const ( sizeofIfMsghdrlFreeBSD10 = 0x68 sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0x6c sizeofIfmaMsghdrFreeBSD10 = 0x10 sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 @@ -19,18 +18,10 @@ const ( sizeofIfMsghdrFreeBSD10 = 0x64 sizeofIfMsghdrFreeBSD11 = 0xa8 - sizeofIfDataFreeBSD7 = 0x50 - sizeofIfDataFreeBSD8 = 0x50 - sizeofIfDataFreeBSD9 = 0x50 - sizeofIfDataFreeBSD10 = 0x54 - sizeofIfDataFreeBSD11 = 0x98 - // MODIFIED BY HAND FOR 386 EMULATION ON AMD64 // 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 sizeofIfmaMsghdrFreeBSD10Emu = 0x10 sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 @@ -43,13 +34,6 @@ const ( sizeofIfMsghdrFreeBSD10Emu = 0xa8 sizeofIfMsghdrFreeBSD11Emu = 0xa8 - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go index 9293393698..3d7f31d13e 100644 --- a/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go +++ b/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go @@ -6,7 +6,6 @@ package route const ( sizeofIfMsghdrlFreeBSD10 = 0xb0 sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0xb0 sizeofIfmaMsghdrFreeBSD10 = 0x10 sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 @@ -19,15 +18,7 @@ const ( sizeofIfMsghdrFreeBSD10 = 0xa8 sizeofIfMsghdrFreeBSD11 = 0xa8 - sizeofIfDataFreeBSD7 = 0x98 - sizeofIfDataFreeBSD8 = 0x98 - sizeofIfDataFreeBSD9 = 0x98 - sizeofIfDataFreeBSD10 = 0x98 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 sizeofIfmaMsghdrFreeBSD10Emu = 0x10 sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 @@ -40,13 +31,6 @@ const ( sizeofIfMsghdrFreeBSD10Emu = 0xa8 sizeofIfMsghdrFreeBSD11Emu = 0xa8 - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/vendor/golang.org/x/net/route/zsys_freebsd_arm.go index a2bdb4ad3b..931afa3931 100644 --- a/vendor/golang.org/x/net/route/zsys_freebsd_arm.go +++ b/vendor/golang.org/x/net/route/zsys_freebsd_arm.go @@ -6,7 +6,6 @@ package route const ( sizeofIfMsghdrlFreeBSD10 = 0x68 sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0x6c sizeofIfmaMsghdrFreeBSD10 = 0x10 sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 @@ -19,15 +18,7 @@ const ( sizeofIfMsghdrFreeBSD10 = 0x70 sizeofIfMsghdrFreeBSD11 = 0xa8 - sizeofIfDataFreeBSD7 = 0x60 - sizeofIfDataFreeBSD8 = 0x60 - sizeofIfDataFreeBSD9 = 0x60 - sizeofIfDataFreeBSD10 = 0x60 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0x68 sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0x6c sizeofIfmaMsghdrFreeBSD10Emu = 0x10 sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 @@ -40,13 +31,6 @@ const ( sizeofIfMsghdrFreeBSD10Emu = 0x70 sizeofIfMsghdrFreeBSD11Emu = 0xa8 - sizeofIfDataFreeBSD7Emu = 0x60 - sizeofIfDataFreeBSD8Emu = 0x60 - sizeofIfDataFreeBSD9Emu = 0x60 - sizeofIfDataFreeBSD10Emu = 0x60 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go b/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go index 9293393698..3d7f31d13e 100644 --- a/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go +++ b/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go @@ -6,7 +6,6 @@ package route const ( sizeofIfMsghdrlFreeBSD10 = 0xb0 sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0xb0 sizeofIfmaMsghdrFreeBSD10 = 0x10 sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 @@ -19,15 +18,7 @@ const ( sizeofIfMsghdrFreeBSD10 = 0xa8 sizeofIfMsghdrFreeBSD11 = 0xa8 - sizeofIfDataFreeBSD7 = 0x98 - sizeofIfDataFreeBSD8 = 0x98 - sizeofIfDataFreeBSD9 = 0x98 - sizeofIfDataFreeBSD10 = 0x98 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 sizeofIfmaMsghdrFreeBSD10Emu = 0x10 sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 @@ -40,13 +31,6 @@ const ( sizeofIfMsghdrFreeBSD10Emu = 0xa8 sizeofIfMsghdrFreeBSD11Emu = 0xa8 - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go b/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go index 9293393698..3d7f31d13e 100644 --- a/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go +++ b/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go @@ -6,7 +6,6 @@ package route const ( sizeofIfMsghdrlFreeBSD10 = 0xb0 sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0xb0 sizeofIfmaMsghdrFreeBSD10 = 0x10 sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 @@ -19,15 +18,7 @@ const ( sizeofIfMsghdrFreeBSD10 = 0xa8 sizeofIfMsghdrFreeBSD11 = 0xa8 - sizeofIfDataFreeBSD7 = 0x98 - sizeofIfDataFreeBSD8 = 0x98 - sizeofIfDataFreeBSD9 = 0x98 - sizeofIfDataFreeBSD10 = 0x98 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 sizeofIfmaMsghdrFreeBSD10Emu = 0x10 sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 @@ -40,13 +31,6 @@ const ( sizeofIfMsghdrFreeBSD10Emu = 0xa8 sizeofIfMsghdrFreeBSD11Emu = 0xa8 - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_netbsd.go b/vendor/golang.org/x/net/route/zsys_netbsd.go index eaffe8c408..90ce707d47 100644 --- a/vendor/golang.org/x/net/route/zsys_netbsd.go +++ b/vendor/golang.org/x/net/route/zsys_netbsd.go @@ -8,10 +8,8 @@ const ( sizeofIfaMsghdrNetBSD7 = 0x18 sizeofIfAnnouncemsghdrNetBSD7 = 0x18 - sizeofRtMsghdrNetBSD7 = 0x78 - sizeofRtMetricsNetBSD7 = 0x50 + sizeofRtMsghdrNetBSD7 = 0x78 - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/net/route/zsys_openbsd.go b/vendor/golang.org/x/net/route/zsys_openbsd.go index b11b812680..64fbdd98fb 100644 --- a/vendor/golang.org/x/net/route/zsys_openbsd.go +++ b/vendor/golang.org/x/net/route/zsys_openbsd.go @@ -6,7 +6,6 @@ package route const ( sizeofRtMsghdr = 0x60 - sizeofSockaddrStorage = 0x100 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c + sizeofSockaddrInet = 0x10 + sizeofSockaddrInet6 = 0x1c ) diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index 948a3ee63d..b8322598ae 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -118,6 +118,7 @@ func (g *Group) TryGo(f func() error) bool { // SetLimit limits the number of active goroutines in this group to at most n. // A negative value indicates no limit. +// A limit of zero will prevent any new goroutines from being added. // // Any subsequent call to the Go method will block until it can add an active // goroutine without exceeding the configured limit. diff --git a/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s b/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s new file mode 100644 index 0000000000..ec2acfe540 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && amd64 && gc + +#include "textflag.h" + +TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) +GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) + +TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_sysctlbyname(SB) +GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8 +DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go index ec07aab057..9c105f23af 100644 --- a/vendor/golang.org/x/sys/cpu/cpu.go +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -72,6 +72,9 @@ var X86 struct { HasSSSE3 bool // Supplemental streaming SIMD extension 3 HasSSE41 bool // Streaming SIMD extension 4 and 4.1 HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + HasAVXIFMA bool // Advanced vector extension Integer Fused Multiply Add + HasAVXVNNI bool // Advanced vector extension Vector Neural Network Instructions + HasAVXVNNIInt8 bool // Advanced vector extension Vector Neural Network Int8 instructions _ CacheLinePad } @@ -201,6 +204,25 @@ var S390X struct { _ CacheLinePad } +// RISCV64 contains the supported CPU features and performance characteristics for riscv64 +// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate +// the presence of RISC-V extensions. +// +// It is safe to assume that all the RV64G extensions are supported and so they are omitted from +// this structure. As riscv64 Go programs require at least RV64G, the code that populates +// this structure cannot run successfully if some of the RV64G extensions are missing. +// The struct is padded to avoid false sharing. +var RISCV64 struct { + _ CacheLinePad + HasFastMisaligned bool // Fast misaligned accesses + HasC bool // Compressed instruction-set extension + HasV bool // Vector extension compatible with RVV 1.0 + HasZba bool // Address generation instructions extension + HasZbb bool // Basic bit-manipulation extension + HasZbs bool // Single-bit instructions extension + _ CacheLinePad +} + func init() { archInit() initOptions() diff --git a/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go b/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go new file mode 100644 index 0000000000..b838cb9e95 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go @@ -0,0 +1,61 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin && amd64 && gc + +package cpu + +// darwinSupportsAVX512 checks Darwin kernel for AVX512 support via sysctl +// call (see issue 43089). It also restricts AVX512 support for Darwin to +// kernel version 21.3.0 (MacOS 12.2.0) or later (see issue 49233). +// +// Background: +// Darwin implements a special mechanism to economize on thread state when +// AVX512 specific registers are not in use. This scheme minimizes state when +// preempting threads that haven't yet used any AVX512 instructions, but adds +// special requirements to check for AVX512 hardware support at runtime (e.g. +// via sysctl call or commpage inspection). See issue 43089 and link below for +// full background: +// https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.1.10/osfmk/i386/fpu.c#L214-L240 +// +// Additionally, all versions of the Darwin kernel from 19.6.0 through 21.2.0 +// (corresponding to MacOS 10.15.6 - 12.1) have a bug that can cause corruption +// of the AVX512 mask registers (K0-K7) upon signal return. For this reason +// AVX512 is considered unsafe to use on Darwin for kernel versions prior to +// 21.3.0, where a fix has been confirmed. See issue 49233 for full background. +func darwinSupportsAVX512() bool { + return darwinSysctlEnabled([]byte("hw.optional.avx512f\x00")) && darwinKernelVersionCheck(21, 3, 0) +} + +// Ensure Darwin kernel version is at least major.minor.patch, avoiding dependencies +func darwinKernelVersionCheck(major, minor, patch int) bool { + var release [256]byte + err := darwinOSRelease(&release) + if err != nil { + return false + } + + var mmp [3]int + c := 0 +Loop: + for _, b := range release[:] { + switch { + case b >= '0' && b <= '9': + mmp[c] = 10*mmp[c] + int(b-'0') + case b == '.': + c++ + if c > 2 { + return false + } + case b == 0: + break Loop + default: + return false + } + } + if c != 2 { + return false + } + return mmp[0] > major || mmp[0] == major && (mmp[1] > minor || mmp[1] == minor && mmp[2] >= patch) +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go index 910728fb16..32a44514e2 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -6,10 +6,10 @@ package cpu -// cpuid is implemented in cpu_x86.s for gc compiler +// cpuid is implemented in cpu_gc_x86.s for gc compiler // and in cpu_gccgo.c for gccgo. func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) -// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// xgetbv with ecx = 0 is implemented in cpu_gc_x86.s for gc compiler // and in cpu_gccgo.c for gccgo. func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.s b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s similarity index 94% rename from vendor/golang.org/x/sys/cpu/cpu_x86.s rename to vendor/golang.org/x/sys/cpu/cpu_gc_x86.s index 7d7ba33efb..ce208ce6d6 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_x86.s +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.s @@ -18,7 +18,7 @@ TEXT ·cpuid(SB), NOSPLIT, $0-24 RET // func xgetbv() (eax, edx uint32) -TEXT ·xgetbv(SB),NOSPLIT,$0-8 +TEXT ·xgetbv(SB), NOSPLIT, $0-8 MOVL $0, CX XGETBV MOVL AX, eax+0(FP) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go index 99c60fe9f9..170d21ddfd 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go @@ -23,9 +23,3 @@ func xgetbv() (eax, edx uint32) { gccgoXgetbv(&a, &d) return a, d } - -// gccgo doesn't build on Darwin, per: -// https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76 -func darwinSupportsAVX512() bool { - return false -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go index 08f35ea177..f1caf0f78e 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -110,7 +110,6 @@ func doinit() { ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) ARM64.HasDIT = isSet(hwCap, hwcap_DIT) - // HWCAP2 feature bits ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2) ARM64.HasI8MM = isSet(hwCap2, hwcap2_I8MM) diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go index cd63e73355..7d902b6847 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x +//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 package cpu diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go new file mode 100644 index 0000000000..cb4a0c5728 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go @@ -0,0 +1,137 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "syscall" + "unsafe" +) + +// RISC-V extension discovery code for Linux. The approach here is to first try the riscv_hwprobe +// syscall falling back to HWCAP to check for the C extension if riscv_hwprobe is not available. +// +// A note on detection of the Vector extension using HWCAP. +// +// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5. +// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe +// syscall is not available then neither is the Vector extension (which needs kernel support). +// The riscv_hwprobe syscall should then be all we need to detect the Vector extension. +// However, some RISC-V board manufacturers ship boards with an older kernel on top of which +// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe +// patches. These kernels advertise support for the Vector extension using HWCAP. Falling +// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not +// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option. +// +// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by +// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board +// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified +// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use +// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector +// extension are binary incompatible. HWCAP can then not be used in isolation to populate the +// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0. +// +// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector +// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype +// register. This check would allow us to safely detect version 1.0 of the Vector extension +// with HWCAP, if riscv_hwprobe were not available. However, the check cannot +// be added until the assembler supports the Vector instructions. +// +// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the +// extensions it advertises support for are explicitly versioned. It's also worth noting that +// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zba. +// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority +// of RISC-V extensions. +// +// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information. + +// golang.org/x/sys/cpu is not allowed to depend on golang.org/x/sys/unix so we must +// reproduce the constants, types and functions needed to make the riscv_hwprobe syscall +// here. + +const ( + // Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. + riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4 + riscv_HWPROBE_IMA_C = 0x2 + riscv_HWPROBE_IMA_V = 0x4 + riscv_HWPROBE_EXT_ZBA = 0x8 + riscv_HWPROBE_EXT_ZBB = 0x10 + riscv_HWPROBE_EXT_ZBS = 0x20 + riscv_HWPROBE_KEY_CPUPERF_0 = 0x5 + riscv_HWPROBE_MISALIGNED_FAST = 0x3 + riscv_HWPROBE_MISALIGNED_MASK = 0x7 +) + +const ( + // sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go. + sys_RISCV_HWPROBE = 258 +) + +// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. +type riscvHWProbePairs struct { + key int64 + value uint64 +} + +const ( + // CPU features + hwcap_RISCV_ISA_C = 1 << ('C' - 'A') +) + +func doinit() { + // A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key + // field should be initialised with one of the key constants defined above, e.g., + // RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value. + // If the kernel does not recognise a key it will set the key field to -1 and the value field to 0. + + pairs := []riscvHWProbePairs{ + {riscv_HWPROBE_KEY_IMA_EXT_0, 0}, + {riscv_HWPROBE_KEY_CPUPERF_0, 0}, + } + + // This call only indicates that extensions are supported if they are implemented on all cores. + if riscvHWProbe(pairs, 0) { + if pairs[0].key != -1 { + v := uint(pairs[0].value) + RISCV64.HasC = isSet(v, riscv_HWPROBE_IMA_C) + RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V) + RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA) + RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB) + RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS) + } + if pairs[1].key != -1 { + v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK + RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST + } + } + + // Let's double check with HWCAP if the C extension does not appear to be supported. + // This may happen if we're running on a kernel older than 6.4. + + if !RISCV64.HasC { + RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C) + } +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} + +// riscvHWProbe is a simplified version of the generated wrapper function found in +// golang.org/x/sys/unix/zsyscall_linux_riscv64.go. We simplify it by removing the +// cpuCount and cpus parameters which we do not need. We always want to pass 0 for +// these parameters here so the kernel only reports the extensions that are present +// on all cores. +func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool { + var _zero uintptr + var p0 unsafe.Pointer + if len(pairs) > 0 { + p0 = unsafe.Pointer(&pairs[0]) + } else { + p0 = unsafe.Pointer(&_zero) + } + + _, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(p0), uintptr(len(pairs)), uintptr(0), uintptr(0), uintptr(flags), 0) + return e1 == 0 +} diff --git a/vendor/golang.org/x/tools/internal/versions/constraint_go121.go b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go similarity index 50% rename from vendor/golang.org/x/tools/internal/versions/constraint_go121.go rename to vendor/golang.org/x/sys/cpu/cpu_other_x86.go index 38011407d5..a0fd7e2f75 100644 --- a/vendor/golang.org/x/tools/internal/versions/constraint_go121.go +++ b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go @@ -2,13 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.21 -// +build go1.21 +//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc)) -package versions +package cpu -import "go/build/constraint" - -func init() { - ConstraintGoVersion = constraint.GoVersion +func darwinSupportsAVX512() bool { + panic("only implemented for gc && amd64 && darwin") } diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go index 7f0c79c004..aca3199c91 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go +++ b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go @@ -8,4 +8,13 @@ package cpu const cacheLineSize = 64 -func initOptions() {} +func initOptions() { + options = []option{ + {Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned}, + {Name: "c", Feature: &RISCV64.HasC}, + {Name: "v", Feature: &RISCV64.HasV}, + {Name: "zba", Feature: &RISCV64.HasZba}, + {Name: "zbb", Feature: &RISCV64.HasZbb}, + {Name: "zbs", Feature: &RISCV64.HasZbs}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go index c29f5e4c5a..1e642f3304 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_x86.go +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -53,6 +53,9 @@ func initOptions() { {Name: "sse41", Feature: &X86.HasSSE41}, {Name: "sse42", Feature: &X86.HasSSE42}, {Name: "ssse3", Feature: &X86.HasSSSE3}, + {Name: "avxifma", Feature: &X86.HasAVXIFMA}, + {Name: "avxvnni", Feature: &X86.HasAVXVNNI}, + {Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8}, // These capabilities should always be enabled on amd64: {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, @@ -92,10 +95,8 @@ func archInit() { osSupportsAVX = isSet(1, eax) && isSet(2, eax) if runtime.GOOS == "darwin" { - // Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers. - // Since users can't rely on mask register contents, let's not advertise AVX-512 support. - // See issue 49233. - osSupportsAVX512 = false + // Darwin requires special AVX512 checks, see cpu_darwin_x86.go + osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() } else { // Check if OPMASK and ZMM registers have OS support. osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) @@ -108,7 +109,7 @@ func archInit() { return } - _, ebx7, ecx7, edx7 := cpuid(7, 0) + eax7, ebx7, ecx7, edx7 := cpuid(7, 0) X86.HasBMI1 = isSet(3, ebx7) X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX X86.HasBMI2 = isSet(8, ebx7) @@ -136,14 +137,24 @@ func archInit() { X86.HasAVX512VAES = isSet(9, ecx7) X86.HasAVX512VBMI2 = isSet(6, ecx7) X86.HasAVX512BITALG = isSet(12, ecx7) - - eax71, _, _, _ := cpuid(7, 1) - X86.HasAVX512BF16 = isSet(5, eax71) } X86.HasAMXTile = isSet(24, edx7) X86.HasAMXInt8 = isSet(25, edx7) X86.HasAMXBF16 = isSet(22, edx7) + + // These features depend on the second level of extended features. + if eax7 >= 1 { + eax71, _, _, edx71 := cpuid(7, 1) + if X86.HasAVX512 { + X86.HasAVX512BF16 = isSet(5, eax71) + } + if X86.HasAVX { + X86.HasAVXIFMA = isSet(23, eax71) + X86.HasAVXVNNI = isSet(4, eax71) + X86.HasAVXVNNIInt8 = isSet(4, edx71) + } + } } func isSet(bitpos uint, value uint32) bool { diff --git a/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go b/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go new file mode 100644 index 0000000000..4d0888b0c0 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go @@ -0,0 +1,98 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Minimal copy of x/sys/unix so the cpu package can make a +// system call on Darwin without depending on x/sys/unix. + +//go:build darwin && amd64 && gc + +package cpu + +import ( + "syscall" + "unsafe" +) + +type _C_int int32 + +// adapted from unix.Uname() at x/sys/unix/syscall_darwin.go L419 +func darwinOSRelease(release *[256]byte) error { + // from x/sys/unix/zerrors_openbsd_amd64.go + const ( + CTL_KERN = 0x1 + KERN_OSRELEASE = 0x2 + ) + + mib := []_C_int{CTL_KERN, KERN_OSRELEASE} + n := unsafe.Sizeof(*release) + + return sysctl(mib, &release[0], &n, nil, 0) +} + +type Errno = syscall.Errno + +var _zero uintptr // Single-word zero for use when we need a valid pointer to 0 bytes. + +// from x/sys/unix/zsyscall_darwin_amd64.go L791-807 +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + if _, _, err := syscall_syscall6( + libc_sysctl_trampoline_addr, + uintptr(_p0), + uintptr(len(mib)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen), + ); err != 0 { + return err + } + + return nil +} + +var libc_sysctl_trampoline_addr uintptr + +// adapted from internal/cpu/cpu_arm64_darwin.go +func darwinSysctlEnabled(name []byte) bool { + out := int32(0) + nout := unsafe.Sizeof(out) + if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil { + return false + } + return out > 0 +} + +//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" + +var libc_sysctlbyname_trampoline_addr uintptr + +// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix +func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + if _, _, err := syscall_syscall6( + libc_sysctlbyname_trampoline_addr, + uintptr(unsafe.Pointer(name)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen), + 0, + ); err != 0 { + return err + } + + return nil +} + +//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib" + +// Implemented in the runtime package (runtime/sys_darwin.go) +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) + +//go:linkname syscall_syscall6 syscall.syscall6 diff --git a/vendor/golang.org/x/sys/plan9/asm.s b/vendor/golang.org/x/sys/plan9/asm.s deleted file mode 100644 index 06449ebfa9..0000000000 --- a/vendor/golang.org/x/sys/plan9/asm.s +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -TEXT ·use(SB),NOSPLIT,$0 - RET diff --git a/vendor/golang.org/x/sys/plan9/asm_plan9_386.s b/vendor/golang.org/x/sys/plan9/asm_plan9_386.s deleted file mode 100644 index bc5cab1f34..0000000000 --- a/vendor/golang.org/x/sys/plan9/asm_plan9_386.s +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -// -// System call support for 386, Plan 9 -// - -// Just jump to package syscall's implementation for all these functions. -// The runtime may know about them. - -TEXT ·Syscall(SB),NOSPLIT,$0-32 - JMP syscall·Syscall(SB) - -TEXT ·Syscall6(SB),NOSPLIT,$0-44 - JMP syscall·Syscall6(SB) - -TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - JMP syscall·RawSyscall(SB) - -TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - JMP syscall·RawSyscall6(SB) - -TEXT ·seek(SB),NOSPLIT,$0-36 - JMP syscall·seek(SB) - -TEXT ·exit(SB),NOSPLIT,$4-4 - JMP syscall·exit(SB) diff --git a/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s b/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s deleted file mode 100644 index d3448e6750..0000000000 --- a/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -// -// System call support for amd64, Plan 9 -// - -// Just jump to package syscall's implementation for all these functions. -// The runtime may know about them. - -TEXT ·Syscall(SB),NOSPLIT,$0-64 - JMP syscall·Syscall(SB) - -TEXT ·Syscall6(SB),NOSPLIT,$0-88 - JMP syscall·Syscall6(SB) - -TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - JMP syscall·RawSyscall(SB) - -TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - JMP syscall·RawSyscall6(SB) - -TEXT ·seek(SB),NOSPLIT,$0-56 - JMP syscall·seek(SB) - -TEXT ·exit(SB),NOSPLIT,$8-8 - JMP syscall·exit(SB) diff --git a/vendor/golang.org/x/sys/plan9/asm_plan9_arm.s b/vendor/golang.org/x/sys/plan9/asm_plan9_arm.s deleted file mode 100644 index afb7c0a9b9..0000000000 --- a/vendor/golang.org/x/sys/plan9/asm_plan9_arm.s +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -// System call support for plan9 on arm - -// Just jump to package syscall's implementation for all these functions. -// The runtime may know about them. - -TEXT ·Syscall(SB),NOSPLIT,$0-32 - JMP syscall·Syscall(SB) - -TEXT ·Syscall6(SB),NOSPLIT,$0-44 - JMP syscall·Syscall6(SB) - -TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - JMP syscall·RawSyscall(SB) - -TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - JMP syscall·RawSyscall6(SB) - -TEXT ·seek(SB),NOSPLIT,$0-36 - JMP syscall·exit(SB) diff --git a/vendor/golang.org/x/sys/plan9/const_plan9.go b/vendor/golang.org/x/sys/plan9/const_plan9.go deleted file mode 100644 index b4e85a3a9d..0000000000 --- a/vendor/golang.org/x/sys/plan9/const_plan9.go +++ /dev/null @@ -1,70 +0,0 @@ -package plan9 - -// Plan 9 Constants - -// Open modes -const ( - O_RDONLY = 0 - O_WRONLY = 1 - O_RDWR = 2 - O_TRUNC = 16 - O_CLOEXEC = 32 - O_EXCL = 0x1000 -) - -// Rfork flags -const ( - RFNAMEG = 1 << 0 - RFENVG = 1 << 1 - RFFDG = 1 << 2 - RFNOTEG = 1 << 3 - RFPROC = 1 << 4 - RFMEM = 1 << 5 - RFNOWAIT = 1 << 6 - RFCNAMEG = 1 << 10 - RFCENVG = 1 << 11 - RFCFDG = 1 << 12 - RFREND = 1 << 13 - RFNOMNT = 1 << 14 -) - -// Qid.Type bits -const ( - QTDIR = 0x80 - QTAPPEND = 0x40 - QTEXCL = 0x20 - QTMOUNT = 0x10 - QTAUTH = 0x08 - QTTMP = 0x04 - QTFILE = 0x00 -) - -// Dir.Mode bits -const ( - DMDIR = 0x80000000 - DMAPPEND = 0x40000000 - DMEXCL = 0x20000000 - DMMOUNT = 0x10000000 - DMAUTH = 0x08000000 - DMTMP = 0x04000000 - DMREAD = 0x4 - DMWRITE = 0x2 - DMEXEC = 0x1 -) - -const ( - STATMAX = 65535 - ERRMAX = 128 - STATFIXLEN = 49 -) - -// Mount and bind flags -const ( - MREPL = 0x0000 - MBEFORE = 0x0001 - MAFTER = 0x0002 - MORDER = 0x0003 - MCREATE = 0x0004 - MCACHE = 0x0010 - MMASK = 0x0017 -) diff --git a/vendor/golang.org/x/sys/plan9/dir_plan9.go b/vendor/golang.org/x/sys/plan9/dir_plan9.go deleted file mode 100644 index 0955e0c53e..0000000000 --- a/vendor/golang.org/x/sys/plan9/dir_plan9.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Plan 9 directory marshalling. See intro(5). - -package plan9 - -import "errors" - -var ( - ErrShortStat = errors.New("stat buffer too short") - ErrBadStat = errors.New("malformed stat buffer") - ErrBadName = errors.New("bad character in file name") -) - -// A Qid represents a 9P server's unique identification for a file. -type Qid struct { - Path uint64 // the file server's unique identification for the file - Vers uint32 // version number for given Path - Type uint8 // the type of the file (plan9.QTDIR for example) -} - -// A Dir contains the metadata for a file. -type Dir struct { - // system-modified data - Type uint16 // server type - Dev uint32 // server subtype - - // file data - Qid Qid // unique id from server - Mode uint32 // permissions - Atime uint32 // last read time - Mtime uint32 // last write time - Length int64 // file length - Name string // last element of path - Uid string // owner name - Gid string // group name - Muid string // last modifier name -} - -var nullDir = Dir{ - Type: ^uint16(0), - Dev: ^uint32(0), - Qid: Qid{ - Path: ^uint64(0), - Vers: ^uint32(0), - Type: ^uint8(0), - }, - Mode: ^uint32(0), - Atime: ^uint32(0), - Mtime: ^uint32(0), - Length: ^int64(0), -} - -// Null assigns special "don't touch" values to members of d to -// avoid modifying them during plan9.Wstat. -func (d *Dir) Null() { *d = nullDir } - -// Marshal encodes a 9P stat message corresponding to d into b -// -// If there isn't enough space in b for a stat message, ErrShortStat is returned. -func (d *Dir) Marshal(b []byte) (n int, err error) { - n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid) - if n > len(b) { - return n, ErrShortStat - } - - for _, c := range d.Name { - if c == '/' { - return n, ErrBadName - } - } - - b = pbit16(b, uint16(n)-2) - b = pbit16(b, d.Type) - b = pbit32(b, d.Dev) - b = pbit8(b, d.Qid.Type) - b = pbit32(b, d.Qid.Vers) - b = pbit64(b, d.Qid.Path) - b = pbit32(b, d.Mode) - b = pbit32(b, d.Atime) - b = pbit32(b, d.Mtime) - b = pbit64(b, uint64(d.Length)) - b = pstring(b, d.Name) - b = pstring(b, d.Uid) - b = pstring(b, d.Gid) - b = pstring(b, d.Muid) - - return n, nil -} - -// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir. -// -// If b is too small to hold a valid stat message, ErrShortStat is returned. -// -// If the stat message itself is invalid, ErrBadStat is returned. -func UnmarshalDir(b []byte) (*Dir, error) { - if len(b) < STATFIXLEN { - return nil, ErrShortStat - } - size, buf := gbit16(b) - if len(b) != int(size)+2 { - return nil, ErrBadStat - } - b = buf - - var d Dir - d.Type, b = gbit16(b) - d.Dev, b = gbit32(b) - d.Qid.Type, b = gbit8(b) - d.Qid.Vers, b = gbit32(b) - d.Qid.Path, b = gbit64(b) - d.Mode, b = gbit32(b) - d.Atime, b = gbit32(b) - d.Mtime, b = gbit32(b) - - n, b := gbit64(b) - d.Length = int64(n) - - var ok bool - if d.Name, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - if d.Uid, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - if d.Gid, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - if d.Muid, b, ok = gstring(b); !ok { - return nil, ErrBadStat - } - - return &d, nil -} - -// pbit8 copies the 8-bit number v to b and returns the remaining slice of b. -func pbit8(b []byte, v uint8) []byte { - b[0] = byte(v) - return b[1:] -} - -// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b. -func pbit16(b []byte, v uint16) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - return b[2:] -} - -// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b. -func pbit32(b []byte, v uint32) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - return b[4:] -} - -// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b. -func pbit64(b []byte, v uint64) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) - return b[8:] -} - -// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and -// returning the remaining slice of b.. -func pstring(b []byte, s string) []byte { - b = pbit16(b, uint16(len(s))) - n := copy(b, s) - return b[n:] -} - -// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b. -func gbit8(b []byte) (uint8, []byte) { - return uint8(b[0]), b[1:] -} - -// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b. -func gbit16(b []byte) (uint16, []byte) { - return uint16(b[0]) | uint16(b[1])<<8, b[2:] -} - -// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b. -func gbit32(b []byte) (uint32, []byte) { - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] -} - -// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b. -func gbit64(b []byte) (uint64, []byte) { - lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24 - return uint64(lo) | uint64(hi)<<32, b[8:] -} - -// gstring reads a string from b, prefixed with a 16-bit length in little-endian order. -// It returns the string with the remaining slice of b and a boolean. If the length is -// greater than the number of bytes in b, the boolean will be false. -func gstring(b []byte) (string, []byte, bool) { - n, b := gbit16(b) - if int(n) > len(b) { - return "", b, false - } - return string(b[:n]), b[n:], true -} diff --git a/vendor/golang.org/x/sys/plan9/env_plan9.go b/vendor/golang.org/x/sys/plan9/env_plan9.go deleted file mode 100644 index 8f1918004f..0000000000 --- a/vendor/golang.org/x/sys/plan9/env_plan9.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Plan 9 environment variables. - -package plan9 - -import ( - "syscall" -) - -func Getenv(key string) (value string, found bool) { - return syscall.Getenv(key) -} - -func Setenv(key, value string) error { - return syscall.Setenv(key, value) -} - -func Clearenv() { - syscall.Clearenv() -} - -func Environ() []string { - return syscall.Environ() -} - -func Unsetenv(key string) error { - return syscall.Unsetenv(key) -} diff --git a/vendor/golang.org/x/sys/plan9/errors_plan9.go b/vendor/golang.org/x/sys/plan9/errors_plan9.go deleted file mode 100644 index 65fe74d3ef..0000000000 --- a/vendor/golang.org/x/sys/plan9/errors_plan9.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package plan9 - -import "syscall" - -// Constants -const ( - // Invented values to support what package os expects. - O_CREAT = 0x02000 - O_APPEND = 0x00400 - O_NOCTTY = 0x00000 - O_NONBLOCK = 0x00000 - O_SYNC = 0x00000 - O_ASYNC = 0x00000 - - S_IFMT = 0x1f000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 -) - -// Errors -var ( - EINVAL = syscall.NewError("bad arg in system call") - ENOTDIR = syscall.NewError("not a directory") - EISDIR = syscall.NewError("file is a directory") - ENOENT = syscall.NewError("file does not exist") - EEXIST = syscall.NewError("file already exists") - EMFILE = syscall.NewError("no free file descriptors") - EIO = syscall.NewError("i/o error") - ENAMETOOLONG = syscall.NewError("file name too long") - EINTR = syscall.NewError("interrupted") - EPERM = syscall.NewError("permission denied") - EBUSY = syscall.NewError("no free devices") - ETIMEDOUT = syscall.NewError("connection timed out") - EPLAN9 = syscall.NewError("not supported by plan 9") - - // The following errors do not correspond to any - // Plan 9 system messages. Invented to support - // what package os and others expect. - EACCES = syscall.NewError("access permission denied") - EAFNOSUPPORT = syscall.NewError("address family not supported by protocol") -) diff --git a/vendor/golang.org/x/sys/plan9/mkall.sh b/vendor/golang.org/x/sys/plan9/mkall.sh deleted file mode 100644 index 1650fbcc74..0000000000 --- a/vendor/golang.org/x/sys/plan9/mkall.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# The plan9 package provides access to the raw system call -# interface of the underlying operating system. Porting Go to -# a new architecture/operating system combination requires -# some manual effort, though there are tools that automate -# much of the process. The auto-generated files have names -# beginning with z. -# -# This script runs or (given -n) prints suggested commands to generate z files -# for the current system. Running those commands is not automatic. -# This script is documentation more than anything else. -# -# * asm_${GOOS}_${GOARCH}.s -# -# This hand-written assembly file implements system call dispatch. -# There are three entry points: -# -# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr); -# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); -# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr); -# -# The first and second are the standard ones; they differ only in -# how many arguments can be passed to the kernel. -# The third is for low-level use by the ForkExec wrapper; -# unlike the first two, it does not call into the scheduler to -# let it know that a system call is running. -# -# * syscall_${GOOS}.go -# -# This hand-written Go file implements system calls that need -# special handling and lists "//sys" comments giving prototypes -# for ones that can be auto-generated. Mksyscall reads those -# comments to generate the stubs. -# -# * syscall_${GOOS}_${GOARCH}.go -# -# Same as syscall_${GOOS}.go except that it contains code specific -# to ${GOOS} on one particular architecture. -# -# * types_${GOOS}.c -# -# This hand-written C file includes standard C headers and then -# creates typedef or enum names beginning with a dollar sign -# (use of $ in variable names is a gcc extension). The hardest -# part about preparing this file is figuring out which headers to -# include and which symbols need to be #defined to get the -# actual data structures that pass through to the kernel system calls. -# Some C libraries present alternate versions for binary compatibility -# and translate them on the way in and out of system calls, but -# there is almost always a #define that can get the real ones. -# See types_darwin.c and types_linux.c for examples. -# -# * zerror_${GOOS}_${GOARCH}.go -# -# This machine-generated file defines the system's error numbers, -# error strings, and signal numbers. The generator is "mkerrors.sh". -# Usually no arguments are needed, but mkerrors.sh will pass its -# arguments on to godefs. -# -# * zsyscall_${GOOS}_${GOARCH}.go -# -# Generated by mksyscall.pl; see syscall_${GOOS}.go above. -# -# * zsysnum_${GOOS}_${GOARCH}.go -# -# Generated by mksysnum_${GOOS}. -# -# * ztypes_${GOOS}_${GOARCH}.go -# -# Generated by godefs; see types_${GOOS}.c above. - -GOOSARCH="${GOOS}_${GOARCH}" - -# defaults -mksyscall="go run mksyscall.go" -mkerrors="./mkerrors.sh" -zerrors="zerrors_$GOOSARCH.go" -mksysctl="" -zsysctl="zsysctl_$GOOSARCH.go" -mksysnum= -mktypes= -run="sh" - -case "$1" in --syscalls) - for i in zsyscall*go - do - sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i - rm _$i - done - exit 0 - ;; --n) - run="cat" - shift -esac - -case "$#" in -0) - ;; -*) - echo 'usage: mkall.sh [-n]' 1>&2 - exit 2 -esac - -case "$GOOSARCH" in -_* | *_ | _) - echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 - exit 1 - ;; -plan9_386) - mkerrors= - mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,386" - mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" - mktypes="XXX" - ;; -plan9_amd64) - mkerrors= - mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,amd64" - mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" - mktypes="XXX" - ;; -plan9_arm) - mkerrors= - mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,arm" - mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" - mktypes="XXX" - ;; -*) - echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 - exit 1 - ;; -esac - -( - if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi - case "$GOOS" in - plan9) - syscall_goos="syscall_$GOOS.go" - if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos |gofmt >zsyscall_$GOOSARCH.go"; fi - ;; - esac - if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi - if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi - if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi -) | $run diff --git a/vendor/golang.org/x/sys/plan9/mkerrors.sh b/vendor/golang.org/x/sys/plan9/mkerrors.sh deleted file mode 100644 index 526d04ab68..0000000000 --- a/vendor/golang.org/x/sys/plan9/mkerrors.sh +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# Generate Go code listing errors and other #defined constant -# values (ENAMETOOLONG etc.), by asking the preprocessor -# about the definitions. - -unset LANG -export LC_ALL=C -export LC_CTYPE=C - -CC=${CC:-gcc} - -uname=$(uname) - -includes=' -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -' - -ccflags="$@" - -# Write go tool cgo -godefs input. -( - echo package plan9 - echo - echo '/*' - indirect="includes_$(uname)" - echo "${!indirect} $includes" - echo '*/' - echo 'import "C"' - echo - echo 'const (' - - # The gcc command line prints all the #defines - # it encounters while processing the input - echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags | - awk ' - $1 != "#define" || $2 ~ /\(/ || $3 == "" {next} - - $2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers - $2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next} - $2 ~ /^(SCM_SRCRT)$/ {next} - $2 ~ /^(MAP_FAILED)$/ {next} - - $2 !~ /^ETH_/ && - $2 !~ /^EPROC_/ && - $2 !~ /^EQUIV_/ && - $2 !~ /^EXPR_/ && - $2 ~ /^E[A-Z0-9_]+$/ || - $2 ~ /^B[0-9_]+$/ || - $2 ~ /^V[A-Z0-9]+$/ || - $2 ~ /^CS[A-Z0-9]/ || - $2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ || - $2 ~ /^IGN/ || - $2 ~ /^IX(ON|ANY|OFF)$/ || - $2 ~ /^IN(LCR|PCK)$/ || - $2 ~ /(^FLU?SH)|(FLU?SH$)/ || - $2 ~ /^C(LOCAL|READ)$/ || - $2 == "BRKINT" || - $2 == "HUPCL" || - $2 == "PENDIN" || - $2 == "TOSTOP" || - $2 ~ /^PAR/ || - $2 ~ /^SIG[^_]/ || - $2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ || - $2 ~ /^IN_/ || - $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || - $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ || - $2 == "ICMPV6_FILTER" || - $2 == "SOMAXCONN" || - $2 == "NAME_MAX" || - $2 == "IFNAMSIZ" || - $2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ || - $2 ~ /^SYSCTL_VERS/ || - $2 ~ /^(MS|MNT)_/ || - $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || - $2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ || - $2 ~ /^LINUX_REBOOT_CMD_/ || - $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || - $2 !~ "NLA_TYPE_MASK" && - $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || - $2 ~ /^SIOC/ || - $2 ~ /^TIOC/ || - $2 !~ "RTF_BITS" && - $2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ || - $2 ~ /^BIOC/ || - $2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ || - $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ || - $2 ~ /^PRIO_(PROCESS|PGRP|USER)/ || - $2 ~ /^CLONE_[A-Z_]+/ || - $2 !~ /^(BPF_TIMEVAL)$/ && - $2 ~ /^(BPF|DLT)_/ || - $2 !~ "WMESGLEN" && - $2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)} - $2 ~ /^__WCOREFLAG$/ {next} - $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} - - {next} - ' | sort - - echo ')' -) >_const.go - -# Pull out the error names for later. -errors=$( - echo '#include ' | $CC -x c - -E -dM $ccflags | - awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' | - sort -) - -# Pull out the signal names for later. -signals=$( - echo '#include ' | $CC -x c - -E -dM $ccflags | - awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | - grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' | - sort -) - -# Again, writing regexps to a file. -echo '#include ' | $CC -x c - -E -dM $ccflags | - awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' | - sort >_error.grep -echo '#include ' | $CC -x c - -E -dM $ccflags | - awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | - grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' | - sort >_signal.grep - -echo '// mkerrors.sh' "$@" -echo '// Code generated by the command above; DO NOT EDIT.' -echo -go tool cgo -godefs -- "$@" _const.go >_error.out -cat _error.out | grep -vf _error.grep | grep -vf _signal.grep -echo -echo '// Errors' -echo 'const (' -cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/' -echo ')' - -echo -echo '// Signals' -echo 'const (' -cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/' -echo ')' - -# Run C program to print error and syscall strings. -( - echo -E " -#include -#include -#include -#include -#include -#include - -#define nelem(x) (sizeof(x)/sizeof((x)[0])) - -enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below - -int errors[] = { -" - for i in $errors - do - echo -E ' '$i, - done - - echo -E " -}; - -int signals[] = { -" - for i in $signals - do - echo -E ' '$i, - done - - # Use -E because on some systems bash builtin interprets \n itself. - echo -E ' -}; - -static int -intcmp(const void *a, const void *b) -{ - return *(int*)a - *(int*)b; -} - -int -main(void) -{ - int i, j, e; - char buf[1024], *p; - - printf("\n\n// Error table\n"); - printf("var errors = [...]string {\n"); - qsort(errors, nelem(errors), sizeof errors[0], intcmp); - for(i=0; i 0 && errors[i-1] == e) - continue; - strcpy(buf, strerror(e)); - // lowercase first letter: Bad -> bad, but STREAM -> STREAM. - if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) - buf[0] += a - A; - printf("\t%d: \"%s\",\n", e, buf); - } - printf("}\n\n"); - - printf("\n\n// Signal table\n"); - printf("var signals = [...]string {\n"); - qsort(signals, nelem(signals), sizeof signals[0], intcmp); - for(i=0; i 0 && signals[i-1] == e) - continue; - strcpy(buf, strsignal(e)); - // lowercase first letter: Bad -> bad, but STREAM -> STREAM. - if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) - buf[0] += a - A; - // cut trailing : number. - p = strrchr(buf, ":"[0]); - if(p) - *p = '\0'; - printf("\t%d: \"%s\",\n", e, buf); - } - printf("}\n\n"); - - return 0; -} - -' -) >_errors.c - -$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out diff --git a/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh b/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh deleted file mode 100644 index 3c3ab05810..0000000000 --- a/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -COMMAND="mksysnum_plan9.sh $@" - -cat <= 10 { - buf[i] = byte(val%10 + '0') - i-- - val /= 10 - } - buf[i] = byte(val + '0') - return string(buf[i:]) -} diff --git a/vendor/golang.org/x/sys/plan9/syscall.go b/vendor/golang.org/x/sys/plan9/syscall.go deleted file mode 100644 index d631fd664a..0000000000 --- a/vendor/golang.org/x/sys/plan9/syscall.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build plan9 - -// Package plan9 contains an interface to the low-level operating system -// primitives. OS details vary depending on the underlying system, and -// by default, godoc will display the OS-specific documentation for the current -// system. If you want godoc to display documentation for another -// system, set $GOOS and $GOARCH to the desired system. For example, if -// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS -// to freebsd and $GOARCH to arm. -// -// The primary use of this package is inside other packages that provide a more -// portable interface to the system, such as "os", "time" and "net". Use -// those packages rather than this one if you can. -// -// For details of the functions and data types in this package consult -// the manuals for the appropriate operating system. -// -// These calls return err == nil to indicate success; otherwise -// err represents an operating system error describing the failure and -// holds a value of type syscall.ErrorString. -package plan9 // import "golang.org/x/sys/plan9" - -import ( - "bytes" - "strings" - "unsafe" -) - -// ByteSliceFromString returns a NUL-terminated slice of bytes -// containing the text of s. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). -func ByteSliceFromString(s string) ([]byte, error) { - if strings.IndexByte(s, 0) != -1 { - return nil, EINVAL - } - a := make([]byte, len(s)+1) - copy(a, s) - return a, nil -} - -// BytePtrFromString returns a pointer to a NUL-terminated array of -// bytes containing the text of s. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). -func BytePtrFromString(s string) (*byte, error) { - a, err := ByteSliceFromString(s) - if err != nil { - return nil, err - } - return &a[0], nil -} - -// ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any -// bytes after the NUL removed. -func ByteSliceToString(s []byte) string { - if i := bytes.IndexByte(s, 0); i != -1 { - s = s[:i] - } - return string(s) -} - -// BytePtrToString takes a pointer to a sequence of text and returns the corresponding string. -// If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated -// at a zero byte; if the zero byte is not present, the program may crash. -func BytePtrToString(p *byte) string { - if p == nil { - return "" - } - if *p == 0 { - return "" - } - - // Find NUL terminator. - n := 0 - for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ { - ptr = unsafe.Pointer(uintptr(ptr) + 1) - } - - return string(unsafe.Slice(p, n)) -} - -// Single-word zero for use when we need a valid pointer to 0 bytes. -// See mksyscall.pl. -var _zero uintptr - -func (ts *Timespec) Unix() (sec int64, nsec int64) { - return int64(ts.Sec), int64(ts.Nsec) -} - -func (tv *Timeval) Unix() (sec int64, nsec int64) { - return int64(tv.Sec), int64(tv.Usec) * 1000 -} - -func (ts *Timespec) Nano() int64 { - return int64(ts.Sec)*1e9 + int64(ts.Nsec) -} - -func (tv *Timeval) Nano() int64 { - return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 -} - -// use is a no-op, but the compiler cannot see that it is. -// Calling use(p) ensures that p is kept live until that point. -// -//go:noescape -func use(p unsafe.Pointer) diff --git a/vendor/golang.org/x/sys/plan9/syscall_plan9.go b/vendor/golang.org/x/sys/plan9/syscall_plan9.go deleted file mode 100644 index d079d8116e..0000000000 --- a/vendor/golang.org/x/sys/plan9/syscall_plan9.go +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Plan 9 system calls. -// This file is compiled as ordinary Go code, -// but it is also input to mksyscall, -// which parses the //sys lines and generates system call stubs. -// Note that sometimes we use a lowercase //sys name and -// wrap it in our own nicer implementation. - -package plan9 - -import ( - "bytes" - "syscall" - "unsafe" -) - -// A Note is a string describing a process note. -// It implements the os.Signal interface. -type Note string - -func (n Note) Signal() {} - -func (n Note) String() string { - return string(n) -} - -var ( - Stdin = 0 - Stdout = 1 - Stderr = 2 -) - -// For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. -var SocketDisableIPv6 bool - -func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.ErrorString) -func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.ErrorString) -func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) -func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) - -func atoi(b []byte) (n uint) { - n = 0 - for i := 0; i < len(b); i++ { - n = n*10 + uint(b[i]-'0') - } - return -} - -func cstring(s []byte) string { - i := bytes.IndexByte(s, 0) - if i == -1 { - i = len(s) - } - return string(s[:i]) -} - -func errstr() string { - var buf [ERRMAX]byte - - RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0) - - buf[len(buf)-1] = 0 - return cstring(buf[:]) -} - -// Implemented in assembly to import from runtime. -func exit(code int) - -func Exit(code int) { exit(code) } - -func readnum(path string) (uint, error) { - var b [12]byte - - fd, e := Open(path, O_RDONLY) - if e != nil { - return 0, e - } - defer Close(fd) - - n, e := Pread(fd, b[:], 0) - - if e != nil { - return 0, e - } - - m := 0 - for ; m < n && b[m] == ' '; m++ { - } - - return atoi(b[m : n-1]), nil -} - -func Getpid() (pid int) { - n, _ := readnum("#c/pid") - return int(n) -} - -func Getppid() (ppid int) { - n, _ := readnum("#c/ppid") - return int(n) -} - -func Read(fd int, p []byte) (n int, err error) { - return Pread(fd, p, -1) -} - -func Write(fd int, p []byte) (n int, err error) { - return Pwrite(fd, p, -1) -} - -var ioSync int64 - -//sys fd2path(fd int, buf []byte) (err error) - -func Fd2path(fd int) (path string, err error) { - var buf [512]byte - - e := fd2path(fd, buf[:]) - if e != nil { - return "", e - } - return cstring(buf[:]), nil -} - -//sys pipe(p *[2]int32) (err error) - -func Pipe(p []int) (err error) { - if len(p) != 2 { - return syscall.ErrorString("bad arg in system call") - } - var pp [2]int32 - err = pipe(&pp) - if err == nil { - p[0] = int(pp[0]) - p[1] = int(pp[1]) - } - return -} - -// Underlying system call writes to newoffset via pointer. -// Implemented in assembly to avoid allocation. -func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string) - -func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - newoffset, e := seek(0, fd, offset, whence) - - if newoffset == -1 { - err = syscall.ErrorString(e) - } - return -} - -func Mkdir(path string, mode uint32) (err error) { - fd, err := Create(path, O_RDONLY, DMDIR|mode) - - if fd != -1 { - Close(fd) - } - - return -} - -type Waitmsg struct { - Pid int - Time [3]uint32 - Msg string -} - -func (w Waitmsg) Exited() bool { return true } -func (w Waitmsg) Signaled() bool { return false } - -func (w Waitmsg) ExitStatus() int { - if len(w.Msg) == 0 { - // a normal exit returns no message - return 0 - } - return 1 -} - -//sys await(s []byte) (n int, err error) - -func Await(w *Waitmsg) (err error) { - var buf [512]byte - var f [5][]byte - - n, err := await(buf[:]) - - if err != nil || w == nil { - return - } - - nf := 0 - p := 0 - for i := 0; i < n && nf < len(f)-1; i++ { - if buf[i] == ' ' { - f[nf] = buf[p:i] - p = i + 1 - nf++ - } - } - f[nf] = buf[p:] - nf++ - - if nf != len(f) { - return syscall.ErrorString("invalid wait message") - } - w.Pid = int(atoi(f[0])) - w.Time[0] = uint32(atoi(f[1])) - w.Time[1] = uint32(atoi(f[2])) - w.Time[2] = uint32(atoi(f[3])) - w.Msg = cstring(f[4]) - if w.Msg == "''" { - // await() returns '' for no error - w.Msg = "" - } - return -} - -func Unmount(name, old string) (err error) { - fixwd() - oldp, err := BytePtrFromString(old) - if err != nil { - return err - } - oldptr := uintptr(unsafe.Pointer(oldp)) - - var r0 uintptr - var e syscall.ErrorString - - // bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted. - if name == "" { - r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0) - } else { - namep, err := BytePtrFromString(name) - if err != nil { - return err - } - r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0) - } - - if int32(r0) == -1 { - err = e - } - return -} - -func Fchdir(fd int) (err error) { - path, err := Fd2path(fd) - - if err != nil { - return - } - - return Chdir(path) -} - -type Timespec struct { - Sec int32 - Nsec int32 -} - -type Timeval struct { - Sec int32 - Usec int32 -} - -func NsecToTimeval(nsec int64) (tv Timeval) { - nsec += 999 // round up to microsecond - tv.Usec = int32(nsec % 1e9 / 1e3) - tv.Sec = int32(nsec / 1e9) - return -} - -func nsec() int64 { - var scratch int64 - - r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0) - // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. - if r0 == 0 { - return scratch - } - return int64(r0) -} - -func Gettimeofday(tv *Timeval) error { - nsec := nsec() - *tv = NsecToTimeval(nsec) - return nil -} - -func Getpagesize() int { return 0x1000 } - -func Getegid() (egid int) { return -1 } -func Geteuid() (euid int) { return -1 } -func Getgid() (gid int) { return -1 } -func Getuid() (uid int) { return -1 } - -func Getgroups() (gids []int, err error) { - return make([]int, 0), nil -} - -//sys open(path string, mode int) (fd int, err error) - -func Open(path string, mode int) (fd int, err error) { - fixwd() - return open(path, mode) -} - -//sys create(path string, mode int, perm uint32) (fd int, err error) - -func Create(path string, mode int, perm uint32) (fd int, err error) { - fixwd() - return create(path, mode, perm) -} - -//sys remove(path string) (err error) - -func Remove(path string) error { - fixwd() - return remove(path) -} - -//sys stat(path string, edir []byte) (n int, err error) - -func Stat(path string, edir []byte) (n int, err error) { - fixwd() - return stat(path, edir) -} - -//sys bind(name string, old string, flag int) (err error) - -func Bind(name string, old string, flag int) (err error) { - fixwd() - return bind(name, old, flag) -} - -//sys mount(fd int, afd int, old string, flag int, aname string) (err error) - -func Mount(fd int, afd int, old string, flag int, aname string) (err error) { - fixwd() - return mount(fd, afd, old, flag, aname) -} - -//sys wstat(path string, edir []byte) (err error) - -func Wstat(path string, edir []byte) (err error) { - fixwd() - return wstat(path, edir) -} - -//sys chdir(path string) (err error) -//sys Dup(oldfd int, newfd int) (fd int, err error) -//sys Pread(fd int, p []byte, offset int64) (n int, err error) -//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) -//sys Close(fd int) (err error) -//sys Fstat(fd int, edir []byte) (n int, err error) -//sys Fwstat(fd int, edir []byte) (err error) diff --git a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go deleted file mode 100644 index f780d5c807..0000000000 --- a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go +++ /dev/null @@ -1,284 +0,0 @@ -// go run mksyscall.go -l32 -plan9 -tags plan9,386 syscall_plan9.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build plan9 && 386 - -package plan9 - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fd2path(fd int, buf []byte) (err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pipe(p *[2]int32) (err error) { - r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func await(s []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(s) > 0 { - _p0 = unsafe.Pointer(&s[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func open(path string, mode int) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func create(path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func remove(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func stat(path string, edir []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(edir) > 0 { - _p1 = unsafe.Pointer(&edir[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func bind(name string, old string, flag int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(old) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func mount(fd int, afd int, old string, flag int, aname string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(old) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(aname) - if err != nil { - return - } - r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func wstat(path string, edir []byte) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(edir) > 0 { - _p1 = unsafe.Pointer(&edir[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func chdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup(oldfd int, newfd int) (fd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pread(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pwrite(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Close(fd int) (err error) { - r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstat(fd int, edir []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(edir) > 0 { - _p0 = unsafe.Pointer(&edir[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fwstat(fd int, edir []byte) (err error) { - var _p0 unsafe.Pointer - if len(edir) > 0 { - _p0 = unsafe.Pointer(&edir[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - if int32(r0) == -1 { - err = e1 - } - return -} diff --git a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go deleted file mode 100644 index 7de61065f6..0000000000 --- a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go +++ /dev/null @@ -1,284 +0,0 @@ -// go run mksyscall.go -l32 -plan9 -tags plan9,amd64 syscall_plan9.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build plan9 && amd64 - -package plan9 - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fd2path(fd int, buf []byte) (err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pipe(p *[2]int32) (err error) { - r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func await(s []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(s) > 0 { - _p0 = unsafe.Pointer(&s[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func open(path string, mode int) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func create(path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func remove(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func stat(path string, edir []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(edir) > 0 { - _p1 = unsafe.Pointer(&edir[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func bind(name string, old string, flag int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(old) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func mount(fd int, afd int, old string, flag int, aname string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(old) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(aname) - if err != nil { - return - } - r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func wstat(path string, edir []byte) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(edir) > 0 { - _p1 = unsafe.Pointer(&edir[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func chdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup(oldfd int, newfd int) (fd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pread(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pwrite(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Close(fd int) (err error) { - r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstat(fd int, edir []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(edir) > 0 { - _p0 = unsafe.Pointer(&edir[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fwstat(fd int, edir []byte) (err error) { - var _p0 unsafe.Pointer - if len(edir) > 0 { - _p0 = unsafe.Pointer(&edir[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - if int32(r0) == -1 { - err = e1 - } - return -} diff --git a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go deleted file mode 100644 index ea85780f03..0000000000 --- a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go +++ /dev/null @@ -1,284 +0,0 @@ -// go run mksyscall.go -l32 -plan9 -tags plan9,arm syscall_plan9.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build plan9 && arm - -package plan9 - -import "unsafe" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func fd2path(fd int, buf []byte) (err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func pipe(p *[2]int32) (err error) { - r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func await(s []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(s) > 0 { - _p0 = unsafe.Pointer(&s[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func open(path string, mode int) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func create(path string, mode int, perm uint32) (fd int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func remove(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func stat(path string, edir []byte) (n int, err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(edir) > 0 { - _p1 = unsafe.Pointer(&edir[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func bind(name string, old string, flag int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(name) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(old) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func mount(fd int, afd int, old string, flag int, aname string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(old) - if err != nil { - return - } - var _p1 *byte - _p1, err = BytePtrFromString(aname) - if err != nil { - return - } - r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func wstat(path string, edir []byte) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - var _p1 unsafe.Pointer - if len(edir) > 0 { - _p1 = unsafe.Pointer(&edir[0]) - } else { - _p1 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func chdir(path string) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Dup(oldfd int, newfd int) (fd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) - fd = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pread(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pwrite(fd int, p []byte, offset int64) (n int, err error) { - var _p0 unsafe.Pointer - if len(p) > 0 { - _p0 = unsafe.Pointer(&p[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Close(fd int) (err error) { - r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstat(fd int, edir []byte) (n int, err error) { - var _p0 unsafe.Pointer - if len(edir) > 0 { - _p0 = unsafe.Pointer(&edir[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - n = int(r0) - if int32(r0) == -1 { - err = e1 - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fwstat(fd int, edir []byte) (err error) { - var _p0 unsafe.Pointer - if len(edir) > 0 { - _p0 = unsafe.Pointer(&edir[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - if int32(r0) == -1 { - err = e1 - } - return -} diff --git a/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go b/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go deleted file mode 100644 index 22e8abd43d..0000000000 --- a/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go +++ /dev/null @@ -1,49 +0,0 @@ -// mksysnum_plan9.sh /opt/plan9/sys/src/libc/9syscall/sys.h -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT - -package plan9 - -const ( - SYS_SYSR1 = 0 - SYS_BIND = 2 - SYS_CHDIR = 3 - SYS_CLOSE = 4 - SYS_DUP = 5 - SYS_ALARM = 6 - SYS_EXEC = 7 - SYS_EXITS = 8 - SYS_FAUTH = 10 - SYS_SEGBRK = 12 - SYS_OPEN = 14 - SYS_OSEEK = 16 - SYS_SLEEP = 17 - SYS_RFORK = 19 - SYS_PIPE = 21 - SYS_CREATE = 22 - SYS_FD2PATH = 23 - SYS_BRK_ = 24 - SYS_REMOVE = 25 - SYS_NOTIFY = 28 - SYS_NOTED = 29 - SYS_SEGATTACH = 30 - SYS_SEGDETACH = 31 - SYS_SEGFREE = 32 - SYS_SEGFLUSH = 33 - SYS_RENDEZVOUS = 34 - SYS_UNMOUNT = 35 - SYS_SEMACQUIRE = 37 - SYS_SEMRELEASE = 38 - SYS_SEEK = 39 - SYS_FVERSION = 40 - SYS_ERRSTR = 41 - SYS_STAT = 42 - SYS_FSTAT = 43 - SYS_WSTAT = 44 - SYS_FWSTAT = 45 - SYS_MOUNT = 46 - SYS_AWAIT = 47 - SYS_PREAD = 50 - SYS_PWRITE = 51 - SYS_TSEMACQUIRE = 52 - SYS_NSEC = 53 -) diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md index 7d3c060e12..6e08a76a71 100644 --- a/vendor/golang.org/x/sys/unix/README.md +++ b/vendor/golang.org/x/sys/unix/README.md @@ -156,7 +156,7 @@ from the generated architecture-specific files listed below, and merge these into a common file for each OS. The merge is performed in the following steps: -1. Construct the set of common code that is idential in all architecture-specific files. +1. Construct the set of common code that is identical in all architecture-specific files. 2. Write this common code to the merged file. 3. Remove the common code from all architecture-specific files. diff --git a/vendor/golang.org/x/sys/unix/auxv.go b/vendor/golang.org/x/sys/unix/auxv.go new file mode 100644 index 0000000000..37a82528f5 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/auxv.go @@ -0,0 +1,36 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) + +package unix + +import ( + "syscall" + "unsafe" +) + +//go:linkname runtime_getAuxv runtime.getAuxv +func runtime_getAuxv() []uintptr + +// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs. +// The returned slice is always a fresh copy, owned by the caller. +// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed, +// which happens in some locked-down environments and build modes. +func Auxv() ([][2]uintptr, error) { + vec := runtime_getAuxv() + vecLen := len(vec) + + if vecLen == 0 { + return nil, syscall.ENOENT + } + + if vecLen%2 != 0 { + return nil, syscall.EINVAL + } + + result := make([]uintptr, vecLen) + copy(result, vec) + return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil +} diff --git a/vendor/golang.org/x/sys/unix/auxv_unsupported.go b/vendor/golang.org/x/sys/unix/auxv_unsupported.go new file mode 100644 index 0000000000..1200487f2e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/auxv_unsupported.go @@ -0,0 +1,13 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) + +package unix + +import "syscall" + +func Auxv() ([][2]uintptr, error) { + return nil, syscall.ENOTSUP +} diff --git a/vendor/golang.org/x/sys/unix/ioctl_linux.go b/vendor/golang.org/x/sys/unix/ioctl_linux.go index dbe680eab8..7ca4fa12aa 100644 --- a/vendor/golang.org/x/sys/unix/ioctl_linux.go +++ b/vendor/golang.org/x/sys/unix/ioctl_linux.go @@ -58,6 +58,102 @@ func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) { return &value, err } +// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC +// association for the network device specified by ifname. +func IoctlGetEthtoolTsInfo(fd int, ifname string) (*EthtoolTsInfo, error) { + ifr, err := NewIfreq(ifname) + if err != nil { + return nil, err + } + + value := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO} + ifrd := ifr.withData(unsafe.Pointer(&value)) + + err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd) + return &value, err +} + +// IoctlGetHwTstamp retrieves the hardware timestamping configuration +// for the network device specified by ifname. +func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) { + ifr, err := NewIfreq(ifname) + if err != nil { + return nil, err + } + + value := HwTstampConfig{} + ifrd := ifr.withData(unsafe.Pointer(&value)) + + err = ioctlIfreqData(fd, SIOCGHWTSTAMP, &ifrd) + return &value, err +} + +// IoctlSetHwTstamp updates the hardware timestamping configuration for +// the network device specified by ifname. +func IoctlSetHwTstamp(fd int, ifname string, cfg *HwTstampConfig) error { + ifr, err := NewIfreq(ifname) + if err != nil { + return err + } + ifrd := ifr.withData(unsafe.Pointer(cfg)) + return ioctlIfreqData(fd, SIOCSHWTSTAMP, &ifrd) +} + +// FdToClockID derives the clock ID from the file descriptor number +// - see clock_gettime(3), FD_TO_CLOCKID macros. The resulting ID is +// suitable for system calls like ClockGettime. +func FdToClockID(fd int) int32 { return int32((int(^fd) << 3) | 3) } + +// IoctlPtpClockGetcaps returns the description of a given PTP device. +func IoctlPtpClockGetcaps(fd int) (*PtpClockCaps, error) { + var value PtpClockCaps + err := ioctlPtr(fd, PTP_CLOCK_GETCAPS2, unsafe.Pointer(&value)) + return &value, err +} + +// IoctlPtpSysOffsetPrecise returns a description of the clock +// offset compared to the system clock. +func IoctlPtpSysOffsetPrecise(fd int) (*PtpSysOffsetPrecise, error) { + var value PtpSysOffsetPrecise + err := ioctlPtr(fd, PTP_SYS_OFFSET_PRECISE2, unsafe.Pointer(&value)) + return &value, err +} + +// IoctlPtpSysOffsetExtended returns an extended description of the +// clock offset compared to the system clock. The samples parameter +// specifies the desired number of measurements. +func IoctlPtpSysOffsetExtended(fd int, samples uint) (*PtpSysOffsetExtended, error) { + value := PtpSysOffsetExtended{Samples: uint32(samples)} + err := ioctlPtr(fd, PTP_SYS_OFFSET_EXTENDED2, unsafe.Pointer(&value)) + return &value, err +} + +// IoctlPtpPinGetfunc returns the configuration of the specified +// I/O pin on given PTP device. +func IoctlPtpPinGetfunc(fd int, index uint) (*PtpPinDesc, error) { + value := PtpPinDesc{Index: uint32(index)} + err := ioctlPtr(fd, PTP_PIN_GETFUNC2, unsafe.Pointer(&value)) + return &value, err +} + +// IoctlPtpPinSetfunc updates configuration of the specified PTP +// I/O pin. +func IoctlPtpPinSetfunc(fd int, pd *PtpPinDesc) error { + return ioctlPtr(fd, PTP_PIN_SETFUNC2, unsafe.Pointer(pd)) +} + +// IoctlPtpPeroutRequest configures the periodic output mode of the +// PTP I/O pins. +func IoctlPtpPeroutRequest(fd int, r *PtpPeroutRequest) error { + return ioctlPtr(fd, PTP_PEROUT_REQUEST2, unsafe.Pointer(r)) +} + +// IoctlPtpExttsRequest configures the external timestamping mode +// of the PTP I/O pins. +func IoctlPtpExttsRequest(fd int, r *PtpExttsRequest) error { + return ioctlPtr(fd, PTP_EXTTS_REQUEST2, unsafe.Pointer(r)) +} + // IoctlGetWatchdogInfo fetches information about a watchdog device from the // Linux watchdog API. For more information, see: // https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index d07dd09eb5..6ab02b6c31 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -158,6 +158,16 @@ includes_Linux=' #endif #define _GNU_SOURCE +// See the description in unix/linux/types.go +#if defined(__ARM_EABI__) || \ + (defined(__mips__) && (_MIPS_SIM == _ABIO32)) || \ + (defined(__powerpc__) && (!defined(__powerpc64__))) +# ifdef _TIME_BITS +# undef _TIME_BITS +# endif +# define _TIME_BITS 32 +#endif + // is broken on powerpc64, as it fails to include definitions of // these structures. We just include them copied from . #if defined(__powerpc__) @@ -256,6 +266,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -527,6 +538,7 @@ ccflags="$@" $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ || $2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ || $2 ~ /^NFC_.*_(MAX)?SIZE$/ || + $2 ~ /^PTP_/ || $2 ~ /^RAW_PAYLOAD_/ || $2 ~ /^[US]F_/ || $2 ~ /^TP_STATUS_/ || @@ -552,6 +564,7 @@ ccflags="$@" $2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ && $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ || $2 ~ /^SOCK_|SK_DIAG_|SKNLGRP_$/ || + $2 ~ /^(CONNECT|SAE)_/ || $2 ~ /^FIORDCHK$/ || $2 ~ /^SIOC/ || $2 ~ /^TIOC/ || @@ -655,7 +668,7 @@ errors=$( signals=$( echo '#include ' | $CC -x c - -E -dM $ccflags | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | - grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' | + grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | sort ) @@ -665,7 +678,7 @@ echo '#include ' | $CC -x c - -E -dM $ccflags | sort >_error.grep echo '#include ' | $CC -x c - -E -dM $ccflags | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | - grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' | + grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | sort >_signal.grep echo '// mkerrors.sh' "$@" diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go index 67ce6cef2d..6f15ba1eaf 100644 --- a/vendor/golang.org/x/sys/unix/syscall_aix.go +++ b/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -360,7 +360,7 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, var status _C_int var r Pid_t err = ERESTART - // AIX wait4 may return with ERESTART errno, while the processus is still + // AIX wait4 may return with ERESTART errno, while the process is still // active. for err == ERESTART { r, err = wait4(Pid_t(pid), &status, options, rusage) diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 2d15200adb..099867deed 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -566,6 +566,43 @@ func PthreadFchdir(fd int) (err error) { return pthread_fchdir_np(fd) } +// Connectx calls connectx(2) to initiate a connection on a socket. +// +// srcIf, srcAddr, and dstAddr are filled into a [SaEndpoints] struct and passed as the endpoints argument. +// +// - srcIf is the optional source interface index. 0 means unspecified. +// - srcAddr is the optional source address. nil means unspecified. +// - dstAddr is the destination address. +// +// On success, Connectx returns the number of bytes enqueued for transmission. +func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocID, flags uint32, iov []Iovec, connid *SaeConnID) (n uintptr, err error) { + endpoints := SaEndpoints{ + Srcif: srcIf, + } + + if srcAddr != nil { + addrp, addrlen, err := srcAddr.sockaddr() + if err != nil { + return 0, err + } + endpoints.Srcaddr = (*RawSockaddr)(addrp) + endpoints.Srcaddrlen = uint32(addrlen) + } + + if dstAddr != nil { + addrp, addrlen, err := dstAddr.sockaddr() + if err != nil { + return 0, err + } + endpoints.Dstaddr = (*RawSockaddr)(addrp) + endpoints.Dstaddrlen = uint32(addrlen) + } + + err = connectx(fd, &endpoints, associd, flags, iov, &n, connid) + return +} + +//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go index 97cb916f2c..be8c002070 100644 --- a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go +++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go @@ -246,6 +246,18 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e return sendfile(outfd, infd, offset, count) } +func Dup3(oldfd, newfd, flags int) error { + if oldfd == newfd || flags&^O_CLOEXEC != 0 { + return EINVAL + } + how := F_DUP2FD + if flags&O_CLOEXEC != 0 { + how = F_DUP2FD_CLOEXEC + } + _, err := fcntl(oldfd, how, newfd) + return err +} + /* * Exposed directly */ diff --git a/vendor/golang.org/x/sys/unix/syscall_hurd.go b/vendor/golang.org/x/sys/unix/syscall_hurd.go index ba46651f8e..a6a2d2fc2b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_hurd.go +++ b/vendor/golang.org/x/sys/unix/syscall_hurd.go @@ -11,6 +11,7 @@ package unix int ioctl(int, unsigned long int, uintptr_t); */ import "C" +import "unsafe" func ioctl(fd int, req uint, arg uintptr) (err error) { r0, er := C.ioctl(C.int(fd), C.ulong(req), C.uintptr_t(arg)) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 3f1d3d4cb2..230a94549a 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -1295,6 +1295,48 @@ func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) { return &value, err } +// GetsockoptTCPCCVegasInfo returns algorithm specific congestion control information for a socket using the "vegas" +// algorithm. +// +// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option: +// +// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION) +func GetsockoptTCPCCVegasInfo(fd, level, opt int) (*TCPVegasInfo, error) { + var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment + vallen := _Socklen(SizeofTCPCCInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + out := (*TCPVegasInfo)(unsafe.Pointer(&value[0])) + return out, err +} + +// GetsockoptTCPCCDCTCPInfo returns algorithm specific congestion control information for a socket using the "dctp" +// algorithm. +// +// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option: +// +// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION) +func GetsockoptTCPCCDCTCPInfo(fd, level, opt int) (*TCPDCTCPInfo, error) { + var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment + vallen := _Socklen(SizeofTCPCCInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + out := (*TCPDCTCPInfo)(unsafe.Pointer(&value[0])) + return out, err +} + +// GetsockoptTCPCCBBRInfo returns algorithm specific congestion control information for a socket using the "bbr" +// algorithm. +// +// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option: +// +// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION) +func GetsockoptTCPCCBBRInfo(fd, level, opt int) (*TCPBBRInfo, error) { + var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment + vallen := _Socklen(SizeofTCPCCInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + out := (*TCPBBRInfo)(unsafe.Pointer(&value[0])) + return out, err +} + // GetsockoptString returns the string value of the socket option opt for the // socket associated with fd at the given socket level. func GetsockoptString(fd, level, opt int) (string, error) { @@ -1818,6 +1860,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e //sys ClockAdjtime(clockid int32, buf *Timex) (state int, err error) //sys ClockGetres(clockid int32, res *Timespec) (err error) //sys ClockGettime(clockid int32, time *Timespec) (err error) +//sys ClockSettime(clockid int32, time *Timespec) (err error) //sys ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) //sys Close(fd int) (err error) //sys CloseRange(first uint, last uint, flags uint) (err error) @@ -1959,7 +2002,26 @@ func Getpgrp() (pid int) { //sysnb Getpid() (pid int) //sysnb Getppid() (ppid int) //sys Getpriority(which int, who int) (prio int, err error) -//sys Getrandom(buf []byte, flags int) (n int, err error) + +func Getrandom(buf []byte, flags int) (n int, err error) { + vdsoRet, supported := vgetrandom(buf, uint32(flags)) + if supported { + if vdsoRet < 0 { + return 0, errnoErr(syscall.Errno(-vdsoRet)) + } + return vdsoRet, nil + } + var p *byte + if len(buf) > 0 { + p = &buf[0] + } + r, _, e := Syscall(SYS_GETRANDOM, uintptr(unsafe.Pointer(p)), uintptr(len(buf)), uintptr(flags)) + if e != 0 { + return 0, errnoErr(e) + } + return int(r), nil +} + //sysnb Getrusage(who int, rusage *Rusage) (err error) //sysnb Getsid(pid int) (sid int, err error) //sysnb Gettid() (tid int) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index cf2ee6c75e..745e5c7e6c 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -182,3 +182,5 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error } return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) } + +const SYS_FSTATAT = SYS_NEWFSTATAT diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go index 3d0e98451f..dd2262a407 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go @@ -214,3 +214,5 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error } return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) } + +const SYS_FSTATAT = SYS_NEWFSTATAT diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index 6f5a288944..8cf3670bda 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -187,3 +187,5 @@ func RISCVHWProbe(pairs []RISCVHWProbePairs, set *CPUSet, flags uint) (err error } return riscvHWProbe(pairs, setSize, set, flags) } + +const SYS_FSTATAT = SYS_NEWFSTATAT diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go index 21974af064..abc3955477 100644 --- a/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -1102,3 +1102,90 @@ func (s *Strioctl) SetInt(i int) { func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) { return ioctlPtrRet(fd, req, unsafe.Pointer(s)) } + +// Ucred Helpers +// See ucred(3c) and getpeerucred(3c) + +//sys getpeerucred(fd uintptr, ucred *uintptr) (err error) +//sys ucredFree(ucred uintptr) = ucred_free +//sys ucredGet(pid int) (ucred uintptr, err error) = ucred_get +//sys ucredGeteuid(ucred uintptr) (uid int) = ucred_geteuid +//sys ucredGetegid(ucred uintptr) (gid int) = ucred_getegid +//sys ucredGetruid(ucred uintptr) (uid int) = ucred_getruid +//sys ucredGetrgid(ucred uintptr) (gid int) = ucred_getrgid +//sys ucredGetsuid(ucred uintptr) (uid int) = ucred_getsuid +//sys ucredGetsgid(ucred uintptr) (gid int) = ucred_getsgid +//sys ucredGetpid(ucred uintptr) (pid int) = ucred_getpid + +// Ucred is an opaque struct that holds user credentials. +type Ucred struct { + ucred uintptr +} + +// We need to ensure that ucredFree is called on the underlying ucred +// when the Ucred is garbage collected. +func ucredFinalizer(u *Ucred) { + ucredFree(u.ucred) +} + +func GetPeerUcred(fd uintptr) (*Ucred, error) { + var ucred uintptr + err := getpeerucred(fd, &ucred) + if err != nil { + return nil, err + } + result := &Ucred{ + ucred: ucred, + } + // set the finalizer on the result so that the ucred will be freed + runtime.SetFinalizer(result, ucredFinalizer) + return result, nil +} + +func UcredGet(pid int) (*Ucred, error) { + ucred, err := ucredGet(pid) + if err != nil { + return nil, err + } + result := &Ucred{ + ucred: ucred, + } + // set the finalizer on the result so that the ucred will be freed + runtime.SetFinalizer(result, ucredFinalizer) + return result, nil +} + +func (u *Ucred) Geteuid() int { + defer runtime.KeepAlive(u) + return ucredGeteuid(u.ucred) +} + +func (u *Ucred) Getruid() int { + defer runtime.KeepAlive(u) + return ucredGetruid(u.ucred) +} + +func (u *Ucred) Getsuid() int { + defer runtime.KeepAlive(u) + return ucredGetsuid(u.ucred) +} + +func (u *Ucred) Getegid() int { + defer runtime.KeepAlive(u) + return ucredGetegid(u.ucred) +} + +func (u *Ucred) Getrgid() int { + defer runtime.KeepAlive(u) + return ucredGetrgid(u.ucred) +} + +func (u *Ucred) Getsgid() int { + defer runtime.KeepAlive(u) + return ucredGetsgid(u.ucred) +} + +func (u *Ucred) Getpid() int { + defer runtime.KeepAlive(u) + return ucredGetpid(u.ucred) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index 312ae6ac1d..7bf5c04bb0 100644 --- a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -768,6 +768,15 @@ func Munmap(b []byte) (err error) { return mapper.Munmap(b) } +func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) { + xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset) + return unsafe.Pointer(xaddr), err +} + +func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) { + return mapper.munmap(uintptr(addr), length) +} + //sys Gethostname(buf []byte) (err error) = SYS___GETHOSTNAME_A //sysnb Getgid() (gid int) //sysnb Getpid() (pid int) @@ -816,10 +825,10 @@ func Lstat(path string, stat *Stat_t) (err error) { // for checking symlinks begins with $VERSION/ $SYSNAME/ $SYSSYMR/ $SYSSYMA/ func isSpecialPath(path []byte) (v bool) { var special = [4][8]byte{ - [8]byte{'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'}, - [8]byte{'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'}, - [8]byte{'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'}, - [8]byte{'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}} + {'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'}, + {'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'}, + {'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'}, + {'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}} var i, j int for i = 0; i < len(special); i++ { @@ -3115,3 +3124,90 @@ func legacy_Mkfifoat(dirfd int, path string, mode uint32) (err error) { //sys Posix_openpt(oflag int) (fd int, err error) = SYS_POSIX_OPENPT //sys Grantpt(fildes int) (rc int, err error) = SYS_GRANTPT //sys Unlockpt(fildes int) (rc int, err error) = SYS_UNLOCKPT + +func fcntlAsIs(fd uintptr, cmd int, arg uintptr) (val int, err error) { + runtime.EnterSyscall() + r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_FCNTL<<4, uintptr(fd), uintptr(cmd), arg) + runtime.ExitSyscall() + val = int(r0) + if int64(r0) == -1 { + err = errnoErr2(e1, e2) + } + return +} + +func Fcntl(fd uintptr, cmd int, op interface{}) (ret int, err error) { + switch op.(type) { + case *Flock_t: + err = FcntlFlock(fd, cmd, op.(*Flock_t)) + if err != nil { + ret = -1 + } + return + case int: + return FcntlInt(fd, cmd, op.(int)) + case *F_cnvrt: + return fcntlAsIs(fd, cmd, uintptr(unsafe.Pointer(op.(*F_cnvrt)))) + case unsafe.Pointer: + return fcntlAsIs(fd, cmd, uintptr(op.(unsafe.Pointer))) + default: + return -1, EINVAL + } + return +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + // TODO: use LE call instead if the call is implemented + originalOffset, err := Seek(infd, 0, SEEK_CUR) + if err != nil { + return -1, err + } + //start reading data from in_fd + if offset != nil { + _, err := Seek(infd, *offset, SEEK_SET) + if err != nil { + return -1, err + } + } + + buf := make([]byte, count) + readBuf := make([]byte, 0) + var n int = 0 + for i := 0; i < count; i += n { + n, err := Read(infd, buf) + if n == 0 { + if err != nil { + return -1, err + } else { // EOF + break + } + } + readBuf = append(readBuf, buf...) + buf = buf[0:0] + } + + n2, err := Write(outfd, readBuf) + if err != nil { + return -1, err + } + + //When sendfile() returns, this variable will be set to the + // offset of the byte following the last byte that was read. + if offset != nil { + *offset = *offset + int64(n) + // If offset is not NULL, then sendfile() does not modify the file + // offset of in_fd + _, err := Seek(infd, originalOffset, SEEK_SET) + if err != nil { + return -1, err + } + } + return n2, nil +} diff --git a/vendor/golang.org/x/sys/unix/vgetrandom_linux.go b/vendor/golang.org/x/sys/unix/vgetrandom_linux.go new file mode 100644 index 0000000000..07ac8e09d1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/vgetrandom_linux.go @@ -0,0 +1,13 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && go1.24 + +package unix + +import _ "unsafe" + +//go:linkname vgetrandom runtime.vgetrandom +//go:noescape +func vgetrandom(p []byte, flags uint32) (ret int, supported bool) diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain_go119.go b/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go similarity index 56% rename from vendor/golang.org/x/tools/internal/versions/toolchain_go119.go rename to vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go index f65beed9d8..297e97bce9 100644 --- a/vendor/golang.org/x/tools/internal/versions/toolchain_go119.go +++ b/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go @@ -2,13 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.19 -// +build go1.19 +//go:build !linux || !go1.24 -package versions +package unix -func init() { - if Compare(toolchain, Go1_19) < 0 { - toolchain = Go1_19 - } +func vgetrandom(p []byte, flags uint32) (ret int, supported bool) { + return -1, false } diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go index 4308ac1772..d73c4652e6 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go @@ -237,6 +237,9 @@ const ( CLOCK_UPTIME_RAW_APPROX = 0x9 CLONE_NOFOLLOW = 0x1 CLONE_NOOWNERCOPY = 0x2 + CONNECT_DATA_AUTHENTICATED = 0x4 + CONNECT_DATA_IDEMPOTENT = 0x2 + CONNECT_RESUME_ON_READ_WRITE = 0x1 CR0 = 0x0 CR1 = 0x1000 CR2 = 0x2000 @@ -1265,6 +1268,10 @@ const ( RTV_SSTHRESH = 0x20 RUSAGE_CHILDREN = -0x1 RUSAGE_SELF = 0x0 + SAE_ASSOCID_ALL = 0xffffffff + SAE_ASSOCID_ANY = 0x0 + SAE_CONNID_ALL = 0xffffffff + SAE_CONNID_ANY = 0x0 SCM_CREDS = 0x3 SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go index c8068a7a16..4a55a40058 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go @@ -237,6 +237,9 @@ const ( CLOCK_UPTIME_RAW_APPROX = 0x9 CLONE_NOFOLLOW = 0x1 CLONE_NOOWNERCOPY = 0x2 + CONNECT_DATA_AUTHENTICATED = 0x4 + CONNECT_DATA_IDEMPOTENT = 0x2 + CONNECT_RESUME_ON_READ_WRITE = 0x1 CR0 = 0x0 CR1 = 0x1000 CR2 = 0x2000 @@ -1265,6 +1268,10 @@ const ( RTV_SSTHRESH = 0x20 RUSAGE_CHILDREN = -0x1 RUSAGE_SELF = 0x0 + SAE_ASSOCID_ALL = 0xffffffff + SAE_ASSOCID_ANY = 0x0 + SAE_CONNID_ALL = 0xffffffff + SAE_CONNID_ANY = 0x0 SCM_CREDS = 0x3 SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 01a70b2463..4f432bfe8f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -321,6 +321,9 @@ const ( AUDIT_INTEGRITY_STATUS = 0x70a AUDIT_IPC = 0x517 AUDIT_IPC_SET_PERM = 0x51f + AUDIT_IPE_ACCESS = 0x58c + AUDIT_IPE_CONFIG_CHANGE = 0x58d + AUDIT_IPE_POLICY_LOAD = 0x58e AUDIT_KERNEL = 0x7d0 AUDIT_KERNEL_OTHER = 0x524 AUDIT_KERN_MODULE = 0x532 @@ -489,12 +492,14 @@ const ( BPF_F_ID = 0x20 BPF_F_NETFILTER_IP_DEFRAG = 0x1 BPF_F_QUERY_EFFECTIVE = 0x1 + BPF_F_REDIRECT_FLAGS = 0x19 BPF_F_REPLACE = 0x4 BPF_F_SLEEPABLE = 0x10 BPF_F_STRICT_ALIGNMENT = 0x1 BPF_F_TEST_REG_INVARIANTS = 0x80 BPF_F_TEST_RND_HI32 = 0x4 BPF_F_TEST_RUN_ON_CPU = 0x1 + BPF_F_TEST_SKB_CHECKSUM_COMPLETE = 0x4 BPF_F_TEST_STATE_FREQ = 0x8 BPF_F_TEST_XDP_LIVE_FRAMES = 0x2 BPF_F_XDP_DEV_BOUND_ONLY = 0x40 @@ -1165,6 +1170,7 @@ const ( EXTA = 0xe EXTB = 0xf F2FS_SUPER_MAGIC = 0xf2f52010 + FALLOC_FL_ALLOCATE_RANGE = 0x0 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -1239,6 +1245,7 @@ const ( FAN_REPORT_DFID_NAME = 0xc00 FAN_REPORT_DFID_NAME_TARGET = 0x1e00 FAN_REPORT_DIR_FID = 0x400 + FAN_REPORT_FD_ERROR = 0x2000 FAN_REPORT_FID = 0x200 FAN_REPORT_NAME = 0x800 FAN_REPORT_PIDFD = 0x80 @@ -1324,8 +1331,10 @@ const ( FUSE_SUPER_MAGIC = 0x65735546 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 + F_CREATED_QUERY = 0x404 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 + F_DUPFD_QUERY = 0x403 F_EXLCK = 0x4 F_GETFD = 0x1 F_GETFL = 0x3 @@ -1545,6 +1554,7 @@ const ( IPPROTO_ROUTING = 0x2b IPPROTO_RSVP = 0x2e IPPROTO_SCTP = 0x84 + IPPROTO_SMC = 0x100 IPPROTO_TCP = 0x6 IPPROTO_TP = 0x1d IPPROTO_UDP = 0x11 @@ -1617,6 +1627,8 @@ const ( IPV6_UNICAST_IF = 0x4c IPV6_USER_FLOW = 0xe IPV6_V6ONLY = 0x1a + IPV6_VERSION = 0x60 + IPV6_VERSION_MASK = 0xf0 IPV6_XFRM_POLICY = 0x23 IP_ADD_MEMBERSHIP = 0x23 IP_ADD_SOURCE_MEMBERSHIP = 0x27 @@ -1798,6 +1810,8 @@ const ( LANDLOCK_ACCESS_NET_BIND_TCP = 0x1 LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2 LANDLOCK_CREATE_RULESET_VERSION = 0x1 + LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1 + LANDLOCK_SCOPE_SIGNAL = 0x2 LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef LINUX_REBOOT_CMD_HALT = 0xcdef0123 @@ -1859,6 +1873,7 @@ const ( MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 MADV_WIPEONFORK = 0x12 + MAP_DROPPABLE = 0x8 MAP_FILE = 0x0 MAP_FIXED = 0x10 MAP_FIXED_NOREPLACE = 0x100000 @@ -1922,6 +1937,8 @@ const ( MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 MNT_ID_REQ_SIZE_VER0 = 0x18 + MNT_ID_REQ_SIZE_VER1 = 0x20 + MNT_NS_INFO_SIZE_VER0 = 0x10 MODULE_INIT_COMPRESSED_FILE = 0x4 MODULE_INIT_IGNORE_MODVERSIONS = 0x1 MODULE_INIT_IGNORE_VERMAGIC = 0x2 @@ -1957,6 +1974,7 @@ const ( MSG_PEEK = 0x2 MSG_PROXY = 0x10 MSG_RST = 0x1000 + MSG_SOCK_DEVMEM = 0x2000000 MSG_SYN = 0x400 MSG_TRUNC = 0x20 MSG_TRYHARD = 0x4 @@ -2073,6 +2091,7 @@ const ( NFC_ATR_REQ_MAXSIZE = 0x40 NFC_ATR_RES_GB_MAXSIZE = 0x2f NFC_ATR_RES_MAXSIZE = 0x40 + NFC_ATS_MAXSIZE = 0x14 NFC_COMM_ACTIVE = 0x0 NFC_COMM_PASSIVE = 0x1 NFC_DEVICE_NAME_MAXSIZE = 0x8 @@ -2153,6 +2172,7 @@ const ( NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_ULOG = 0x4 NFS_SUPER_MAGIC = 0x6969 + NFT_BITWISE_BOOL = 0x0 NFT_CHAIN_FLAGS = 0x7 NFT_CHAIN_MAXNAMELEN = 0x100 NFT_CT_MAX = 0x17 @@ -2187,7 +2207,7 @@ const ( NFT_REG_SIZE = 0x10 NFT_REJECT_ICMPX_MAX = 0x3 NFT_RT_MAX = 0x4 - NFT_SECMARK_CTX_MAXLEN = 0x100 + NFT_SECMARK_CTX_MAXLEN = 0x1000 NFT_SET_MAXNAMELEN = 0x100 NFT_SOCKET_MAX = 0x3 NFT_TABLE_F_MASK = 0x7 @@ -2356,9 +2376,11 @@ const ( PERF_MEM_LVLNUM_IO = 0xa PERF_MEM_LVLNUM_L1 = 0x1 PERF_MEM_LVLNUM_L2 = 0x2 + PERF_MEM_LVLNUM_L2_MHB = 0x5 PERF_MEM_LVLNUM_L3 = 0x3 PERF_MEM_LVLNUM_L4 = 0x4 PERF_MEM_LVLNUM_LFB = 0xc + PERF_MEM_LVLNUM_MSC = 0x6 PERF_MEM_LVLNUM_NA = 0xf PERF_MEM_LVLNUM_PMEM = 0xe PERF_MEM_LVLNUM_RAM = 0xd @@ -2431,6 +2453,7 @@ const ( PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROCFS_IOCTL_MAGIC = 'f' PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 @@ -2478,6 +2501,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SHADOW_STACK_STATUS = 0x4a PR_GET_SPECULATION_CTRL = 0x34 PR_GET_TAGGED_ADDR_CTRL = 0x38 PR_GET_THP_DISABLE = 0x2a @@ -2486,6 +2510,7 @@ const ( PR_GET_TIMING = 0xd PR_GET_TSC = 0x19 PR_GET_UNALIGN = 0x5 + PR_LOCK_SHADOW_STACK_STATUS = 0x4c PR_MCE_KILL = 0x21 PR_MCE_KILL_CLEAR = 0x0 PR_MCE_KILL_DEFAULT = 0x2 @@ -2512,6 +2537,8 @@ const ( PR_PAC_GET_ENABLED_KEYS = 0x3d PR_PAC_RESET_KEYS = 0x36 PR_PAC_SET_ENABLED_KEYS = 0x3c + PR_PMLEN_MASK = 0x7f000000 + PR_PMLEN_SHIFT = 0x18 PR_PPC_DEXCR_CTRL_CLEAR = 0x4 PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC = 0x10 PR_PPC_DEXCR_CTRL_EDITABLE = 0x1 @@ -2579,6 +2606,7 @@ const ( PR_SET_PTRACER = 0x59616d61 PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SHADOW_STACK_STATUS = 0x4b PR_SET_SPECULATION_CTRL = 0x35 PR_SET_SYSCALL_USER_DISPATCH = 0x3b PR_SET_TAGGED_ADDR_CTRL = 0x37 @@ -2589,6 +2617,9 @@ const ( PR_SET_UNALIGN = 0x6 PR_SET_VMA = 0x53564d41 PR_SET_VMA_ANON_NAME = 0x0 + PR_SHADOW_STACK_ENABLE = 0x1 + PR_SHADOW_STACK_PUSH = 0x4 + PR_SHADOW_STACK_WRITE = 0x2 PR_SME_GET_VL = 0x40 PR_SME_SET_VL = 0x3f PR_SME_SET_VL_ONEXEC = 0x40000 @@ -2620,6 +2651,28 @@ const ( PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 PSTOREFS_MAGIC = 0x6165676c + PTP_CLK_MAGIC = '=' + PTP_ENABLE_FEATURE = 0x1 + PTP_EXTTS_EDGES = 0x6 + PTP_EXTTS_EVENT_VALID = 0x1 + PTP_EXTTS_V1_VALID_FLAGS = 0x7 + PTP_EXTTS_VALID_FLAGS = 0x1f + PTP_EXT_OFFSET = 0x10 + PTP_FALLING_EDGE = 0x4 + PTP_MAX_SAMPLES = 0x19 + PTP_PEROUT_DUTY_CYCLE = 0x2 + PTP_PEROUT_ONE_SHOT = 0x1 + PTP_PEROUT_PHASE = 0x4 + PTP_PEROUT_V1_VALID_FLAGS = 0x0 + PTP_PEROUT_VALID_FLAGS = 0x7 + PTP_PIN_GETFUNC = 0xc0603d06 + PTP_PIN_GETFUNC2 = 0xc0603d0f + PTP_RISING_EDGE = 0x2 + PTP_STRICT_FLAGS = 0x8 + PTP_SYS_OFFSET_EXTENDED = 0xc4c03d09 + PTP_SYS_OFFSET_EXTENDED2 = 0xc4c03d12 + PTP_SYS_OFFSET_PRECISE = 0xc0403d08 + PTP_SYS_OFFSET_PRECISE2 = 0xc0403d11 PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -2876,7 +2929,6 @@ const ( RTM_NEWNEXTHOP = 0x68 RTM_NEWNEXTHOPBUCKET = 0x74 RTM_NEWNSID = 0x58 - RTM_NEWNVLAN = 0x70 RTM_NEWPREFIX = 0x34 RTM_NEWQDISC = 0x24 RTM_NEWROUTE = 0x18 @@ -2885,6 +2937,7 @@ const ( RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c RTM_NEWTUNNEL = 0x78 + RTM_NEWVLAN = 0x70 RTM_NR_FAMILIES = 0x1b RTM_NR_MSGTYPES = 0x6c RTM_SETDCB = 0x4f @@ -2933,15 +2986,17 @@ const ( RUSAGE_SELF = 0x0 RUSAGE_THREAD = 0x1 RWF_APPEND = 0x10 + RWF_ATOMIC = 0x40 RWF_DSYNC = 0x2 RWF_HIPRI = 0x1 RWF_NOAPPEND = 0x20 RWF_NOWAIT = 0x8 - RWF_SUPPORTED = 0x3f + RWF_SUPPORTED = 0x7f RWF_SYNC = 0x4 RWF_WRITE_LIFE_NOT_SET = 0x0 SCHED_BATCH = 0x3 SCHED_DEADLINE = 0x6 + SCHED_EXT = 0x7 SCHED_FIFO = 0x1 SCHED_FLAG_ALL = 0x7f SCHED_FLAG_DL_OVERRUN = 0x4 @@ -3210,6 +3265,7 @@ const ( STATX_ATTR_MOUNT_ROOT = 0x2000 STATX_ATTR_NODUMP = 0x40 STATX_ATTR_VERITY = 0x100000 + STATX_ATTR_WRITE_ATOMIC = 0x400000 STATX_BASIC_STATS = 0x7ff STATX_BLOCKS = 0x400 STATX_BTIME = 0x800 @@ -3226,6 +3282,7 @@ const ( STATX_SUBVOL = 0x8000 STATX_TYPE = 0x1 STATX_UID = 0x8 + STATX_WRITE_ATOMIC = 0x10000 STATX__RESERVED = 0x80000000 SYNC_FILE_RANGE_WAIT_AFTER = 0x4 SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 @@ -3624,6 +3681,7 @@ const ( XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 XDP_UMEM_PGOFF_FILL_RING = 0x100000000 XDP_UMEM_REG = 0x4 + XDP_UMEM_TX_METADATA_LEN = 0x4 XDP_UMEM_TX_SW_CSUM = 0x2 XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1 XDP_USE_NEED_WAKEUP = 0x8 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 684a5168da..75207613c7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -109,12 +109,15 @@ const ( HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -153,9 +156,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -232,6 +240,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x7434 PPPIOCXFERUNIT = 0x744e PR_SET_PTRACER_ANY = 0xffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_GETFPREGS = 0xe PTRACE_GETFPXREGS = 0x12 PTRACE_GET_THREAD_AREA = 0x19 @@ -278,10 +300,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -316,6 +341,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 61d74b592d..c68acda535 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -109,12 +109,15 @@ const ( HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -153,9 +156,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -232,6 +240,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x7434 PPPIOCXFERUNIT = 0x744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_ARCH_PRCTL = 0x1e PTRACE_GETFPREGS = 0xe PTRACE_GETFPXREGS = 0x12 @@ -279,10 +301,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -317,6 +342,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index a28c9e3e89..a8c607ab86 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x7434 PPPIOCXFERUNIT = 0x744e PR_SET_PTRACER_ANY = 0xffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_GETCRUNCHREGS = 0x19 PTRACE_GETFDPIC = 0x1f PTRACE_GETFDPIC_EXEC = 0x0 @@ -284,10 +306,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -322,6 +347,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index ab5d1fe8ea..18563dd8d3 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -109,15 +109,19 @@ const ( F_SETOWN = 0x8 F_UNLCK = 0x2 F_WRLCK = 0x1 + GCS_MAGIC = 0x47435300 HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -154,9 +158,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -200,6 +209,7 @@ const ( PERF_EVENT_IOC_SET_BPF = 0x40042408 PERF_EVENT_IOC_SET_FILTER = 0x40082406 PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + POE_MAGIC = 0x504f4530 PPPIOCATTACH = 0x4004743d PPPIOCATTCHAN = 0x40047438 PPPIOCBRIDGECHAN = 0x40047435 @@ -235,6 +245,20 @@ const ( PROT_BTI = 0x10 PROT_MTE = 0x20 PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_PEEKMTETAGS = 0x21 PTRACE_POKEMTETAGS = 0x22 PTRACE_SYSEMU = 0x1f @@ -275,10 +299,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -313,6 +340,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index c523090e7c..22912cdaa9 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -109,12 +109,15 @@ const ( HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -154,9 +157,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -233,6 +241,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x7434 PPPIOCXFERUNIT = 0x744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_SYSEMU = 0x1f PTRACE_SYSEMU_SINGLESTEP = 0x20 RLIMIT_AS = 0x9 @@ -271,10 +293,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -309,6 +334,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 01e6ea7804..29344eb37a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x100 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x20007434 PPPIOCXFERUNIT = 0x2000744e PR_SET_PTRACER_ANY = 0xffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETFPREGS = 0xe PTRACE_GET_THREAD_AREA = 0x19 PTRACE_GET_THREAD_AREA_3264 = 0xc4 @@ -277,10 +299,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -315,6 +340,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 SO_ERROR = 0x1007 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 7aa610b1e7..20d51fb96a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x100 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x20007434 PPPIOCXFERUNIT = 0x2000744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETFPREGS = 0xe PTRACE_GET_THREAD_AREA = 0x19 PTRACE_GET_THREAD_AREA_3264 = 0xc4 @@ -277,10 +299,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -315,6 +340,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 SO_ERROR = 0x1007 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 92af771b44..321b60902a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x100 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x20007434 PPPIOCXFERUNIT = 0x2000744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETFPREGS = 0xe PTRACE_GET_THREAD_AREA = 0x19 PTRACE_GET_THREAD_AREA_3264 = 0xc4 @@ -277,10 +299,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -315,6 +340,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 SO_ERROR = 0x1007 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index b27ef5e6f1..9bacdf1e27 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x100 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x20007434 PPPIOCXFERUNIT = 0x2000744e PR_SET_PTRACER_ANY = 0xffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETFPREGS = 0xe PTRACE_GET_THREAD_AREA = 0x19 PTRACE_GET_THREAD_AREA_3264 = 0xc4 @@ -277,10 +299,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -315,6 +340,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 SO_ERROR = 0x1007 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 237a2cefb3..c224272615 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x4000 ICANON = 0x100 IEXTEN = 0x400 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x80 IUCLC = 0x1000 IXOFF = 0x400 @@ -152,9 +155,14 @@ const ( NL3 = 0x300 NLDLY = 0x300 NOFLSH = 0x80000000 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x4 ONLCR = 0x2 @@ -232,6 +240,20 @@ const ( PPPIOCXFERUNIT = 0x2000744e PROT_SAO = 0x10 PR_SET_PTRACER_ANY = 0xffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETEVRREGS = 0x14 PTRACE_GETFPREGS = 0xe PTRACE_GETREGS64 = 0x16 @@ -332,10 +354,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -370,6 +395,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 4a5c555a36..6270c8ee13 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x4000 ICANON = 0x100 IEXTEN = 0x400 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x80 IUCLC = 0x1000 IXOFF = 0x400 @@ -152,9 +155,14 @@ const ( NL3 = 0x300 NLDLY = 0x300 NOFLSH = 0x80000000 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x4 ONLCR = 0x2 @@ -232,6 +240,20 @@ const ( PPPIOCXFERUNIT = 0x2000744e PROT_SAO = 0x10 PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETEVRREGS = 0x14 PTRACE_GETFPREGS = 0xe PTRACE_GETREGS64 = 0x16 @@ -336,10 +358,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -374,6 +399,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index a02fb49a5f..9966c1941f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x4000 ICANON = 0x100 IEXTEN = 0x400 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x80 IUCLC = 0x1000 IXOFF = 0x400 @@ -152,9 +155,14 @@ const ( NL3 = 0x300 NLDLY = 0x300 NOFLSH = 0x80000000 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x4 ONLCR = 0x2 @@ -232,6 +240,20 @@ const ( PPPIOCXFERUNIT = 0x2000744e PROT_SAO = 0x10 PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETEVRREGS = 0x14 PTRACE_GETFPREGS = 0xe PTRACE_GETREGS64 = 0x16 @@ -336,10 +358,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -374,6 +399,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index e26a7c61b2..848e5fcc42 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x7434 PPPIOCXFERUNIT = 0x744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_GETFDPIC = 0x21 PTRACE_GETFDPIC_EXEC = 0x0 PTRACE_GETFDPIC_INTERP = 0x1 @@ -268,10 +290,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -306,6 +331,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index c48f7c2103..669b2adb80 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -108,12 +108,15 @@ const ( HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 + HIDIOCREVOKE = 0x4004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -150,9 +153,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 @@ -229,6 +237,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x7434 PPPIOCXFERUNIT = 0x744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x80503d01 + PTP_CLOCK_GETCAPS2 = 0x80503d0a + PTP_ENABLE_PPS = 0x40043d04 + PTP_ENABLE_PPS2 = 0x40043d0d + PTP_EXTTS_REQUEST = 0x40103d02 + PTP_EXTTS_REQUEST2 = 0x40103d0b + PTP_MASK_CLEAR_ALL = 0x3d13 + PTP_MASK_EN_SINGLE = 0x40043d14 + PTP_PEROUT_REQUEST = 0x40383d03 + PTP_PEROUT_REQUEST2 = 0x40383d0c + PTP_PIN_SETFUNC = 0x40603d07 + PTP_PIN_SETFUNC2 = 0x40603d10 + PTP_SYS_OFFSET = 0x43403d05 + PTP_SYS_OFFSET2 = 0x43403d0e PTRACE_DISABLE_TE = 0x5010 PTRACE_ENABLE_TE = 0x5009 PTRACE_GET_LAST_BREAK = 0x5006 @@ -340,10 +362,13 @@ const ( RTC_WIE_ON = 0x700f RTC_WKALM_RD = 0x80287010 RTC_WKALM_SET = 0x4028700f + SCM_DEVMEM_DMABUF = 0x4f + SCM_DEVMEM_LINEAR = 0x4e SCM_TIMESTAMPING = 0x25 SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 @@ -378,6 +403,9 @@ const ( SO_CNX_ADVICE = 0x35 SO_COOKIE = 0x39 SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DEVMEM_DMABUF = 0x4f + SO_DEVMEM_DONTNEED = 0x50 + SO_DEVMEM_LINEAR = 0x4e SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 SO_ERROR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index ad4b9aace7..4834e57514 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -112,12 +112,15 @@ const ( HIDIOCGRAWINFO = 0x40084803 HIDIOCGRDESC = 0x50044802 HIDIOCGRDESCSIZE = 0x40044801 + HIDIOCREVOKE = 0x8004480d HUPCL = 0x400 ICANON = 0x2 IEXTEN = 0x8000 IN_CLOEXEC = 0x400000 IN_NONBLOCK = 0x4000 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -155,9 +158,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 @@ -234,6 +242,20 @@ const ( PPPIOCUNBRIDGECHAN = 0x20007434 PPPIOCXFERUNIT = 0x2000744e PR_SET_PTRACER_ANY = 0xffffffffffffffff + PTP_CLOCK_GETCAPS = 0x40503d01 + PTP_CLOCK_GETCAPS2 = 0x40503d0a + PTP_ENABLE_PPS = 0x80043d04 + PTP_ENABLE_PPS2 = 0x80043d0d + PTP_EXTTS_REQUEST = 0x80103d02 + PTP_EXTTS_REQUEST2 = 0x80103d0b + PTP_MASK_CLEAR_ALL = 0x20003d13 + PTP_MASK_EN_SINGLE = 0x80043d14 + PTP_PEROUT_REQUEST = 0x80383d03 + PTP_PEROUT_REQUEST2 = 0x80383d0c + PTP_PIN_SETFUNC = 0x80603d07 + PTP_PIN_SETFUNC2 = 0x80603d10 + PTP_SYS_OFFSET = 0x83403d05 + PTP_SYS_OFFSET2 = 0x83403d0e PTRACE_GETFPAREGS = 0x14 PTRACE_GETFPREGS = 0xe PTRACE_GETFPREGS64 = 0x19 @@ -331,10 +353,13 @@ const ( RTC_WIE_ON = 0x2000700f RTC_WKALM_RD = 0x40287010 RTC_WKALM_SET = 0x8028700f + SCM_DEVMEM_DMABUF = 0x58 + SCM_DEVMEM_LINEAR = 0x57 SCM_TIMESTAMPING = 0x23 SCM_TIMESTAMPING_OPT_STATS = 0x38 SCM_TIMESTAMPING_PKTINFO = 0x3c SCM_TIMESTAMPNS = 0x21 + SCM_TS_OPT_ID = 0x5a SCM_TXTIME = 0x3f SCM_WIFI_STATUS = 0x25 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 @@ -417,6 +442,9 @@ const ( SO_CNX_ADVICE = 0x37 SO_COOKIE = 0x3b SO_DETACH_REUSEPORT_BPF = 0x47 + SO_DEVMEM_DMABUF = 0x58 + SO_DEVMEM_DONTNEED = 0x59 + SO_DEVMEM_LINEAR = 0x57 SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 SO_ERROR = 0x1007 diff --git a/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go index da08b2ab3d..1ec2b1407b 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go @@ -581,6 +581,8 @@ const ( AT_EMPTY_PATH = 0x1000 AT_REMOVEDIR = 0x200 RENAME_NOREPLACE = 1 << 0 + ST_RDONLY = 1 + ST_NOSUID = 2 ) const ( diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index b622533ef2..24b346e1a3 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -841,6 +841,26 @@ var libc_pthread_fchdir_np_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) { + var _p0 unsafe.Pointer + if len(iov) > 0 { + _p0 = unsafe.Pointer(&iov[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall_syscall9(libc_connectx_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(endpoints)), uintptr(associd), uintptr(flags), uintptr(_p0), uintptr(len(iov)), uintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(connid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_connectx_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_connectx connectx "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index cfe6646baf..ebd213100b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -248,6 +248,11 @@ TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) +TEXT libc_connectx_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_connectx(SB) +GLOBL ·libc_connectx_trampoline_addr(SB), RODATA, $8 +DATA ·libc_connectx_trampoline_addr(SB)/8, $libc_connectx_trampoline<>(SB) + TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 13f624f69f..824b9c2d5e 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -841,6 +841,26 @@ var libc_pthread_fchdir_np_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) { + var _p0 unsafe.Pointer + if len(iov) > 0 { + _p0 = unsafe.Pointer(&iov[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall_syscall9(libc_connectx_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(endpoints)), uintptr(associd), uintptr(flags), uintptr(_p0), uintptr(len(iov)), uintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(connid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_connectx_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_connectx connectx "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index fe222b75df..4f178a2293 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -248,6 +248,11 @@ TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) +TEXT libc_connectx_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_connectx(SB) +GLOBL ·libc_connectx_trampoline_addr(SB), RODATA, $8 +DATA ·libc_connectx_trampoline_addr(SB)/8, $libc_connectx_trampoline<>(SB) + TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 1bc1a5adb2..5cc1e8eb2f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -592,6 +592,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockSettime(clockid int32, time *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_SETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) if e1 != 0 { @@ -971,23 +981,6 @@ func Getpriority(which int, who int) (prio int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Getrandom(buf []byte, flags int) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_GETRANDOM, uintptr(_p0), uintptr(len(buf)), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getrusage(who int, rusage *Rusage) (err error) { _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go index 829b87feb8..c6545413c4 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go @@ -141,6 +141,16 @@ import ( //go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so" //go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so" //go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so" +//go:cgo_import_dynamic libc_getpeerucred getpeerucred "libc.so" +//go:cgo_import_dynamic libc_ucred_get ucred_get "libc.so" +//go:cgo_import_dynamic libc_ucred_geteuid ucred_geteuid "libc.so" +//go:cgo_import_dynamic libc_ucred_getegid ucred_getegid "libc.so" +//go:cgo_import_dynamic libc_ucred_getruid ucred_getruid "libc.so" +//go:cgo_import_dynamic libc_ucred_getrgid ucred_getrgid "libc.so" +//go:cgo_import_dynamic libc_ucred_getsuid ucred_getsuid "libc.so" +//go:cgo_import_dynamic libc_ucred_getsgid ucred_getsgid "libc.so" +//go:cgo_import_dynamic libc_ucred_getpid ucred_getpid "libc.so" +//go:cgo_import_dynamic libc_ucred_free ucred_free "libc.so" //go:cgo_import_dynamic libc_port_create port_create "libc.so" //go:cgo_import_dynamic libc_port_associate port_associate "libc.so" //go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so" @@ -280,6 +290,16 @@ import ( //go:linkname procgetpeername libc_getpeername //go:linkname procsetsockopt libc_setsockopt //go:linkname procrecvfrom libc_recvfrom +//go:linkname procgetpeerucred libc_getpeerucred +//go:linkname procucred_get libc_ucred_get +//go:linkname procucred_geteuid libc_ucred_geteuid +//go:linkname procucred_getegid libc_ucred_getegid +//go:linkname procucred_getruid libc_ucred_getruid +//go:linkname procucred_getrgid libc_ucred_getrgid +//go:linkname procucred_getsuid libc_ucred_getsuid +//go:linkname procucred_getsgid libc_ucred_getsgid +//go:linkname procucred_getpid libc_ucred_getpid +//go:linkname procucred_free libc_ucred_free //go:linkname procport_create libc_port_create //go:linkname procport_associate libc_port_associate //go:linkname procport_dissociate libc_port_dissociate @@ -420,6 +440,16 @@ var ( procgetpeername, procsetsockopt, procrecvfrom, + procgetpeerucred, + procucred_get, + procucred_geteuid, + procucred_getegid, + procucred_getruid, + procucred_getrgid, + procucred_getsuid, + procucred_getsgid, + procucred_getpid, + procucred_free, procport_create, procport_associate, procport_dissociate, @@ -2029,6 +2059,90 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func getpeerucred(fd uintptr, ucred *uintptr) (err error) { + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procgetpeerucred)), 2, uintptr(fd), uintptr(unsafe.Pointer(ucred)), 0, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGet(pid int) (ucred uintptr, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procucred_get)), 1, uintptr(pid), 0, 0, 0, 0, 0) + ucred = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGeteuid(ucred uintptr) (uid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_geteuid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetegid(ucred uintptr) (gid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getegid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetruid(ucred uintptr) (uid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getruid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetrgid(ucred uintptr) (gid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getrgid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetsuid(ucred uintptr) (uid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getsuid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetsgid(ucred uintptr) (gid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getsgid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetpid(ucred uintptr) (pid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getpid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredFree(ucred uintptr) { + sysvicall6(uintptr(unsafe.Pointer(&procucred_free)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func port_create() (n int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_create)), 0, 0, 0, 0, 0, 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index 524b0820cb..c79aaff306 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -458,4 +458,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index d3e38f681a..5eb450695e 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -341,6 +341,7 @@ const ( SYS_STATX = 332 SYS_IO_PGETEVENTS = 333 SYS_RSEQ = 334 + SYS_URETPROBE = 335 SYS_PIDFD_SEND_SIGNAL = 424 SYS_IO_URING_SETUP = 425 SYS_IO_URING_ENTER = 426 @@ -380,4 +381,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 70b35bf3b0..05e5029744 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -422,4 +422,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 6c778c2327..38c53ec51b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -85,7 +85,7 @@ const ( SYS_SPLICE = 76 SYS_TEE = 77 SYS_READLINKAT = 78 - SYS_FSTATAT = 79 + SYS_NEWFSTATAT = 79 SYS_FSTAT = 80 SYS_SYNC = 81 SYS_FSYNC = 82 @@ -325,4 +325,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index 37281cf51a..31d2e71a18 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -84,6 +84,8 @@ const ( SYS_SPLICE = 76 SYS_TEE = 77 SYS_READLINKAT = 78 + SYS_NEWFSTATAT = 79 + SYS_FSTAT = 80 SYS_SYNC = 81 SYS_FSYNC = 82 SYS_FDATASYNC = 83 @@ -319,4 +321,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 7e567f1eff..f4184a336b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -442,4 +442,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 4460 SYS_LSM_LIST_MODULES = 4461 SYS_MSEAL = 4462 + SYS_SETXATTRAT = 4463 + SYS_GETXATTRAT = 4464 + SYS_LISTXATTRAT = 4465 + SYS_REMOVEXATTRAT = 4466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 38ae55e5ef..05b9962278 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -372,4 +372,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 5460 SYS_LSM_LIST_MODULES = 5461 SYS_MSEAL = 5462 + SYS_SETXATTRAT = 5463 + SYS_GETXATTRAT = 5464 + SYS_LISTXATTRAT = 5465 + SYS_REMOVEXATTRAT = 5466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 55e92e60a8..43a256e9e6 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -372,4 +372,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 5460 SYS_LSM_LIST_MODULES = 5461 SYS_MSEAL = 5462 + SYS_SETXATTRAT = 5463 + SYS_GETXATTRAT = 5464 + SYS_LISTXATTRAT = 5465 + SYS_REMOVEXATTRAT = 5466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index 60658d6a02..eea5ddfc22 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -442,4 +442,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 4460 SYS_LSM_LIST_MODULES = 4461 SYS_MSEAL = 4462 + SYS_SETXATTRAT = 4463 + SYS_GETXATTRAT = 4464 + SYS_LISTXATTRAT = 4465 + SYS_REMOVEXATTRAT = 4466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index e203e8a7ed..0d777bfbb1 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -449,4 +449,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index 5944b97d54..b446365025 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -421,4 +421,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index c66d416dad..0c7d21c188 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -421,4 +421,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 9889f6a559..8405391698 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -84,7 +84,7 @@ const ( SYS_SPLICE = 76 SYS_TEE = 77 SYS_READLINKAT = 78 - SYS_FSTATAT = 79 + SYS_NEWFSTATAT = 79 SYS_FSTAT = 80 SYS_SYNC = 81 SYS_FSYNC = 82 @@ -326,4 +326,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 01d86825bb..fcf1b790d6 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -387,4 +387,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 7b703e77cd..52d15b5f9d 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -400,4 +400,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index 091d107f3a..17c53bd9b3 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -306,6 +306,19 @@ type XVSockPgen struct { type _Socklen uint32 +type SaeAssocID uint32 + +type SaeConnID uint32 + +type SaEndpoints struct { + Srcif uint32 + Srcaddr *RawSockaddr + Srcaddrlen uint32 + Dstaddr *RawSockaddr + Dstaddrlen uint32 + _ [4]byte +} + type Xucred struct { Version uint32 Uid uint32 @@ -449,11 +462,14 @@ type FdSet struct { const ( SizeofIfMsghdr = 0x70 + SizeofIfMsghdr2 = 0xa0 SizeofIfData = 0x60 + SizeofIfData64 = 0x80 SizeofIfaMsghdr = 0x14 SizeofIfmaMsghdr = 0x10 SizeofIfmaMsghdr2 = 0x14 SizeofRtMsghdr = 0x5c + SizeofRtMsghdr2 = 0x5c SizeofRtMetrics = 0x38 ) @@ -467,6 +483,20 @@ type IfMsghdr struct { Data IfData } +type IfMsghdr2 struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + Snd_len int32 + Snd_maxlen int32 + Snd_drops int32 + Timer int32 + Data IfData64 +} + type IfData struct { Type uint8 Typelen uint8 @@ -499,6 +529,34 @@ type IfData struct { Reserved2 uint32 } +type IfData64 struct { + Type uint8 + Typelen uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Recvquota uint8 + Xmitquota uint8 + Unused1 uint8 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Noproto uint64 + Recvtiming uint32 + Xmittiming uint32 + Lastchange Timeval32 +} + type IfaMsghdr struct { Msglen uint16 Version uint8 @@ -544,6 +602,21 @@ type RtMsghdr struct { Rmx RtMetrics } +type RtMsghdr2 struct { + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + Flags int32 + Addrs int32 + Refcnt int32 + Parentflags int32 + Reserved int32 + Use int32 + Inits uint32 + Rmx RtMetrics +} + type RtMetrics struct { Locks uint32 Mtu uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index 28ff4ef74d..2392226a74 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -306,6 +306,19 @@ type XVSockPgen struct { type _Socklen uint32 +type SaeAssocID uint32 + +type SaeConnID uint32 + +type SaEndpoints struct { + Srcif uint32 + Srcaddr *RawSockaddr + Srcaddrlen uint32 + Dstaddr *RawSockaddr + Dstaddrlen uint32 + _ [4]byte +} + type Xucred struct { Version uint32 Uid uint32 @@ -449,11 +462,14 @@ type FdSet struct { const ( SizeofIfMsghdr = 0x70 + SizeofIfMsghdr2 = 0xa0 SizeofIfData = 0x60 + SizeofIfData64 = 0x80 SizeofIfaMsghdr = 0x14 SizeofIfmaMsghdr = 0x10 SizeofIfmaMsghdr2 = 0x14 SizeofRtMsghdr = 0x5c + SizeofRtMsghdr2 = 0x5c SizeofRtMetrics = 0x38 ) @@ -467,6 +483,20 @@ type IfMsghdr struct { Data IfData } +type IfMsghdr2 struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + Snd_len int32 + Snd_maxlen int32 + Snd_drops int32 + Timer int32 + Data IfData64 +} + type IfData struct { Type uint8 Typelen uint8 @@ -499,6 +529,34 @@ type IfData struct { Reserved2 uint32 } +type IfData64 struct { + Type uint8 + Typelen uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Recvquota uint8 + Xmitquota uint8 + Unused1 uint8 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Noproto uint64 + Recvtiming uint32 + Xmittiming uint32 + Lastchange Timeval32 +} + type IfaMsghdr struct { Msglen uint16 Version uint8 @@ -544,6 +602,21 @@ type RtMsghdr struct { Rmx RtMetrics } +type RtMsghdr2 struct { + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + Flags int32 + Addrs int32 + Refcnt int32 + Parentflags int32 + Reserved int32 + Use int32 + Inits uint32 + Rmx RtMetrics +} + type RtMetrics struct { Locks uint32 Mtu uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go index 6cbd094a3a..51e13eb055 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go @@ -625,6 +625,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go index 7c03b6ee77..d002d8ef3c 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go @@ -630,6 +630,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go index 422107ee8b..3f863d898d 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go @@ -616,6 +616,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go index 505a12acfd..61c7293106 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go @@ -610,6 +610,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go index cc986c7900..b5d17414f0 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go @@ -612,6 +612,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index 7f1961b907..a46abe6472 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -87,31 +87,35 @@ type StatxTimestamp struct { } type Statx_t struct { - Mask uint32 - Blksize uint32 - Attributes uint64 - Nlink uint32 - Uid uint32 - Gid uint32 - Mode uint16 - _ [1]uint16 - Ino uint64 - Size uint64 - Blocks uint64 - Attributes_mask uint64 - Atime StatxTimestamp - Btime StatxTimestamp - Ctime StatxTimestamp - Mtime StatxTimestamp - Rdev_major uint32 - Rdev_minor uint32 - Dev_major uint32 - Dev_minor uint32 - Mnt_id uint64 - Dio_mem_align uint32 - Dio_offset_align uint32 - Subvol uint64 - _ [11]uint64 + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + Mnt_id uint64 + Dio_mem_align uint32 + Dio_offset_align uint32 + Subvol uint64 + Atomic_write_unit_min uint32 + Atomic_write_unit_max uint32 + Atomic_write_segments_max uint32 + _ [1]uint32 + _ [9]uint64 } type Fsid struct { @@ -516,6 +520,29 @@ type TCPInfo struct { Total_rto_time uint32 } +type TCPVegasInfo struct { + Enabled uint32 + Rttcnt uint32 + Rtt uint32 + Minrtt uint32 +} + +type TCPDCTCPInfo struct { + Enabled uint16 + Ce_state uint16 + Alpha uint32 + Ab_ecn uint32 + Ab_tot uint32 +} + +type TCPBBRInfo struct { + Bw_lo uint32 + Bw_hi uint32 + Min_rtt uint32 + Pacing_gain uint32 + Cwnd_gain uint32 +} + type CanFilter struct { Id uint32 Mask uint32 @@ -557,6 +584,7 @@ const ( SizeofICMPv6Filter = 0x20 SizeofUcred = 0xc SizeofTCPInfo = 0xf8 + SizeofTCPCCInfo = 0x14 SizeofCanFilter = 0x8 SizeofTCPRepairOpt = 0x8 ) @@ -1724,12 +1752,6 @@ const ( IFLA_IPVLAN_UNSPEC = 0x0 IFLA_IPVLAN_MODE = 0x1 IFLA_IPVLAN_FLAGS = 0x2 - NETKIT_NEXT = -0x1 - NETKIT_PASS = 0x0 - NETKIT_DROP = 0x2 - NETKIT_REDIRECT = 0x7 - NETKIT_L2 = 0x0 - NETKIT_L3 = 0x1 IFLA_NETKIT_UNSPEC = 0x0 IFLA_NETKIT_PEER_INFO = 0x1 IFLA_NETKIT_PRIMARY = 0x2 @@ -1768,6 +1790,7 @@ const ( IFLA_VXLAN_DF = 0x1d IFLA_VXLAN_VNIFILTER = 0x1e IFLA_VXLAN_LOCALBYPASS = 0x1f + IFLA_VXLAN_LABEL_POLICY = 0x20 IFLA_GENEVE_UNSPEC = 0x0 IFLA_GENEVE_ID = 0x1 IFLA_GENEVE_REMOTE = 0x2 @@ -1797,6 +1820,8 @@ const ( IFLA_GTP_ROLE = 0x4 IFLA_GTP_CREATE_SOCKETS = 0x5 IFLA_GTP_RESTART_COUNT = 0x6 + IFLA_GTP_LOCAL = 0x7 + IFLA_GTP_LOCAL6 = 0x8 IFLA_BOND_UNSPEC = 0x0 IFLA_BOND_MODE = 0x1 IFLA_BOND_ACTIVE_SLAVE = 0x2 @@ -1829,6 +1854,7 @@ const ( IFLA_BOND_AD_LACP_ACTIVE = 0x1d IFLA_BOND_MISSED_MAX = 0x1e IFLA_BOND_NS_IP6_TARGET = 0x1f + IFLA_BOND_COUPLED_CONTROL = 0x20 IFLA_BOND_AD_INFO_UNSPEC = 0x0 IFLA_BOND_AD_INFO_AGGREGATOR = 0x1 IFLA_BOND_AD_INFO_NUM_PORTS = 0x2 @@ -1897,6 +1923,7 @@ const ( IFLA_HSR_SEQ_NR = 0x5 IFLA_HSR_VERSION = 0x6 IFLA_HSR_PROTOCOL = 0x7 + IFLA_HSR_INTERLINK = 0x8 IFLA_STATS_UNSPEC = 0x0 IFLA_STATS_LINK_64 = 0x1 IFLA_STATS_LINK_XSTATS = 0x2 @@ -1949,6 +1976,15 @@ const ( IFLA_DSA_MASTER = 0x1 ) +const ( + NETKIT_NEXT = -0x1 + NETKIT_PASS = 0x0 + NETKIT_DROP = 0x2 + NETKIT_REDIRECT = 0x7 + NETKIT_L2 = 0x0 + NETKIT_L3 = 0x1 +) + const ( NF_INET_PRE_ROUTING = 0x0 NF_INET_LOCAL_IN = 0x1 @@ -2486,7 +2522,7 @@ type XDPMmapOffsets struct { type XDPUmemReg struct { Addr uint64 Len uint64 - Chunk_size uint32 + Size uint32 Headroom uint32 Flags uint32 Tx_metadata_len uint32 @@ -2558,8 +2594,8 @@ const ( SOF_TIMESTAMPING_BIND_PHC = 0x8000 SOF_TIMESTAMPING_OPT_ID_TCP = 0x10000 - SOF_TIMESTAMPING_LAST = 0x10000 - SOF_TIMESTAMPING_MASK = 0x1ffff + SOF_TIMESTAMPING_LAST = 0x20000 + SOF_TIMESTAMPING_MASK = 0x3ffff SCM_TSTAMP_SND = 0x0 SCM_TSTAMP_SCHED = 0x1 @@ -3505,7 +3541,7 @@ type Nhmsg struct { type NexthopGrp struct { Id uint32 Weight uint8 - Resvd1 uint8 + High uint8 Resvd2 uint16 } @@ -3766,7 +3802,7 @@ const ( ETHTOOL_MSG_PSE_GET = 0x24 ETHTOOL_MSG_PSE_SET = 0x25 ETHTOOL_MSG_RSS_GET = 0x26 - ETHTOOL_MSG_USER_MAX = 0x2b + ETHTOOL_MSG_USER_MAX = 0x2d ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 @@ -3806,7 +3842,7 @@ const ( ETHTOOL_MSG_MODULE_NTF = 0x24 ETHTOOL_MSG_PSE_GET_REPLY = 0x25 ETHTOOL_MSG_RSS_GET_REPLY = 0x26 - ETHTOOL_MSG_KERNEL_MAX = 0x2b + ETHTOOL_MSG_KERNEL_MAX = 0x2e ETHTOOL_FLAG_COMPACT_BITSETS = 0x1 ETHTOOL_FLAG_OMIT_REPLY = 0x2 ETHTOOL_FLAG_STATS = 0x4 @@ -3814,7 +3850,7 @@ const ( ETHTOOL_A_HEADER_DEV_INDEX = 0x1 ETHTOOL_A_HEADER_DEV_NAME = 0x2 ETHTOOL_A_HEADER_FLAGS = 0x3 - ETHTOOL_A_HEADER_MAX = 0x3 + ETHTOOL_A_HEADER_MAX = 0x4 ETHTOOL_A_BITSET_BIT_UNSPEC = 0x0 ETHTOOL_A_BITSET_BIT_INDEX = 0x1 ETHTOOL_A_BITSET_BIT_NAME = 0x2 @@ -3951,7 +3987,7 @@ const ( ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17 ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18 ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19 - ETHTOOL_A_COALESCE_MAX = 0x1c + ETHTOOL_A_COALESCE_MAX = 0x1e ETHTOOL_A_PAUSE_UNSPEC = 0x0 ETHTOOL_A_PAUSE_HEADER = 0x1 ETHTOOL_A_PAUSE_AUTONEG = 0x2 @@ -3995,11 +4031,11 @@ const ( ETHTOOL_A_CABLE_RESULT_UNSPEC = 0x0 ETHTOOL_A_CABLE_RESULT_PAIR = 0x1 ETHTOOL_A_CABLE_RESULT_CODE = 0x2 - ETHTOOL_A_CABLE_RESULT_MAX = 0x2 + ETHTOOL_A_CABLE_RESULT_MAX = 0x3 ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC = 0x0 ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR = 0x1 ETHTOOL_A_CABLE_FAULT_LENGTH_CM = 0x2 - ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = 0x2 + ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = 0x3 ETHTOOL_A_CABLE_TEST_NTF_STATUS_UNSPEC = 0x0 ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED = 0x1 ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED = 0x2 @@ -4082,6 +4118,107 @@ type EthtoolDrvinfo struct { Regdump_len uint32 } +type EthtoolTsInfo struct { + Cmd uint32 + So_timestamping uint32 + Phc_index int32 + Tx_types uint32 + Tx_reserved [3]uint32 + Rx_filters uint32 + Rx_reserved [3]uint32 +} + +type HwTstampConfig struct { + Flags int32 + Tx_type int32 + Rx_filter int32 +} + +const ( + HWTSTAMP_FILTER_NONE = 0x0 + HWTSTAMP_FILTER_ALL = 0x1 + HWTSTAMP_FILTER_SOME = 0x2 + HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 0x3 + HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 0x6 + HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 0x9 + HWTSTAMP_FILTER_PTP_V2_EVENT = 0xc +) + +const ( + HWTSTAMP_TX_OFF = 0x0 + HWTSTAMP_TX_ON = 0x1 + HWTSTAMP_TX_ONESTEP_SYNC = 0x2 +) + +type ( + PtpClockCaps struct { + Max_adj int32 + N_alarm int32 + N_ext_ts int32 + N_per_out int32 + Pps int32 + N_pins int32 + Cross_timestamping int32 + Adjust_phase int32 + Max_phase_adj int32 + Rsv [11]int32 + } + PtpClockTime struct { + Sec int64 + Nsec uint32 + Reserved uint32 + } + PtpExttsEvent struct { + T PtpClockTime + Index uint32 + Flags uint32 + Rsv [2]uint32 + } + PtpExttsRequest struct { + Index uint32 + Flags uint32 + Rsv [2]uint32 + } + PtpPeroutRequest struct { + StartOrPhase PtpClockTime + Period PtpClockTime + Index uint32 + Flags uint32 + On PtpClockTime + } + PtpPinDesc struct { + Name [64]byte + Index uint32 + Func uint32 + Chan uint32 + Rsv [5]uint32 + } + PtpSysOffset struct { + Samples uint32 + Rsv [3]uint32 + Ts [51]PtpClockTime + } + PtpSysOffsetExtended struct { + Samples uint32 + Clockid int32 + Rsv [2]uint32 + Ts [25][3]PtpClockTime + } + PtpSysOffsetPrecise struct { + Device PtpClockTime + Realtime PtpClockTime + Monoraw PtpClockTime + Rsv [4]uint32 + } +) + +const ( + PTP_PF_NONE = 0x0 + PTP_PF_EXTTS = 0x1 + PTP_PF_PEROUT = 0x2 + PTP_PF_PHYSYNC = 0x3 +) + type ( HIDRawReportDescriptor struct { Size uint32 @@ -4263,6 +4400,7 @@ const ( type LandlockRulesetAttr struct { Access_fs uint64 Access_net uint64 + Scoped uint64 } type LandlockPathBeneathAttr struct { @@ -4609,7 +4747,7 @@ const ( NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca - NL80211_ATTR_MAX = 0x14a + NL80211_ATTR_MAX = 0x14d NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CSA_COUNTERS = 0xce NL80211_ATTR_MAX_MATCH_SETS = 0x85 @@ -5213,7 +5351,7 @@ const ( NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf - NL80211_FREQUENCY_ATTR_MAX = 0x20 + NL80211_FREQUENCY_ATTR_MAX = 0x21 NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc @@ -5381,7 +5519,7 @@ const ( NL80211_MNTR_FLAG_CONTROL = 0x3 NL80211_MNTR_FLAG_COOK_FRAMES = 0x5 NL80211_MNTR_FLAG_FCSFAIL = 0x1 - NL80211_MNTR_FLAG_MAX = 0x6 + NL80211_MNTR_FLAG_MAX = 0x7 NL80211_MNTR_FLAG_OTHER_BSS = 0x4 NL80211_MNTR_FLAG_PLCPFAIL = 0x2 NL80211_MPATH_FLAG_ACTIVE = 0x1 @@ -6036,3 +6174,5 @@ type SockDiagReq struct { Family uint8 Protocol uint8 } + +const RTM_NEWNVLAN = 0x70 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index 15adc04142..ad05b51a60 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -727,6 +727,37 @@ const ( RISCV_HWPROBE_EXT_ZBA = 0x8 RISCV_HWPROBE_EXT_ZBB = 0x10 RISCV_HWPROBE_EXT_ZBS = 0x20 + RISCV_HWPROBE_EXT_ZICBOZ = 0x40 + RISCV_HWPROBE_EXT_ZBC = 0x80 + RISCV_HWPROBE_EXT_ZBKB = 0x100 + RISCV_HWPROBE_EXT_ZBKC = 0x200 + RISCV_HWPROBE_EXT_ZBKX = 0x400 + RISCV_HWPROBE_EXT_ZKND = 0x800 + RISCV_HWPROBE_EXT_ZKNE = 0x1000 + RISCV_HWPROBE_EXT_ZKNH = 0x2000 + RISCV_HWPROBE_EXT_ZKSED = 0x4000 + RISCV_HWPROBE_EXT_ZKSH = 0x8000 + RISCV_HWPROBE_EXT_ZKT = 0x10000 + RISCV_HWPROBE_EXT_ZVBB = 0x20000 + RISCV_HWPROBE_EXT_ZVBC = 0x40000 + RISCV_HWPROBE_EXT_ZVKB = 0x80000 + RISCV_HWPROBE_EXT_ZVKG = 0x100000 + RISCV_HWPROBE_EXT_ZVKNED = 0x200000 + RISCV_HWPROBE_EXT_ZVKNHA = 0x400000 + RISCV_HWPROBE_EXT_ZVKNHB = 0x800000 + RISCV_HWPROBE_EXT_ZVKSED = 0x1000000 + RISCV_HWPROBE_EXT_ZVKSH = 0x2000000 + RISCV_HWPROBE_EXT_ZVKT = 0x4000000 + RISCV_HWPROBE_EXT_ZFH = 0x8000000 + RISCV_HWPROBE_EXT_ZFHMIN = 0x10000000 + RISCV_HWPROBE_EXT_ZIHINTNTL = 0x20000000 + RISCV_HWPROBE_EXT_ZVFH = 0x40000000 + RISCV_HWPROBE_EXT_ZVFHMIN = 0x80000000 + RISCV_HWPROBE_EXT_ZFA = 0x100000000 + RISCV_HWPROBE_EXT_ZTSO = 0x200000000 + RISCV_HWPROBE_EXT_ZACAS = 0x400000000 + RISCV_HWPROBE_EXT_ZICOND = 0x800000000 + RISCV_HWPROBE_EXT_ZIHINTPAUSE = 0x1000000000 RISCV_HWPROBE_KEY_CPUPERF_0 = 0x5 RISCV_HWPROBE_MISALIGNED_UNKNOWN = 0x0 RISCV_HWPROBE_MISALIGNED_EMULATED = 0x1 @@ -734,4 +765,6 @@ const ( RISCV_HWPROBE_MISALIGNED_FAST = 0x3 RISCV_HWPROBE_MISALIGNED_UNSUPPORTED = 0x4 RISCV_HWPROBE_MISALIGNED_MASK = 0x7 + RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE = 0x6 + RISCV_HWPROBE_WHICH_CPUS = 0x1 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go index d9a13af468..2e5d5a4435 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go @@ -377,6 +377,12 @@ type Flock_t struct { Pid int32 } +type F_cnvrt struct { + Cvtcmd int32 + Pccsid int16 + Fccsid int16 +} + type Termios struct { Cflag uint32 Iflag uint32 diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go index 115341fba6..3ca814f54d 100644 --- a/vendor/golang.org/x/sys/windows/dll_windows.go +++ b/vendor/golang.org/x/sys/windows/dll_windows.go @@ -43,8 +43,8 @@ type DLL struct { // LoadDLL loads DLL file into memory. // // Warning: using LoadDLL without an absolute path name is subject to -// DLL preloading attacks. To safely load a system DLL, use LazyDLL -// with System set to true, or use LoadLibraryEx directly. +// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL], +// or use [LoadLibraryEx] directly. func LoadDLL(name string) (dll *DLL, err error) { namep, err := UTF16PtrFromString(name) if err != nil { @@ -65,7 +65,7 @@ func LoadDLL(name string) (dll *DLL, err error) { return d, nil } -// MustLoadDLL is like LoadDLL but panics if load operation failes. +// MustLoadDLL is like LoadDLL but panics if load operation fails. func MustLoadDLL(name string) *DLL { d, e := LoadDLL(name) if e != nil { @@ -271,6 +271,9 @@ func (d *LazyDLL) NewProc(name string) *LazyProc { } // NewLazyDLL creates new LazyDLL associated with DLL file. +// +// Warning: using NewLazyDLL without an absolute path name is subject to +// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL]. func NewLazyDLL(name string) *LazyDLL { return &LazyDLL{Name: name} } @@ -410,7 +413,3 @@ func loadLibraryEx(name string, system bool) (*DLL, error) { } return &DLL{Name: name, Handle: h}, nil } - -type errString string - -func (s errString) Error() string { return string(s) } diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 1fa34fd17c..4a32543868 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -168,6 +168,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW //sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) //sys DisconnectNamedPipe(pipe Handle) (err error) +//sys GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error) +//sys GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error) //sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) //sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState @@ -313,6 +315,10 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode //sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo //sys setConsoleCursorPosition(console Handle, position uint32) (err error) = kernel32.SetConsoleCursorPosition +//sys GetConsoleCP() (cp uint32, err error) = kernel32.GetConsoleCP +//sys GetConsoleOutputCP() (cp uint32, err error) = kernel32.GetConsoleOutputCP +//sys SetConsoleCP(cp uint32) (err error) = kernel32.SetConsoleCP +//sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP //sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW //sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW //sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole @@ -721,20 +727,12 @@ func DurationSinceBoot() time.Duration { } func Ftruncate(fd Handle, length int64) (err error) { - curoffset, e := Seek(fd, 0, 1) - if e != nil { - return e - } - defer Seek(fd, curoffset, 0) - _, e = Seek(fd, length, 0) - if e != nil { - return e + type _FILE_END_OF_FILE_INFO struct { + EndOfFile int64 } - e = SetEndOfFile(fd) - if e != nil { - return e - } - return nil + var info _FILE_END_OF_FILE_INFO + info.EndOfFile = length + return SetFileInformationByHandle(fd, FileEndOfFileInfo, (*byte)(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info))) } func Gettimeofday(tv *Timeval) (err error) { @@ -890,6 +888,11 @@ const socket_error = uintptr(^uint32(0)) //sys GetACP() (acp uint32) = kernel32.GetACP //sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar //sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx +//sys GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex +//sys GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry +//sys NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange +//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange +//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2 // For testing: clients can set this flag to force // creation of IPv6 sockets to return EAFNOSUPPORT. @@ -1681,13 +1684,16 @@ func (s NTStatus) Error() string { // do not use NTUnicodeString, and instead UTF16PtrFromString should be used for // the more common *uint16 string type. func NewNTUnicodeString(s string) (*NTUnicodeString, error) { - var u NTUnicodeString - s16, err := UTF16PtrFromString(s) + s16, err := UTF16FromString(s) if err != nil { return nil, err } - RtlInitUnicodeString(&u, s16) - return &u, nil + n := uint16(len(s16) * 2) + return &NTUnicodeString{ + Length: n - 2, // subtract 2 bytes for the NULL terminator + MaximumLength: n, + Buffer: &s16[0], + }, nil } // Slice returns a uint16 slice that aliases the data in the NTUnicodeString. diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 3f03b3d57c..9d138de5fe 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -176,6 +176,7 @@ const ( WAIT_FAILED = 0xFFFFFFFF // Access rights for process. + PROCESS_ALL_ACCESS = 0xFFFF PROCESS_CREATE_PROCESS = 0x0080 PROCESS_CREATE_THREAD = 0x0002 PROCESS_DUP_HANDLE = 0x0040 @@ -1060,6 +1061,7 @@ const ( SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 + SIO_UDP_NETRESET = IOC_IN | IOC_VENDOR | 15 // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 @@ -2202,6 +2204,132 @@ const ( IfOperStatusLowerLayerDown = 7 ) +const ( + IF_MAX_PHYS_ADDRESS_LENGTH = 32 + IF_MAX_STRING_SIZE = 256 +) + +// MIB_IF_ENTRY_LEVEL enumeration from netioapi.h or +// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-getifentry2ex. +const ( + MibIfEntryNormal = 0 + MibIfEntryNormalWithoutStatistics = 2 +) + +// MIB_NOTIFICATION_TYPE enumeration from netioapi.h or +// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ne-netioapi-mib_notification_type. +const ( + MibParameterNotification = 0 + MibAddInstance = 1 + MibDeleteInstance = 2 + MibInitialNotification = 3 +) + +// MibIfRow2 stores information about a particular interface. See +// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_if_row2. +type MibIfRow2 struct { + InterfaceLuid uint64 + InterfaceIndex uint32 + InterfaceGuid GUID + Alias [IF_MAX_STRING_SIZE + 1]uint16 + Description [IF_MAX_STRING_SIZE + 1]uint16 + PhysicalAddressLength uint32 + PhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8 + PermanentPhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8 + Mtu uint32 + Type uint32 + TunnelType uint32 + MediaType uint32 + PhysicalMediumType uint32 + AccessType uint32 + DirectionType uint32 + InterfaceAndOperStatusFlags uint8 + OperStatus uint32 + AdminStatus uint32 + MediaConnectState uint32 + NetworkGuid GUID + ConnectionType uint32 + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + InOctets uint64 + InUcastPkts uint64 + InNUcastPkts uint64 + InDiscards uint64 + InErrors uint64 + InUnknownProtos uint64 + InUcastOctets uint64 + InMulticastOctets uint64 + InBroadcastOctets uint64 + OutOctets uint64 + OutUcastPkts uint64 + OutNUcastPkts uint64 + OutDiscards uint64 + OutErrors uint64 + OutUcastOctets uint64 + OutMulticastOctets uint64 + OutBroadcastOctets uint64 + OutQLen uint64 +} + +// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See +// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row. +type MibUnicastIpAddressRow struct { + Address RawSockaddrInet6 // SOCKADDR_INET union + InterfaceLuid uint64 + InterfaceIndex uint32 + PrefixOrigin uint32 + SuffixOrigin uint32 + ValidLifetime uint32 + PreferredLifetime uint32 + OnLinkPrefixLength uint8 + SkipAsSource uint8 + DadState uint32 + ScopeId uint32 + CreationTimeStamp Filetime +} + +const ScopeLevelCount = 16 + +// MIB_IPINTERFACE_ROW stores interface management information for a particular IP address family on a network interface. +// See https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipinterface_row. +type MibIpInterfaceRow struct { + Family uint16 + InterfaceLuid uint64 + InterfaceIndex uint32 + MaxReassemblySize uint32 + InterfaceIdentifier uint64 + MinRouterAdvertisementInterval uint32 + MaxRouterAdvertisementInterval uint32 + AdvertisingEnabled uint8 + ForwardingEnabled uint8 + WeakHostSend uint8 + WeakHostReceive uint8 + UseAutomaticMetric uint8 + UseNeighborUnreachabilityDetection uint8 + ManagedAddressConfigurationSupported uint8 + OtherStatefulConfigurationSupported uint8 + AdvertiseDefaultRoute uint8 + RouterDiscoveryBehavior uint32 + DadTransmits uint32 + BaseReachableTime uint32 + RetransmitTime uint32 + PathMtuDiscoveryTimeout uint32 + LinkLocalAddressBehavior uint32 + LinkLocalAddressTimeout uint32 + ZoneIndices [ScopeLevelCount]uint32 + SitePrefixLength uint32 + Metric uint32 + NlMtu uint32 + Connected uint8 + SupportsWakeUpPatterns uint8 + SupportsNeighborDiscovery uint8 + SupportsRouterDiscovery uint8 + ReachableTime uint32 + TransmitOffload uint32 + ReceiveOffload uint32 + DisableDefaultRoutes uint8 +} + // Console related constants used for the mode parameter to SetConsoleMode. See // https://docs.microsoft.com/en-us/windows/console/setconsolemode for details. diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 9bb979a3e4..01c0716c2c 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -181,10 +181,15 @@ var ( procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute") procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute") + procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2") procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx") procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") + procGetIfEntry2Ex = modiphlpapi.NewProc("GetIfEntry2Ex") + procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry") + procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange") + procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange") procAddDllDirectory = modkernel32.NewProc("AddDllDirectory") procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject") procCancelIo = modkernel32.NewProc("CancelIo") @@ -247,7 +252,9 @@ var ( procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") + procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") + procGetConsoleOutputCP = modkernel32.NewProc("GetConsoleOutputCP") procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo") procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") @@ -273,8 +280,10 @@ var ( procGetMaximumProcessorCount = modkernel32.NewProc("GetMaximumProcessorCount") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") procGetModuleHandleExW = modkernel32.NewProc("GetModuleHandleExW") + procGetNamedPipeClientProcessId = modkernel32.NewProc("GetNamedPipeClientProcessId") procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") + procGetNamedPipeServerProcessId = modkernel32.NewProc("GetNamedPipeServerProcessId") procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procGetPriorityClass = modkernel32.NewProc("GetPriorityClass") procGetProcAddress = modkernel32.NewProc("GetProcAddress") @@ -347,8 +356,10 @@ var ( procSetCommMask = modkernel32.NewProc("SetCommMask") procSetCommState = modkernel32.NewProc("SetCommState") procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") + procSetConsoleCP = modkernel32.NewProc("SetConsoleCP") procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition") procSetConsoleMode = modkernel32.NewProc("SetConsoleMode") + procSetConsoleOutputCP = modkernel32.NewProc("SetConsoleOutputCP") procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") @@ -1602,6 +1613,14 @@ func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, si return } +func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) { + r0, _, _ := syscall.Syscall(procCancelMibChangeNotify2.Addr(), 1, uintptr(notificationHandle), 0, 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) if r0 != 0 { @@ -1634,6 +1653,46 @@ func GetIfEntry(pIfRow *MibIfRow) (errcode error) { return } +func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) { + r0, _, _ := syscall.Syscall(procGetIfEntry2Ex.Addr(), 2, uintptr(level), uintptr(unsafe.Pointer(row)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) { + r0, _, _ := syscall.Syscall(procGetUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) { + var _p0 uint32 + if initialNotification { + _p0 = 1 + } + r0, _, _ := syscall.Syscall6(procNotifyIpInterfaceChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) { + var _p0 uint32 + if initialNotification { + _p0 = 1 + } + r0, _, _ := syscall.Syscall6(procNotifyUnicastIpAddressChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + func AddDllDirectory(path *uint16) (cookie uintptr, err error) { r0, _, e1 := syscall.Syscall(procAddDllDirectory.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) cookie = uintptr(r0) @@ -2162,6 +2221,15 @@ func GetComputerName(buf *uint16, n *uint32) (err error) { return } +func GetConsoleCP() (cp uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0) + cp = uint32(r0) + if cp == 0 { + err = errnoErr(e1) + } + return +} + func GetConsoleMode(console Handle, mode *uint32) (err error) { r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) if r1 == 0 { @@ -2170,6 +2238,15 @@ func GetConsoleMode(console Handle, mode *uint32) (err error) { return } +func GetConsoleOutputCP() (cp uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetConsoleOutputCP.Addr(), 0, 0, 0, 0) + cp = uint32(r0) + if cp == 0 { + err = errnoErr(e1) + } + return +} + func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) { r1, _, e1 := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(info)), 0) if r1 == 0 { @@ -2371,6 +2448,14 @@ func GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err er return } +func GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetNamedPipeClientProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(clientProcessID)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) if r1 == 0 { @@ -2387,6 +2472,14 @@ func GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint3 return } +func GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetNamedPipeServerProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(serverProcessID)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) { var _p0 uint32 if wait { @@ -3038,6 +3131,14 @@ func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { return } +func SetConsoleCP(cp uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetConsoleCP.Addr(), 1, uintptr(cp), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func setConsoleCursorPosition(console Handle, position uint32) (err error) { r1, _, e1 := syscall.Syscall(procSetConsoleCursorPosition.Addr(), 2, uintptr(console), uintptr(position), 0) if r1 == 0 { @@ -3054,6 +3155,14 @@ func SetConsoleMode(console Handle, mode uint32) (err error) { return } +func SetConsoleOutputCP(cp uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetConsoleOutputCP.Addr(), 1, uintptr(cp), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SetCurrentDirectory(path *uint16) (err error) { r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) if r1 == 0 { diff --git a/vendor/golang.org/x/term/CONTRIBUTING.md b/vendor/golang.org/x/term/CONTRIBUTING.md deleted file mode 100644 index d0485e887a..0000000000 --- a/vendor/golang.org/x/term/CONTRIBUTING.md +++ /dev/null @@ -1,26 +0,0 @@ -# Contributing to Go - -Go is an open source project. - -It is the work of hundreds of contributors. We appreciate your help! - -## Filing issues - -When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: - -1. What version of Go are you using (`go version`)? -2. What operating system and processor architecture are you using? -3. What did you do? -4. What did you expect to see? -5. What did you see instead? - -General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. -The gophers there will answer or ask you to file an issue if you've tripped over a bug. - -## Contributing code - -Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) -before sending patches. - -Unless otherwise noted, the Go source files are distributed under -the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/term/LICENSE b/vendor/golang.org/x/term/LICENSE deleted file mode 100644 index 2a7cf70da6..0000000000 --- a/vendor/golang.org/x/term/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2009 The Go Authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google LLC nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/term/PATENTS b/vendor/golang.org/x/term/PATENTS deleted file mode 100644 index 733099041f..0000000000 --- a/vendor/golang.org/x/term/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/term/README.md b/vendor/golang.org/x/term/README.md deleted file mode 100644 index d03d0aefef..0000000000 --- a/vendor/golang.org/x/term/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Go terminal/console support - -[![Go Reference](https://pkg.go.dev/badge/golang.org/x/term.svg)](https://pkg.go.dev/golang.org/x/term) - -This repository provides Go terminal and console support packages. - -## Download/Install - -The easiest way to install is to run `go get -u golang.org/x/term`. You can -also manually git clone the repository to `$GOPATH/src/golang.org/x/term`. - -## Report Issues / Send Patches - -This repository uses Gerrit for code changes. To learn how to submit changes to -this repository, see https://golang.org/doc/contribute.html. - -The main issue tracker for the term repository is located at -https://github.com/golang/go/issues. Prefix your issue with "x/term:" in the -subject line, so it is easy to find. diff --git a/vendor/golang.org/x/term/codereview.cfg b/vendor/golang.org/x/term/codereview.cfg deleted file mode 100644 index 3f8b14b64e..0000000000 --- a/vendor/golang.org/x/term/codereview.cfg +++ /dev/null @@ -1 +0,0 @@ -issuerepo: golang/go diff --git a/vendor/golang.org/x/term/term.go b/vendor/golang.org/x/term/term.go deleted file mode 100644 index 1a40d10125..0000000000 --- a/vendor/golang.org/x/term/term.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package term provides support functions for dealing with terminals, as -// commonly found on UNIX systems. -// -// Putting a terminal into raw mode is the most common requirement: -// -// oldState, err := term.MakeRaw(int(os.Stdin.Fd())) -// if err != nil { -// panic(err) -// } -// defer term.Restore(int(os.Stdin.Fd()), oldState) -// -// Note that on non-Unix systems os.Stdin.Fd() may not be 0. -package term - -// State contains the state of a terminal. -type State struct { - state -} - -// IsTerminal returns whether the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - return isTerminal(fd) -} - -// MakeRaw puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd int) (*State, error) { - return makeRaw(fd) -} - -// GetState returns the current state of a terminal which may be useful to -// restore the terminal after a signal. -func GetState(fd int) (*State, error) { - return getState(fd) -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func Restore(fd int, oldState *State) error { - return restore(fd, oldState) -} - -// GetSize returns the visible dimensions of the given terminal. -// -// These dimensions don't include any scrollback buffer height. -func GetSize(fd int) (width, height int, err error) { - return getSize(fd) -} - -// ReadPassword reads a line of input from a terminal without local echo. This -// is commonly used for inputting passwords and other sensitive data. The slice -// returned does not include the \n. -func ReadPassword(fd int) ([]byte, error) { - return readPassword(fd) -} diff --git a/vendor/golang.org/x/term/term_plan9.go b/vendor/golang.org/x/term/term_plan9.go deleted file mode 100644 index 21afa55cdb..0000000000 --- a/vendor/golang.org/x/term/term_plan9.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package term - -import ( - "fmt" - "runtime" - - "golang.org/x/sys/plan9" -) - -type state struct{} - -func isTerminal(fd int) bool { - path, err := plan9.Fd2path(fd) - if err != nil { - return false - } - return path == "/dev/cons" || path == "/mnt/term/dev/cons" -} - -func makeRaw(fd int) (*State, error) { - return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func getState(fd int) (*State, error) { - return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func restore(fd int, state *State) error { - return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func getSize(fd int) (width, height int, err error) { - return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func readPassword(fd int) ([]byte, error) { - return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff --git a/vendor/golang.org/x/term/term_unix.go b/vendor/golang.org/x/term/term_unix.go deleted file mode 100644 index 1ad0ddfe30..0000000000 --- a/vendor/golang.org/x/term/term_unix.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos - -package term - -import ( - "golang.org/x/sys/unix" -) - -type state struct { - termios unix.Termios -} - -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - return err == nil -} - -func makeRaw(fd int) (*State, error) { - termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - if err != nil { - return nil, err - } - - oldState := State{state{termios: *termios}} - - // This attempts to replicate the behaviour documented for cfmakeraw in - // the termios(3) manpage. - termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON - termios.Oflag &^= unix.OPOST - termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN - termios.Cflag &^= unix.CSIZE | unix.PARENB - termios.Cflag |= unix.CS8 - termios.Cc[unix.VMIN] = 1 - termios.Cc[unix.VTIME] = 0 - if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { - return nil, err - } - - return &oldState, nil -} - -func getState(fd int) (*State, error) { - termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - if err != nil { - return nil, err - } - - return &State{state{termios: *termios}}, nil -} - -func restore(fd int, state *State) error { - return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) -} - -func getSize(fd int) (width, height int, err error) { - ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) - if err != nil { - return 0, 0, err - } - return int(ws.Col), int(ws.Row), nil -} - -// passwordReader is an io.Reader that reads from a specific file descriptor. -type passwordReader int - -func (r passwordReader) Read(buf []byte) (int, error) { - return unix.Read(int(r), buf) -} - -func readPassword(fd int) ([]byte, error) { - termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - if err != nil { - return nil, err - } - - newState := *termios - newState.Lflag &^= unix.ECHO - newState.Lflag |= unix.ICANON | unix.ISIG - newState.Iflag |= unix.ICRNL - if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { - return nil, err - } - - defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) - - return readPasswordLine(passwordReader(fd)) -} diff --git a/vendor/golang.org/x/term/term_unix_bsd.go b/vendor/golang.org/x/term/term_unix_bsd.go deleted file mode 100644 index 9dbf546298..0000000000 --- a/vendor/golang.org/x/term/term_unix_bsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin || dragonfly || freebsd || netbsd || openbsd - -package term - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TIOCGETA -const ioctlWriteTermios = unix.TIOCSETA diff --git a/vendor/golang.org/x/term/term_unix_other.go b/vendor/golang.org/x/term/term_unix_other.go deleted file mode 100644 index 1b36de799a..0000000000 --- a/vendor/golang.org/x/term/term_unix_other.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || linux || solaris || zos - -package term - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TCGETS -const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/golang.org/x/term/term_unsupported.go b/vendor/golang.org/x/term/term_unsupported.go deleted file mode 100644 index 3c409e5885..0000000000 --- a/vendor/golang.org/x/term/term_unsupported.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !zos && !windows && !solaris && !plan9 - -package term - -import ( - "fmt" - "runtime" -) - -type state struct{} - -func isTerminal(fd int) bool { - return false -} - -func makeRaw(fd int) (*State, error) { - return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func getState(fd int) (*State, error) { - return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func restore(fd int, state *State) error { - return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func getSize(fd int) (width, height int, err error) { - return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -func readPassword(fd int) ([]byte, error) { - return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff --git a/vendor/golang.org/x/term/term_windows.go b/vendor/golang.org/x/term/term_windows.go deleted file mode 100644 index 465f560604..0000000000 --- a/vendor/golang.org/x/term/term_windows.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package term - -import ( - "os" - - "golang.org/x/sys/windows" -) - -type state struct { - mode uint32 -} - -func isTerminal(fd int) bool { - var st uint32 - err := windows.GetConsoleMode(windows.Handle(fd), &st) - return err == nil -} - -func makeRaw(fd int) (*State, error) { - var st uint32 - if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { - return nil, err - } - raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) - if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { - return nil, err - } - return &State{state{st}}, nil -} - -func getState(fd int) (*State, error) { - var st uint32 - if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { - return nil, err - } - return &State{state{st}}, nil -} - -func restore(fd int, state *State) error { - return windows.SetConsoleMode(windows.Handle(fd), state.mode) -} - -func getSize(fd int) (width, height int, err error) { - var info windows.ConsoleScreenBufferInfo - if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { - return 0, 0, err - } - return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil -} - -func readPassword(fd int) ([]byte, error) { - var st uint32 - if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { - return nil, err - } - old := st - - st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT) - st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT) - if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { - return nil, err - } - - defer windows.SetConsoleMode(windows.Handle(fd), old) - - var h windows.Handle - p, _ := windows.GetCurrentProcess() - if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { - return nil, err - } - - f := os.NewFile(uintptr(h), "stdin") - defer f.Close() - return readPasswordLine(f) -} diff --git a/vendor/golang.org/x/term/terminal.go b/vendor/golang.org/x/term/terminal.go deleted file mode 100644 index f636667fb0..0000000000 --- a/vendor/golang.org/x/term/terminal.go +++ /dev/null @@ -1,986 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package term - -import ( - "bytes" - "io" - "runtime" - "strconv" - "sync" - "unicode/utf8" -) - -// EscapeCodes contains escape sequences that can be written to the terminal in -// order to achieve different styles of text. -type EscapeCodes struct { - // Foreground colors - Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte - - // Reset all attributes - Reset []byte -} - -var vt100EscapeCodes = EscapeCodes{ - Black: []byte{keyEscape, '[', '3', '0', 'm'}, - Red: []byte{keyEscape, '[', '3', '1', 'm'}, - Green: []byte{keyEscape, '[', '3', '2', 'm'}, - Yellow: []byte{keyEscape, '[', '3', '3', 'm'}, - Blue: []byte{keyEscape, '[', '3', '4', 'm'}, - Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, - Cyan: []byte{keyEscape, '[', '3', '6', 'm'}, - White: []byte{keyEscape, '[', '3', '7', 'm'}, - - Reset: []byte{keyEscape, '[', '0', 'm'}, -} - -// Terminal contains the state for running a VT100 terminal that is capable of -// reading lines of input. -type Terminal struct { - // AutoCompleteCallback, if non-null, is called for each keypress with - // the full input line and the current position of the cursor (in - // bytes, as an index into |line|). If it returns ok=false, the key - // press is processed normally. Otherwise it returns a replacement line - // and the new cursor position. - AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) - - // Escape contains a pointer to the escape codes for this terminal. - // It's always a valid pointer, although the escape codes themselves - // may be empty if the terminal doesn't support them. - Escape *EscapeCodes - - // lock protects the terminal and the state in this object from - // concurrent processing of a key press and a Write() call. - lock sync.Mutex - - c io.ReadWriter - prompt []rune - - // line is the current line being entered. - line []rune - // pos is the logical position of the cursor in line - pos int - // echo is true if local echo is enabled - echo bool - // pasteActive is true iff there is a bracketed paste operation in - // progress. - pasteActive bool - - // cursorX contains the current X value of the cursor where the left - // edge is 0. cursorY contains the row number where the first row of - // the current line is 0. - cursorX, cursorY int - // maxLine is the greatest value of cursorY so far. - maxLine int - - termWidth, termHeight int - - // outBuf contains the terminal data to be sent. - outBuf []byte - // remainder contains the remainder of any partial key sequences after - // a read. It aliases into inBuf. - remainder []byte - inBuf [256]byte - - // history contains previously entered commands so that they can be - // accessed with the up and down keys. - history stRingBuffer - // historyIndex stores the currently accessed history entry, where zero - // means the immediately previous entry. - historyIndex int - // When navigating up and down the history it's possible to return to - // the incomplete, initial line. That value is stored in - // historyPending. - historyPending string -} - -// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is -// a local terminal, that terminal must first have been put into raw mode. -// prompt is a string that is written at the start of each input line (i.e. -// "> "). -func NewTerminal(c io.ReadWriter, prompt string) *Terminal { - return &Terminal{ - Escape: &vt100EscapeCodes, - c: c, - prompt: []rune(prompt), - termWidth: 80, - termHeight: 24, - echo: true, - historyIndex: -1, - } -} - -const ( - keyCtrlC = 3 - keyCtrlD = 4 - keyCtrlU = 21 - keyEnter = '\r' - keyEscape = 27 - keyBackspace = 127 - keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota - keyUp - keyDown - keyLeft - keyRight - keyAltLeft - keyAltRight - keyHome - keyEnd - keyDeleteWord - keyDeleteLine - keyClearScreen - keyPasteStart - keyPasteEnd -) - -var ( - crlf = []byte{'\r', '\n'} - pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'} - pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'} -) - -// bytesToKey tries to parse a key sequence from b. If successful, it returns -// the key and the remainder of the input. Otherwise it returns utf8.RuneError. -func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { - if len(b) == 0 { - return utf8.RuneError, nil - } - - if !pasteActive { - switch b[0] { - case 1: // ^A - return keyHome, b[1:] - case 2: // ^B - return keyLeft, b[1:] - case 5: // ^E - return keyEnd, b[1:] - case 6: // ^F - return keyRight, b[1:] - case 8: // ^H - return keyBackspace, b[1:] - case 11: // ^K - return keyDeleteLine, b[1:] - case 12: // ^L - return keyClearScreen, b[1:] - case 23: // ^W - return keyDeleteWord, b[1:] - case 14: // ^N - return keyDown, b[1:] - case 16: // ^P - return keyUp, b[1:] - } - } - - if b[0] != keyEscape { - if !utf8.FullRune(b) { - return utf8.RuneError, b - } - r, l := utf8.DecodeRune(b) - return r, b[l:] - } - - if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' { - switch b[2] { - case 'A': - return keyUp, b[3:] - case 'B': - return keyDown, b[3:] - case 'C': - return keyRight, b[3:] - case 'D': - return keyLeft, b[3:] - case 'H': - return keyHome, b[3:] - case 'F': - return keyEnd, b[3:] - } - } - - if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' { - switch b[5] { - case 'C': - return keyAltRight, b[6:] - case 'D': - return keyAltLeft, b[6:] - } - } - - if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) { - return keyPasteStart, b[6:] - } - - if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) { - return keyPasteEnd, b[6:] - } - - // If we get here then we have a key that we don't recognise, or a - // partial sequence. It's not clear how one should find the end of a - // sequence without knowing them all, but it seems that [a-zA-Z~] only - // appears at the end of a sequence. - for i, c := range b[0:] { - if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' { - return keyUnknown, b[i+1:] - } - } - - return utf8.RuneError, b -} - -// queue appends data to the end of t.outBuf -func (t *Terminal) queue(data []rune) { - t.outBuf = append(t.outBuf, []byte(string(data))...) -} - -var space = []rune{' '} - -func isPrintable(key rune) bool { - isInSurrogateArea := key >= 0xd800 && key <= 0xdbff - return key >= 32 && !isInSurrogateArea -} - -// moveCursorToPos appends data to t.outBuf which will move the cursor to the -// given, logical position in the text. -func (t *Terminal) moveCursorToPos(pos int) { - if !t.echo { - return - } - - x := visualLength(t.prompt) + pos - y := x / t.termWidth - x = x % t.termWidth - - up := 0 - if y < t.cursorY { - up = t.cursorY - y - } - - down := 0 - if y > t.cursorY { - down = y - t.cursorY - } - - left := 0 - if x < t.cursorX { - left = t.cursorX - x - } - - right := 0 - if x > t.cursorX { - right = x - t.cursorX - } - - t.cursorX = x - t.cursorY = y - t.move(up, down, left, right) -} - -func (t *Terminal) move(up, down, left, right int) { - m := []rune{} - - // 1 unit up can be expressed as ^[[A or ^[A - // 5 units up can be expressed as ^[[5A - - if up == 1 { - m = append(m, keyEscape, '[', 'A') - } else if up > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(up))...) - m = append(m, 'A') - } - - if down == 1 { - m = append(m, keyEscape, '[', 'B') - } else if down > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(down))...) - m = append(m, 'B') - } - - if right == 1 { - m = append(m, keyEscape, '[', 'C') - } else if right > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(right))...) - m = append(m, 'C') - } - - if left == 1 { - m = append(m, keyEscape, '[', 'D') - } else if left > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(left))...) - m = append(m, 'D') - } - - t.queue(m) -} - -func (t *Terminal) clearLineToRight() { - op := []rune{keyEscape, '[', 'K'} - t.queue(op) -} - -const maxLineLength = 4096 - -func (t *Terminal) setLine(newLine []rune, newPos int) { - if t.echo { - t.moveCursorToPos(0) - t.writeLine(newLine) - for i := len(newLine); i < len(t.line); i++ { - t.writeLine(space) - } - t.moveCursorToPos(newPos) - } - t.line = newLine - t.pos = newPos -} - -func (t *Terminal) advanceCursor(places int) { - t.cursorX += places - t.cursorY += t.cursorX / t.termWidth - if t.cursorY > t.maxLine { - t.maxLine = t.cursorY - } - t.cursorX = t.cursorX % t.termWidth - - if places > 0 && t.cursorX == 0 { - // Normally terminals will advance the current position - // when writing a character. But that doesn't happen - // for the last character in a line. However, when - // writing a character (except a new line) that causes - // a line wrap, the position will be advanced two - // places. - // - // So, if we are stopping at the end of a line, we - // need to write a newline so that our cursor can be - // advanced to the next line. - t.outBuf = append(t.outBuf, '\r', '\n') - } -} - -func (t *Terminal) eraseNPreviousChars(n int) { - if n == 0 { - return - } - - if t.pos < n { - n = t.pos - } - t.pos -= n - t.moveCursorToPos(t.pos) - - copy(t.line[t.pos:], t.line[n+t.pos:]) - t.line = t.line[:len(t.line)-n] - if t.echo { - t.writeLine(t.line[t.pos:]) - for i := 0; i < n; i++ { - t.queue(space) - } - t.advanceCursor(n) - t.moveCursorToPos(t.pos) - } -} - -// countToLeftWord returns then number of characters from the cursor to the -// start of the previous word. -func (t *Terminal) countToLeftWord() int { - if t.pos == 0 { - return 0 - } - - pos := t.pos - 1 - for pos > 0 { - if t.line[pos] != ' ' { - break - } - pos-- - } - for pos > 0 { - if t.line[pos] == ' ' { - pos++ - break - } - pos-- - } - - return t.pos - pos -} - -// countToRightWord returns then number of characters from the cursor to the -// start of the next word. -func (t *Terminal) countToRightWord() int { - pos := t.pos - for pos < len(t.line) { - if t.line[pos] == ' ' { - break - } - pos++ - } - for pos < len(t.line) { - if t.line[pos] != ' ' { - break - } - pos++ - } - return pos - t.pos -} - -// visualLength returns the number of visible glyphs in s. -func visualLength(runes []rune) int { - inEscapeSeq := false - length := 0 - - for _, r := range runes { - switch { - case inEscapeSeq: - if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { - inEscapeSeq = false - } - case r == '\x1b': - inEscapeSeq = true - default: - length++ - } - } - - return length -} - -// handleKey processes the given key and, optionally, returns a line of text -// that the user has entered. -func (t *Terminal) handleKey(key rune) (line string, ok bool) { - if t.pasteActive && key != keyEnter { - t.addKeyToLine(key) - return - } - - switch key { - case keyBackspace: - if t.pos == 0 { - return - } - t.eraseNPreviousChars(1) - case keyAltLeft: - // move left by a word. - t.pos -= t.countToLeftWord() - t.moveCursorToPos(t.pos) - case keyAltRight: - // move right by a word. - t.pos += t.countToRightWord() - t.moveCursorToPos(t.pos) - case keyLeft: - if t.pos == 0 { - return - } - t.pos-- - t.moveCursorToPos(t.pos) - case keyRight: - if t.pos == len(t.line) { - return - } - t.pos++ - t.moveCursorToPos(t.pos) - case keyHome: - if t.pos == 0 { - return - } - t.pos = 0 - t.moveCursorToPos(t.pos) - case keyEnd: - if t.pos == len(t.line) { - return - } - t.pos = len(t.line) - t.moveCursorToPos(t.pos) - case keyUp: - entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1) - if !ok { - return "", false - } - if t.historyIndex == -1 { - t.historyPending = string(t.line) - } - t.historyIndex++ - runes := []rune(entry) - t.setLine(runes, len(runes)) - case keyDown: - switch t.historyIndex { - case -1: - return - case 0: - runes := []rune(t.historyPending) - t.setLine(runes, len(runes)) - t.historyIndex-- - default: - entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1) - if ok { - t.historyIndex-- - runes := []rune(entry) - t.setLine(runes, len(runes)) - } - } - case keyEnter: - t.moveCursorToPos(len(t.line)) - t.queue([]rune("\r\n")) - line = string(t.line) - ok = true - t.line = t.line[:0] - t.pos = 0 - t.cursorX = 0 - t.cursorY = 0 - t.maxLine = 0 - case keyDeleteWord: - // Delete zero or more spaces and then one or more characters. - t.eraseNPreviousChars(t.countToLeftWord()) - case keyDeleteLine: - // Delete everything from the current cursor position to the - // end of line. - for i := t.pos; i < len(t.line); i++ { - t.queue(space) - t.advanceCursor(1) - } - t.line = t.line[:t.pos] - t.moveCursorToPos(t.pos) - case keyCtrlD: - // Erase the character under the current position. - // The EOF case when the line is empty is handled in - // readLine(). - if t.pos < len(t.line) { - t.pos++ - t.eraseNPreviousChars(1) - } - case keyCtrlU: - t.eraseNPreviousChars(t.pos) - case keyClearScreen: - // Erases the screen and moves the cursor to the home position. - t.queue([]rune("\x1b[2J\x1b[H")) - t.queue(t.prompt) - t.cursorX, t.cursorY = 0, 0 - t.advanceCursor(visualLength(t.prompt)) - t.setLine(t.line, t.pos) - default: - if t.AutoCompleteCallback != nil { - prefix := string(t.line[:t.pos]) - suffix := string(t.line[t.pos:]) - - t.lock.Unlock() - newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key) - t.lock.Lock() - - if completeOk { - t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos])) - return - } - } - if !isPrintable(key) { - return - } - if len(t.line) == maxLineLength { - return - } - t.addKeyToLine(key) - } - return -} - -// addKeyToLine inserts the given key at the current position in the current -// line. -func (t *Terminal) addKeyToLine(key rune) { - if len(t.line) == cap(t.line) { - newLine := make([]rune, len(t.line), 2*(1+len(t.line))) - copy(newLine, t.line) - t.line = newLine - } - t.line = t.line[:len(t.line)+1] - copy(t.line[t.pos+1:], t.line[t.pos:]) - t.line[t.pos] = key - if t.echo { - t.writeLine(t.line[t.pos:]) - } - t.pos++ - t.moveCursorToPos(t.pos) -} - -func (t *Terminal) writeLine(line []rune) { - for len(line) != 0 { - remainingOnLine := t.termWidth - t.cursorX - todo := len(line) - if todo > remainingOnLine { - todo = remainingOnLine - } - t.queue(line[:todo]) - t.advanceCursor(visualLength(line[:todo])) - line = line[todo:] - } -} - -// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n. -func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { - for len(buf) > 0 { - i := bytes.IndexByte(buf, '\n') - todo := len(buf) - if i >= 0 { - todo = i - } - - var nn int - nn, err = w.Write(buf[:todo]) - n += nn - if err != nil { - return n, err - } - buf = buf[todo:] - - if i >= 0 { - if _, err = w.Write(crlf); err != nil { - return n, err - } - n++ - buf = buf[1:] - } - } - - return n, nil -} - -func (t *Terminal) Write(buf []byte) (n int, err error) { - t.lock.Lock() - defer t.lock.Unlock() - - if t.cursorX == 0 && t.cursorY == 0 { - // This is the easy case: there's nothing on the screen that we - // have to move out of the way. - return writeWithCRLF(t.c, buf) - } - - // We have a prompt and possibly user input on the screen. We - // have to clear it first. - t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */) - t.cursorX = 0 - t.clearLineToRight() - - for t.cursorY > 0 { - t.move(1 /* up */, 0, 0, 0) - t.cursorY-- - t.clearLineToRight() - } - - if _, err = t.c.Write(t.outBuf); err != nil { - return - } - t.outBuf = t.outBuf[:0] - - if n, err = writeWithCRLF(t.c, buf); err != nil { - return - } - - t.writeLine(t.prompt) - if t.echo { - t.writeLine(t.line) - } - - t.moveCursorToPos(t.pos) - - if _, err = t.c.Write(t.outBuf); err != nil { - return - } - t.outBuf = t.outBuf[:0] - return -} - -// ReadPassword temporarily changes the prompt and reads a password, without -// echo, from the terminal. -func (t *Terminal) ReadPassword(prompt string) (line string, err error) { - t.lock.Lock() - defer t.lock.Unlock() - - oldPrompt := t.prompt - t.prompt = []rune(prompt) - t.echo = false - - line, err = t.readLine() - - t.prompt = oldPrompt - t.echo = true - - return -} - -// ReadLine returns a line of input from the terminal. -func (t *Terminal) ReadLine() (line string, err error) { - t.lock.Lock() - defer t.lock.Unlock() - - return t.readLine() -} - -func (t *Terminal) readLine() (line string, err error) { - // t.lock must be held at this point - - if t.cursorX == 0 && t.cursorY == 0 { - t.writeLine(t.prompt) - t.c.Write(t.outBuf) - t.outBuf = t.outBuf[:0] - } - - lineIsPasted := t.pasteActive - - for { - rest := t.remainder - lineOk := false - for !lineOk { - var key rune - key, rest = bytesToKey(rest, t.pasteActive) - if key == utf8.RuneError { - break - } - if !t.pasteActive { - if key == keyCtrlD { - if len(t.line) == 0 { - return "", io.EOF - } - } - if key == keyCtrlC { - return "", io.EOF - } - if key == keyPasteStart { - t.pasteActive = true - if len(t.line) == 0 { - lineIsPasted = true - } - continue - } - } else if key == keyPasteEnd { - t.pasteActive = false - continue - } - if !t.pasteActive { - lineIsPasted = false - } - line, lineOk = t.handleKey(key) - } - if len(rest) > 0 { - n := copy(t.inBuf[:], rest) - t.remainder = t.inBuf[:n] - } else { - t.remainder = nil - } - t.c.Write(t.outBuf) - t.outBuf = t.outBuf[:0] - if lineOk { - if t.echo { - t.historyIndex = -1 - t.history.Add(line) - } - if lineIsPasted { - err = ErrPasteIndicator - } - return - } - - // t.remainder is a slice at the beginning of t.inBuf - // containing a partial key sequence - readBuf := t.inBuf[len(t.remainder):] - var n int - - t.lock.Unlock() - n, err = t.c.Read(readBuf) - t.lock.Lock() - - if err != nil { - return - } - - t.remainder = t.inBuf[:n+len(t.remainder)] - } -} - -// SetPrompt sets the prompt to be used when reading subsequent lines. -func (t *Terminal) SetPrompt(prompt string) { - t.lock.Lock() - defer t.lock.Unlock() - - t.prompt = []rune(prompt) -} - -func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) { - // Move cursor to column zero at the start of the line. - t.move(t.cursorY, 0, t.cursorX, 0) - t.cursorX, t.cursorY = 0, 0 - t.clearLineToRight() - for t.cursorY < numPrevLines { - // Move down a line - t.move(0, 1, 0, 0) - t.cursorY++ - t.clearLineToRight() - } - // Move back to beginning. - t.move(t.cursorY, 0, 0, 0) - t.cursorX, t.cursorY = 0, 0 - - t.queue(t.prompt) - t.advanceCursor(visualLength(t.prompt)) - t.writeLine(t.line) - t.moveCursorToPos(t.pos) -} - -func (t *Terminal) SetSize(width, height int) error { - t.lock.Lock() - defer t.lock.Unlock() - - if width == 0 { - width = 1 - } - - oldWidth := t.termWidth - t.termWidth, t.termHeight = width, height - - switch { - case width == oldWidth: - // If the width didn't change then nothing else needs to be - // done. - return nil - case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: - // If there is nothing on current line and no prompt printed, - // just do nothing - return nil - case width < oldWidth: - // Some terminals (e.g. xterm) will truncate lines that were - // too long when shinking. Others, (e.g. gnome-terminal) will - // attempt to wrap them. For the former, repainting t.maxLine - // works great, but that behaviour goes badly wrong in the case - // of the latter because they have doubled every full line. - - // We assume that we are working on a terminal that wraps lines - // and adjust the cursor position based on every previous line - // wrapping and turning into two. This causes the prompt on - // xterms to move upwards, which isn't great, but it avoids a - // huge mess with gnome-terminal. - if t.cursorX >= t.termWidth { - t.cursorX = t.termWidth - 1 - } - t.cursorY *= 2 - t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2) - case width > oldWidth: - // If the terminal expands then our position calculations will - // be wrong in the future because we think the cursor is - // |t.pos| chars into the string, but there will be a gap at - // the end of any wrapped line. - // - // But the position will actually be correct until we move, so - // we can move back to the beginning and repaint everything. - t.clearAndRepaintLinePlusNPrevious(t.maxLine) - } - - _, err := t.c.Write(t.outBuf) - t.outBuf = t.outBuf[:0] - return err -} - -type pasteIndicatorError struct{} - -func (pasteIndicatorError) Error() string { - return "terminal: ErrPasteIndicator not correctly handled" -} - -// ErrPasteIndicator may be returned from ReadLine as the error, in addition -// to valid line data. It indicates that bracketed paste mode is enabled and -// that the returned line consists only of pasted data. Programs may wish to -// interpret pasted data more literally than typed data. -var ErrPasteIndicator = pasteIndicatorError{} - -// SetBracketedPasteMode requests that the terminal bracket paste operations -// with markers. Not all terminals support this but, if it is supported, then -// enabling this mode will stop any autocomplete callback from running due to -// pastes. Additionally, any lines that are completely pasted will be returned -// from ReadLine with the error set to ErrPasteIndicator. -func (t *Terminal) SetBracketedPasteMode(on bool) { - if on { - io.WriteString(t.c, "\x1b[?2004h") - } else { - io.WriteString(t.c, "\x1b[?2004l") - } -} - -// stRingBuffer is a ring buffer of strings. -type stRingBuffer struct { - // entries contains max elements. - entries []string - max int - // head contains the index of the element most recently added to the ring. - head int - // size contains the number of elements in the ring. - size int -} - -func (s *stRingBuffer) Add(a string) { - if s.entries == nil { - const defaultNumEntries = 100 - s.entries = make([]string, defaultNumEntries) - s.max = defaultNumEntries - } - - s.head = (s.head + 1) % s.max - s.entries[s.head] = a - if s.size < s.max { - s.size++ - } -} - -// NthPreviousEntry returns the value passed to the nth previous call to Add. -// If n is zero then the immediately prior value is returned, if one, then the -// next most recent, and so on. If such an element doesn't exist then ok is -// false. -func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { - if n < 0 || n >= s.size { - return "", false - } - index := s.head - n - if index < 0 { - index += s.max - } - return s.entries[index], true -} - -// readPasswordLine reads from reader until it finds \n or io.EOF. -// The slice returned does not include the \n. -// readPasswordLine also ignores any \r it finds. -// Windows uses \r as end of line. So, on Windows, readPasswordLine -// reads until it finds \r and ignores any \n it finds during processing. -func readPasswordLine(reader io.Reader) ([]byte, error) { - var buf [1]byte - var ret []byte - - for { - n, err := reader.Read(buf[:]) - if n > 0 { - switch buf[0] { - case '\b': - if len(ret) > 0 { - ret = ret[:len(ret)-1] - } - case '\n': - if runtime.GOOS != "windows" { - return ret, nil - } - // otherwise ignore \n - case '\r': - if runtime.GOOS == "windows" { - return ret, nil - } - // otherwise ignore \r - default: - ret = append(ret, buf[0]) - } - continue - } - if err != nil { - if err == io.EOF && len(ret) > 0 { - return ret, nil - } - return ret, err - } - } -} diff --git a/vendor/golang.org/x/tools/cmd/goimports/gotypesalias.go b/vendor/golang.org/x/tools/cmd/goimports/gotypesalias.go new file mode 100644 index 0000000000..288c10c2d0 --- /dev/null +++ b/vendor/golang.org/x/tools/cmd/goimports/gotypesalias.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.23 + +//go:debug gotypesalias=1 + +package main + +// Materialize aliases whenever the go toolchain version is after 1.23 (#69772). +// Remove this file after go.mod >= 1.23 (which implies gotypesalias=1). diff --git a/vendor/golang.org/x/tools/go/analysis/analysis.go b/vendor/golang.org/x/tools/go/analysis/analysis.go index aa02eeda68..3a73084a53 100644 --- a/vendor/golang.org/x/tools/go/analysis/analysis.go +++ b/vendor/golang.org/x/tools/go/analysis/analysis.go @@ -50,7 +50,7 @@ type Analyzer struct { // RunDespiteErrors allows the driver to invoke // the Run method of this analyzer even on a // package that contains parse or type errors. - // The Pass.TypeErrors field may consequently be non-empty. + // The [Pass.TypeErrors] field may consequently be non-empty. RunDespiteErrors bool // Requires is a set of analyzers that must run successfully @@ -156,10 +156,17 @@ type Pass struct { // AllPackageFacts returns a new slice containing all package // facts of the analysis's FactTypes in unspecified order. + // See comments for AllObjectFacts. AllPackageFacts func() []PackageFact // AllObjectFacts returns a new slice containing all object // facts of the analysis's FactTypes in unspecified order. + // + // The result includes all facts exported by packages + // whose symbols are referenced by the current package + // (by qualified identifiers or field/method selections). + // And it includes all facts exported from the current + // package by the current analysis pass. AllObjectFacts func() []ObjectFact /* Further fields may be added in future. */ diff --git a/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go b/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go index c1b2dd4fa1..775fd20094 100644 --- a/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go +++ b/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go @@ -16,6 +16,7 @@ import ( "path/filepath" "regexp" "runtime" + "slices" "sort" "strconv" "strings" @@ -23,7 +24,8 @@ import ( "text/scanner" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/internal/checker" + "golang.org/x/tools/go/analysis/checker" + "golang.org/x/tools/go/analysis/internal" "golang.org/x/tools/go/packages" "golang.org/x/tools/internal/diff" "golang.org/x/tools/internal/testenv" @@ -34,6 +36,12 @@ import ( // and populates it with a GOPATH-style project using filemap (which // maps file names to contents). On success it returns the name of the // directory and a cleanup function to delete it. +// +// TODO(adonovan): provide a newer version that accepts a testing.T, +// calls T.TempDir, and calls T.Fatal on any error, avoiding the need +// to return cleanup or err: +// +// func WriteFilesToTmp(t *testing.T filemap map[string]string) string func WriteFiles(filemap map[string]string) (dir string, cleanup func(), err error) { gopath, err := os.MkdirTemp("", "analysistest") if err != nil { @@ -137,7 +145,7 @@ type Testing interface { // analyzers that offer alternative fixes are advised to put each fix // in a separate .go file in the testdata. func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Result { - r := Run(t, dir, a, patterns...) + results := Run(t, dir, a, patterns...) // If the immediate caller of RunWithSuggestedFixes is in // x/tools, we apply stricter checks as required by gopls. @@ -162,52 +170,31 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns // Validating the results separately means as long as the two analyses // don't produce conflicting suggestions for a single file, everything // should match up. - for _, act := range r { + for _, result := range results { + act := result.Action + // file -> message -> edits + // TODO(adonovan): this mapping assumes fix.Messages are unique across analyzers, + // whereas they are only unique within a given Diagnostic. fileEdits := make(map[*token.File]map[string][]diff.Edit) - fileContents := make(map[*token.File][]byte) - // Validate edits, prepare the fileEdits map and read the file contents. + // We may assume that fixes are validated upon creation in Pass.Report. + // Group fixes by file and message. for _, diag := range act.Diagnostics { for _, fix := range diag.SuggestedFixes { - // Assert that lazy fixes have a Category (#65578, #65087). if inTools && len(fix.TextEdits) == 0 && diag.Category == "" { t.Errorf("missing Diagnostic.Category for SuggestedFix without TextEdits (gopls requires the category for the name of the fix command") } for _, edit := range fix.TextEdits { - start, end := edit.Pos, edit.End - if !end.IsValid() { - end = start - } - // Validate the edit. - if start > end { - t.Errorf( - "diagnostic for analysis %v contains Suggested Fix with malformed edit: pos (%v) > end (%v)", - act.Pass.Analyzer.Name, start, end) - continue - } - file, endfile := act.Pass.Fset.File(start), act.Pass.Fset.File(end) - if file == nil || endfile == nil || file != endfile { - t.Errorf( - "diagnostic for analysis %v contains Suggested Fix with malformed spanning files %v and %v", - act.Pass.Analyzer.Name, file.Name(), endfile.Name()) - continue - } - if _, ok := fileContents[file]; !ok { - contents, err := os.ReadFile(file.Name()) - if err != nil { - t.Errorf("error reading %s: %v", file.Name(), err) - } - fileContents[file] = contents - } + file := act.Package.Fset.File(edit.Pos) if _, ok := fileEdits[file]; !ok { fileEdits[file] = make(map[string][]diff.Edit) } fileEdits[file][fix.Message] = append(fileEdits[file][fix.Message], diff.Edit{ - Start: file.Offset(start), - End: file.Offset(end), + Start: file.Offset(edit.Pos), + End: file.Offset(edit.End), New: string(edit.NewText), }) } @@ -216,9 +203,10 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns for file, fixes := range fileEdits { // Get the original file contents. - orig, ok := fileContents[file] - if !ok { - t.Errorf("could not find file contents for %s", file.Name()) + // TODO(adonovan): plumb pass.ReadFile. + orig, err := os.ReadFile(file.Name()) + if err != nil { + t.Errorf("error reading %s: %v", file.Name(), err) continue } @@ -239,8 +227,15 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns t.Errorf("%s.golden has leading comment; we don't know what to do with it", file.Name()) continue } - - for sf, edits := range fixes { + // Sort map keys for determinism in tests. + // TODO(jba): replace with slices.Sorted(maps.Keys(fixes)) when go.mod >= 1.23. + var keys []string + for k := range fixes { + keys = append(keys, k) + } + slices.Sort(keys) + for _, sf := range keys { + edits := fixes[sf] found := false for _, vf := range ar.Files { if vf.Name == sf { @@ -263,10 +258,17 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns } } else { // all suggested fixes are represented by a single file - + // TODO(adonovan): fix: this makes no sense if len(fixes) > 1. + // Sort map keys for determinism in tests. + // TODO(jba): replace with slices.Sorted(maps.Keys(fixes)) when go.mod >= 1.23. + var keys []string + for k := range fixes { + keys = append(keys, k) + } + slices.Sort(keys) var catchallEdits []diff.Edit - for _, edits := range fixes { - catchallEdits = append(catchallEdits, edits...) + for _, k := range keys { + catchallEdits = append(catchallEdits, fixes[k]...) } if err := applyDiffsAndCompare(orig, ar.Comment, catchallEdits, file.Name()); err != nil { @@ -275,7 +277,7 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns } } } - return r + return results } // applyDiffsAndCompare applies edits to src and compares the results against @@ -349,36 +351,88 @@ func Run(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Res testenv.NeedsGoPackages(t) } - pkgs, err := loadPackages(a, dir, patterns...) + pkgs, err := loadPackages(dir, patterns...) if err != nil { t.Errorf("loading %s: %v", patterns, err) return nil } - if err := analysis.Validate([]*analysis.Analyzer{a}); err != nil { - t.Errorf("Validate: %v", err) + // Print parse and type errors to the test log. + // (Do not print them to stderr, which would pollute + // the log in cases where the tests pass.) + if t, ok := t.(testing.TB); ok && !a.RunDespiteErrors { + packages.Visit(pkgs, nil, func(pkg *packages.Package) { + for _, err := range pkg.Errors { + t.Log(err) + } + }) + } + + res, err := checker.Analyze([]*analysis.Analyzer{a}, pkgs, nil) + if err != nil { + t.Errorf("Analyze: %v", err) return nil } - results := checker.TestAnalyzer(a, pkgs) - for _, result := range results { - if result.Err != nil { - t.Errorf("error analyzing %s: %v", result.Pass, result.Err) + var results []*Result + for _, act := range res.Roots { + if act.Err != nil { + t.Errorf("error analyzing %s: %v", act, act.Err) } else { - check(t, dir, result.Pass, result.Diagnostics, result.Facts) + check(t, dir, act) } + + // Compute legacy map of facts relating to this package. + facts := make(map[types.Object][]analysis.Fact) + for _, objFact := range act.AllObjectFacts() { + if obj := objFact.Object; obj.Pkg() == act.Package.Types { + facts[obj] = append(facts[obj], objFact.Fact) + } + } + for _, pkgFact := range act.AllPackageFacts() { + if pkgFact.Package == act.Package.Types { + facts[nil] = append(facts[nil], pkgFact.Fact) + } + } + + // Construct the legacy result. + results = append(results, &Result{ + Pass: internal.Pass(act), + Diagnostics: act.Diagnostics, + Facts: facts, + Result: act.Result, + Err: act.Err, + Action: act, + }) } return results } // A Result holds the result of applying an analyzer to a package. -type Result = checker.TestAnalyzerResult +// +// Facts contains only facts associated with the package and its objects. +// +// This internal type was inadvertently and regrettably exposed +// through a public type alias. It is essentially redundant with +// [checker.Action], but must be retained for compatibility. Clients may +// access the public fields of the Pass but must not invoke any of +// its "verbs", since the pass is already complete. +type Result struct { + Action *checker.Action + + // legacy fields + Facts map[types.Object][]analysis.Fact // nil key => package fact + Pass *analysis.Pass + Diagnostics []analysis.Diagnostic // see Action.Diagnostics + Result any // see Action.Result + Err error // see Action.Err +} // loadPackages uses go/packages to load a specified packages (from source, with // dependencies) from dir, which is the root of a GOPATH-style project tree. // loadPackages returns an error if any package had an error, or the pattern // matched no packages. -func loadPackages(a *analysis.Analyzer, dir string, patterns ...string) ([]*packages.Package, error) { +func loadPackages(dir string, patterns ...string) ([]*packages.Package, error) { env := []string{"GOPATH=" + dir, "GO111MODULE=off", "GOWORK=off"} // GOPATH mode // Undocumented module mode. Will be replaced by something better. @@ -421,16 +475,6 @@ func loadPackages(a *analysis.Analyzer, dir string, patterns ...string) ([]*pack } } - // Do NOT print errors if the analyzer will continue running. - // It is incredibly confusing for tests to be printing to stderr - // willy-nilly instead of their test logs, especially when the - // errors are expected and are going to be fixed. - if !a.RunDespiteErrors { - if packages.PrintErrors(pkgs) > 0 { - return nil, fmt.Errorf("there were package loading errors (and RunDespiteErrors is false)") - } - } - if len(pkgs) == 0 { return nil, fmt.Errorf("no packages matched %s", patterns) } @@ -441,7 +485,7 @@ func loadPackages(a *analysis.Analyzer, dir string, patterns ...string) ([]*pack // been run, and verifies that all reported diagnostics and facts match // specified by the contents of "// want ..." comments in the package's // source files, which must have been parsed with comments enabled. -func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis.Diagnostic, facts map[types.Object][]analysis.Fact) { +func check(t Testing, gopath string, act *checker.Action) { type key struct { file string line int @@ -468,7 +512,7 @@ func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis } // Extract 'want' comments from parsed Go files. - for _, f := range pass.Files { + for _, f := range act.Package.Syntax { for _, cgroup := range f.Comments { for _, c := range cgroup.List { @@ -491,7 +535,7 @@ func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis // once outside the loop, but it's // incorrect because it can change due // to //line directives. - posn := pass.Fset.Position(c.Pos()) + posn := act.Package.Fset.Position(c.Pos()) filename := sanitize(gopath, posn.Filename) processComment(filename, posn.Line, text) } @@ -500,7 +544,17 @@ func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis // Extract 'want' comments from non-Go files. // TODO(adonovan): we may need to handle //line directives. - for _, filename := range pass.OtherFiles { + files := act.Package.OtherFiles + + // Hack: these two analyzers need to extract expectations from + // all configurations, so include the files are are usually + // ignored. (This was previously a hack in the respective + // analyzers' tests.) + if act.Analyzer.Name == "buildtag" || act.Analyzer.Name == "directive" { + files = append(files[:len(files):len(files)], act.Package.IgnoredFiles...) + } + + for _, filename := range files { data, err := os.ReadFile(filename) if err != nil { t.Errorf("can't read '// want' comments from %s: %v", filename, err) @@ -553,45 +607,38 @@ func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis } // Check the diagnostics match expectations. - for _, f := range diagnostics { + for _, f := range act.Diagnostics { // TODO(matloob): Support ranges in analysistest. - posn := pass.Fset.Position(f.Pos) + posn := act.Package.Fset.Position(f.Pos) checkMessage(posn, "diagnostic", "", f.Message) } // Check the facts match expectations. - // Report errors in lexical order for determinism. + // We check only facts relating to the current package. + // + // We report errors in lexical order for determinism. // (It's only deterministic within each file, not across files, // because go/packages does not guarantee file.Pos is ascending // across the files of a single compilation unit.) - var objects []types.Object - for obj := range facts { - objects = append(objects, obj) - } - sort.Slice(objects, func(i, j int) bool { - // Package facts compare less than object facts. - ip, jp := objects[i] == nil, objects[j] == nil // whether i, j is a package fact - if ip != jp { - return ip && !jp - } - return objects[i].Pos() < objects[j].Pos() - }) - for _, obj := range objects { - var posn token.Position - var name string - if obj != nil { - // Object facts are reported on the declaring line. - name = obj.Name() - posn = pass.Fset.Position(obj.Pos()) - } else { - // Package facts are reported at the start of the file. - name = "package" - posn = pass.Fset.Position(pass.Files[0].Pos()) - posn.Line = 1 + + // package facts: reported at start of first file + for _, pkgFact := range act.AllPackageFacts() { + if pkgFact.Package == act.Package.Types { + posn := act.Package.Fset.Position(act.Package.Syntax[0].Pos()) + posn.Line, posn.Column = 1, 1 + checkMessage(posn, "fact", "package", fmt.Sprint(pkgFact)) } + } - for _, fact := range facts[obj] { - checkMessage(posn, "fact", name, fmt.Sprint(fact)) + // object facts: reported at line of object declaration + objFacts := act.AllObjectFacts() + sort.Slice(objFacts, func(i, j int) bool { + return objFacts[i].Object.Pos() < objFacts[j].Object.Pos() + }) + for _, objFact := range objFacts { + if obj := objFact.Object; obj.Pkg() == act.Package.Types { + posn := act.Package.Fset.Position(obj.Pos()) + checkMessage(posn, "fact", obj.Name(), fmt.Sprint(objFact.Fact)) } } diff --git a/vendor/golang.org/x/tools/go/analysis/checker/checker.go b/vendor/golang.org/x/tools/go/analysis/checker/checker.go new file mode 100644 index 0000000000..502ec92217 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/checker/checker.go @@ -0,0 +1,637 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package checker provides an analysis driver based on the +// [golang.org/x/tools/go/packages] representation of a set of +// packages and all their dependencies, as produced by +// [packages.Load]. +// +// It is the core of multichecker (the multi-analyzer driver), +// singlechecker (the single-analyzer driver often used to provide a +// convenient command alongside each analyzer), and analysistest, the +// test driver. +// +// By contrast, the 'go vet' command is based on unitchecker, an +// analysis driver that uses separate analysis--analogous to separate +// compilation--with file-based intermediate results. Like separate +// compilation, it is more scalable, especially for incremental +// analysis of large code bases. Commands based on multichecker and +// singlechecker are capable of detecting when they are being invoked +// by "go vet -vettool=exe" and instead dispatching to unitchecker. +// +// Programs built using this package will, in general, not be usable +// in that way. This package is intended only for use in applications +// that invoke the analysis driver as a subroutine, and need to insert +// additional steps before or after the analysis. +// +// See the Example of how to build a complete analysis driver program. +package checker + +import ( + "bytes" + "encoding/gob" + "fmt" + "go/types" + "io" + "log" + "os" + "reflect" + "sort" + "strings" + "sync" + "time" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/internal" + "golang.org/x/tools/go/analysis/internal/analysisflags" + "golang.org/x/tools/go/packages" + "golang.org/x/tools/internal/analysisinternal" +) + +// Options specifies options that control the analysis driver. +type Options struct { + // These options correspond to existing flags exposed by multichecker: + Sequential bool // disable parallelism + SanityCheck bool // check fact encoding is ok and deterministic + FactLog io.Writer // if non-nil, log each exported fact to it + + // TODO(adonovan): expose ReadFile so that an Overlay specified + // in the [packages.Config] can be communicated via + // Pass.ReadFile to each Analyzer. + readFile analysisinternal.ReadFileFunc +} + +// Graph holds the results of a round of analysis, including the graph +// of requested actions (analyzers applied to packages) plus any +// dependent actions that it was necessary to compute. +type Graph struct { + // Roots contains the roots of the action graph. + // Each node (a, p) in the action graph represents the + // application of one analyzer a to one package p. + // (A node thus corresponds to one analysis.Pass instance.) + // Roots holds one action per element of the product + // of the analyzers × packages arguments to Analyze, + // in unspecified order. + // + // Each element of Action.Deps represents an edge in the + // action graph: a dependency from one action to another. + // An edge of the form (a, p) -> (a, p2) indicates that the + // analysis of package p requires information ("facts") from + // the same analyzer applied to one of p's dependencies, p2. + // An edge of the form (a, p) -> (a2, p) indicates that the + // analysis of package p requires information ("results") + // from a different analyzer a2 applied to the same package. + // These two kind of edges are called "vertical" and "horizontal", + // respectively. + Roots []*Action +} + +// All returns an iterator over the action graph in depth-first postorder. +// +// Example: +// +// for act := range graph.All() { +// ... +// } +// +// Clients using go1.22 should iterate using the code below and may +// not assume anything else about the result: +// +// graph.All()(func (act *Action) bool { +// ... +// }) +func (g *Graph) All() actionSeq { + return func(yield func(*Action) bool) { + forEach(g.Roots, func(act *Action) error { + if !yield(act) { + return io.EOF // any error will do + } + return nil + }) + } +} + +// An Action represents one unit of analysis work by the driver: the +// application of one analysis to one package. It provides the inputs +// to and records the outputs of a single analysis.Pass. +// +// Actions form a DAG, both within a package (as different analyzers +// are applied, either in sequence or parallel), and across packages +// (as dependencies are analyzed). +type Action struct { + Analyzer *analysis.Analyzer + Package *packages.Package + IsRoot bool // whether this is a root node of the graph + Deps []*Action + Result any // computed result of Analyzer.run, if any (and if IsRoot) + Err error // error result of Analyzer.run + Diagnostics []analysis.Diagnostic + Duration time.Duration // execution time of this step + + opts *Options + once sync.Once + pass *analysis.Pass + objectFacts map[objectFactKey]analysis.Fact + packageFacts map[packageFactKey]analysis.Fact + inputs map[*analysis.Analyzer]any +} + +func (act *Action) String() string { + return fmt.Sprintf("%s@%s", act.Analyzer, act.Package) +} + +// Analyze runs the specified analyzers on the initial packages. +// +// The initial packages and all dependencies must have been loaded +// using the [packages.LoadAllSyntax] flag, Analyze may need to run +// some analyzer (those that consume and produce facts) on +// dependencies too. +// +// On success, it returns a Graph of actions whose Roots hold one +// item per (a, p) in the cross-product of analyzers and pkgs. +// +// If opts is nil, it is equivalent to new(Options). +func Analyze(analyzers []*analysis.Analyzer, pkgs []*packages.Package, opts *Options) (*Graph, error) { + if opts == nil { + opts = new(Options) + } + + if err := analysis.Validate(analyzers); err != nil { + return nil, err + } + + // Construct the action graph. + // + // Each graph node (action) is one unit of analysis. + // Edges express package-to-package (vertical) dependencies, + // and analysis-to-analysis (horizontal) dependencies. + type key struct { + a *analysis.Analyzer + pkg *packages.Package + } + actions := make(map[key]*Action) + + var mkAction func(a *analysis.Analyzer, pkg *packages.Package) *Action + mkAction = func(a *analysis.Analyzer, pkg *packages.Package) *Action { + k := key{a, pkg} + act, ok := actions[k] + if !ok { + act = &Action{Analyzer: a, Package: pkg, opts: opts} + + // Add a dependency on each required analyzers. + for _, req := range a.Requires { + act.Deps = append(act.Deps, mkAction(req, pkg)) + } + + // An analysis that consumes/produces facts + // must run on the package's dependencies too. + if len(a.FactTypes) > 0 { + paths := make([]string, 0, len(pkg.Imports)) + for path := range pkg.Imports { + paths = append(paths, path) + } + sort.Strings(paths) // for determinism + for _, path := range paths { + dep := mkAction(a, pkg.Imports[path]) + act.Deps = append(act.Deps, dep) + } + } + + actions[k] = act + } + return act + } + + // Build nodes for initial packages. + var roots []*Action + for _, a := range analyzers { + for _, pkg := range pkgs { + root := mkAction(a, pkg) + root.IsRoot = true + roots = append(roots, root) + } + } + + // Execute the graph in parallel. + execAll(roots) + + // Ensure that only root Results are visible to caller. + // (The others are considered temporary intermediaries.) + // TODO(adonovan): opt: clear them earlier, so we can + // release large data structures like SSA sooner. + for _, act := range actions { + if !act.IsRoot { + act.Result = nil + } + } + + return &Graph{Roots: roots}, nil +} + +func init() { + // Allow analysistest to access Action.pass, + // for its legacy Result data type. + internal.Pass = func(x any) *analysis.Pass { return x.(*Action).pass } +} + +type objectFactKey struct { + obj types.Object + typ reflect.Type +} + +type packageFactKey struct { + pkg *types.Package + typ reflect.Type +} + +func execAll(actions []*Action) { + var wg sync.WaitGroup + for _, act := range actions { + wg.Add(1) + work := func(act *Action) { + act.exec() + wg.Done() + } + if act.opts.Sequential { + work(act) + } else { + go work(act) + } + } + wg.Wait() +} + +func (act *Action) exec() { act.once.Do(act.execOnce) } + +func (act *Action) execOnce() { + // Analyze dependencies. + execAll(act.Deps) + + // Record time spent in this node but not its dependencies. + // In parallel mode, due to GC/scheduler contention, the + // time is 5x higher than in sequential mode, even with a + // semaphore limiting the number of threads here. + // So use -debug=tp. + t0 := time.Now() + defer func() { act.Duration = time.Since(t0) }() + + // Report an error if any dependency failed. + var failed []string + for _, dep := range act.Deps { + if dep.Err != nil { + failed = append(failed, dep.String()) + } + } + if failed != nil { + sort.Strings(failed) + act.Err = fmt.Errorf("failed prerequisites: %s", strings.Join(failed, ", ")) + return + } + + // Plumb the output values of the dependencies + // into the inputs of this action. Also facts. + inputs := make(map[*analysis.Analyzer]any) + act.objectFacts = make(map[objectFactKey]analysis.Fact) + act.packageFacts = make(map[packageFactKey]analysis.Fact) + for _, dep := range act.Deps { + if dep.Package == act.Package { + // Same package, different analysis (horizontal edge): + // in-memory outputs of prerequisite analyzers + // become inputs to this analysis pass. + inputs[dep.Analyzer] = dep.Result + + } else if dep.Analyzer == act.Analyzer { // (always true) + // Same analysis, different package (vertical edge): + // serialized facts produced by prerequisite analysis + // become available to this analysis pass. + inheritFacts(act, dep) + } + } + + // Quick (nonexhaustive) check that the correct go/packages mode bits were used. + // (If there were errors, all bets are off.) + if pkg := act.Package; pkg.Errors == nil { + if pkg.Name == "" || pkg.PkgPath == "" || pkg.Types == nil || pkg.Fset == nil || pkg.TypesSizes == nil { + panic("packages must be loaded with packages.LoadSyntax mode") + } + } + + module := &analysis.Module{} // possibly empty (non nil) in go/analysis drivers. + if mod := act.Package.Module; mod != nil { + module.Path = mod.Path + module.Version = mod.Version + module.GoVersion = mod.GoVersion + } + + // Run the analysis. + pass := &analysis.Pass{ + Analyzer: act.Analyzer, + Fset: act.Package.Fset, + Files: act.Package.Syntax, + OtherFiles: act.Package.OtherFiles, + IgnoredFiles: act.Package.IgnoredFiles, + Pkg: act.Package.Types, + TypesInfo: act.Package.TypesInfo, + TypesSizes: act.Package.TypesSizes, + TypeErrors: act.Package.TypeErrors, + Module: module, + + ResultOf: inputs, + Report: func(d analysis.Diagnostic) { + // Assert that SuggestedFixes are well formed. + if err := analysisinternal.ValidateFixes(act.Package.Fset, act.Analyzer, d.SuggestedFixes); err != nil { + panic(err) + } + act.Diagnostics = append(act.Diagnostics, d) + }, + ImportObjectFact: act.ObjectFact, + ExportObjectFact: act.exportObjectFact, + ImportPackageFact: act.PackageFact, + ExportPackageFact: act.exportPackageFact, + AllObjectFacts: act.AllObjectFacts, + AllPackageFacts: act.AllPackageFacts, + } + readFile := os.ReadFile + if act.opts.readFile != nil { + readFile = act.opts.readFile + } + pass.ReadFile = analysisinternal.CheckedReadFile(pass, readFile) + act.pass = pass + + act.Result, act.Err = func() (any, error) { + if act.Package.IllTyped && !pass.Analyzer.RunDespiteErrors { + return nil, fmt.Errorf("analysis skipped due to errors in package") + } + + result, err := pass.Analyzer.Run(pass) + if err != nil { + return nil, err + } + + // correct result type? + if got, want := reflect.TypeOf(result), pass.Analyzer.ResultType; got != want { + return nil, fmt.Errorf( + "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v", + pass.Pkg.Path(), pass.Analyzer, got, want) + } + + // resolve diagnostic URLs + for i := range act.Diagnostics { + url, err := analysisflags.ResolveURL(act.Analyzer, act.Diagnostics[i]) + if err != nil { + return nil, err + } + act.Diagnostics[i].URL = url + } + return result, nil + }() + + // Help detect (disallowed) calls after Run. + pass.ExportObjectFact = nil + pass.ExportPackageFact = nil +} + +// inheritFacts populates act.facts with +// those it obtains from its dependency, dep. +func inheritFacts(act, dep *Action) { + for key, fact := range dep.objectFacts { + // Filter out facts related to objects + // that are irrelevant downstream + // (equivalently: not in the compiler export data). + if !exportedFrom(key.obj, dep.Package.Types) { + if false { + log.Printf("%v: discarding %T fact from %s for %s: %s", act, fact, dep, key.obj, fact) + } + continue + } + + // Optionally serialize/deserialize fact + // to verify that it works across address spaces. + if act.opts.SanityCheck { + encodedFact, err := codeFact(fact) + if err != nil { + log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) + } + fact = encodedFact + } + + if false { + log.Printf("%v: inherited %T fact for %s: %s", act, fact, key.obj, fact) + } + act.objectFacts[key] = fact + } + + for key, fact := range dep.packageFacts { + // TODO: filter out facts that belong to + // packages not mentioned in the export data + // to prevent side channels. + // + // The Pass.All{Object,Package}Facts accessors expose too much: + // all facts, of all types, for all dependencies in the action + // graph. Not only does the representation grow quadratically, + // but it violates the separate compilation paradigm, allowing + // analysis implementations to communicate with indirect + // dependencies that are not mentioned in the export data. + // + // It's not clear how to fix this short of a rather expensive + // filtering step after each action that enumerates all the + // objects that would appear in export data, and deletes + // facts associated with objects not in this set. + + // Optionally serialize/deserialize fact + // to verify that it works across address spaces + // and is deterministic. + if act.opts.SanityCheck { + encodedFact, err := codeFact(fact) + if err != nil { + log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) + } + fact = encodedFact + } + + if false { + log.Printf("%v: inherited %T fact for %s: %s", act, fact, key.pkg.Path(), fact) + } + act.packageFacts[key] = fact + } +} + +// codeFact encodes then decodes a fact, +// just to exercise that logic. +func codeFact(fact analysis.Fact) (analysis.Fact, error) { + // We encode facts one at a time. + // A real modular driver would emit all facts + // into one encoder to improve gob efficiency. + var buf bytes.Buffer + if err := gob.NewEncoder(&buf).Encode(fact); err != nil { + return nil, err + } + + // Encode it twice and assert that we get the same bits. + // This helps detect nondeterministic Gob encoding (e.g. of maps). + var buf2 bytes.Buffer + if err := gob.NewEncoder(&buf2).Encode(fact); err != nil { + return nil, err + } + if !bytes.Equal(buf.Bytes(), buf2.Bytes()) { + return nil, fmt.Errorf("encoding of %T fact is nondeterministic", fact) + } + + new := reflect.New(reflect.TypeOf(fact).Elem()).Interface().(analysis.Fact) + if err := gob.NewDecoder(&buf).Decode(new); err != nil { + return nil, err + } + return new, nil +} + +// exportedFrom reports whether obj may be visible to a package that imports pkg. +// This includes not just the exported members of pkg, but also unexported +// constants, types, fields, and methods, perhaps belonging to other packages, +// that find there way into the API. +// This is an overapproximation of the more accurate approach used by +// gc export data, which walks the type graph, but it's much simpler. +// +// TODO(adonovan): do more accurate filtering by walking the type graph. +func exportedFrom(obj types.Object, pkg *types.Package) bool { + switch obj := obj.(type) { + case *types.Func: + return obj.Exported() && obj.Pkg() == pkg || + obj.Type().(*types.Signature).Recv() != nil + case *types.Var: + if obj.IsField() { + return true + } + // we can't filter more aggressively than this because we need + // to consider function parameters exported, but have no way + // of telling apart function parameters from local variables. + return obj.Pkg() == pkg + case *types.TypeName, *types.Const: + return true + } + return false // Nil, Builtin, Label, or PkgName +} + +// ObjectFact retrieves a fact associated with obj, +// and returns true if one was found. +// Given a value ptr of type *T, where *T satisfies Fact, +// ObjectFact copies the value to *ptr. +// +// See documentation at ImportObjectFact field of [analysis.Pass]. +func (act *Action) ObjectFact(obj types.Object, ptr analysis.Fact) bool { + if obj == nil { + panic("nil object") + } + key := objectFactKey{obj, factType(ptr)} + if v, ok := act.objectFacts[key]; ok { + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem()) + return true + } + return false +} + +// exportObjectFact implements Pass.ExportObjectFact. +func (act *Action) exportObjectFact(obj types.Object, fact analysis.Fact) { + if act.pass.ExportObjectFact == nil { + log.Panicf("%s: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact) + } + + if obj.Pkg() != act.Package.Types { + log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package", + act.Analyzer, act.Package, obj, fact) + } + + key := objectFactKey{obj, factType(fact)} + act.objectFacts[key] = fact // clobber any existing entry + if log := act.opts.FactLog; log != nil { + objstr := types.ObjectString(obj, (*types.Package).Name) + fmt.Fprintf(log, "%s: object %s has fact %s\n", + act.Package.Fset.Position(obj.Pos()), objstr, fact) + } +} + +// AllObjectFacts returns a new slice containing all object facts of +// the analysis's FactTypes in unspecified order. +// +// See documentation at AllObjectFacts field of [analysis.Pass]. +func (act *Action) AllObjectFacts() []analysis.ObjectFact { + facts := make([]analysis.ObjectFact, 0, len(act.objectFacts)) + for k, fact := range act.objectFacts { + facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: fact}) + } + return facts +} + +// PackageFact retrieves a fact associated with package pkg, +// which must be this package or one of its dependencies. +// +// See documentation at ImportObjectFact field of [analysis.Pass]. +func (act *Action) PackageFact(pkg *types.Package, ptr analysis.Fact) bool { + if pkg == nil { + panic("nil package") + } + key := packageFactKey{pkg, factType(ptr)} + if v, ok := act.packageFacts[key]; ok { + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem()) + return true + } + return false +} + +// exportPackageFact implements Pass.ExportPackageFact. +func (act *Action) exportPackageFact(fact analysis.Fact) { + if act.pass.ExportPackageFact == nil { + log.Panicf("%s: Pass.ExportPackageFact(%T) called after Run", act, fact) + } + + key := packageFactKey{act.pass.Pkg, factType(fact)} + act.packageFacts[key] = fact // clobber any existing entry + if log := act.opts.FactLog; log != nil { + fmt.Fprintf(log, "%s: package %s has fact %s\n", + act.Package.Fset.Position(act.pass.Files[0].Pos()), act.pass.Pkg.Path(), fact) + } +} + +func factType(fact analysis.Fact) reflect.Type { + t := reflect.TypeOf(fact) + if t.Kind() != reflect.Ptr { + log.Fatalf("invalid Fact type: got %T, want pointer", fact) + } + return t +} + +// AllPackageFacts returns a new slice containing all package +// facts of the analysis's FactTypes in unspecified order. +// +// See documentation at AllPackageFacts field of [analysis.Pass]. +func (act *Action) AllPackageFacts() []analysis.PackageFact { + facts := make([]analysis.PackageFact, 0, len(act.packageFacts)) + for k, fact := range act.packageFacts { + facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: fact}) + } + return facts +} + +// forEach is a utility function for traversing the action graph. It +// applies function f to each action in the graph reachable from +// roots, in depth-first postorder. If any call to f returns an error, +// the traversal is aborted and ForEach returns the error. +func forEach(roots []*Action, f func(*Action) error) error { + seen := make(map[*Action]bool) + var visitAll func(actions []*Action) error + visitAll = func(actions []*Action) error { + for _, act := range actions { + if !seen[act] { + seen[act] = true + if err := visitAll(act.Deps); err != nil { + return err + } + if err := f(act); err != nil { + return err + } + } + } + return nil + } + return visitAll(roots) +} diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain_go121.go b/vendor/golang.org/x/tools/go/analysis/checker/iter_go122.go similarity index 53% rename from vendor/golang.org/x/tools/internal/versions/toolchain_go121.go rename to vendor/golang.org/x/tools/go/analysis/checker/iter_go122.go index b7ef216dfe..cd25cce035 100644 --- a/vendor/golang.org/x/tools/internal/versions/toolchain_go121.go +++ b/vendor/golang.org/x/tools/go/analysis/checker/iter_go122.go @@ -2,13 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.21 -// +build go1.21 +//go:build !go1.23 -package versions +package checker -func init() { - if Compare(toolchain, Go1_21) < 0 { - toolchain = Go1_21 - } -} +// This type is a placeholder for go1.23's iter.Seq[*Action]. +type actionSeq func(yield func(*Action) bool) diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain_go120.go b/vendor/golang.org/x/tools/go/analysis/checker/iter_go123.go similarity index 55% rename from vendor/golang.org/x/tools/internal/versions/toolchain_go120.go rename to vendor/golang.org/x/tools/go/analysis/checker/iter_go123.go index 1a9efa126c..e8278a9c1a 100644 --- a/vendor/golang.org/x/tools/internal/versions/toolchain_go120.go +++ b/vendor/golang.org/x/tools/go/analysis/checker/iter_go123.go @@ -2,13 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.20 -// +build go1.20 +//go:build go1.23 -package versions +package checker -func init() { - if Compare(toolchain, Go1_20) < 0 { - toolchain = Go1_20 - } -} +import "iter" + +type actionSeq = iter.Seq[*Action] diff --git a/vendor/golang.org/x/tools/go/analysis/checker/print.go b/vendor/golang.org/x/tools/go/analysis/checker/print.go new file mode 100644 index 0000000000..d7c0430117 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/checker/print.go @@ -0,0 +1,88 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package checker + +// This file defines helpers for printing analysis results. +// They should all be pure functions. + +import ( + "bytes" + "fmt" + "go/token" + "io" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/internal/analysisflags" +) + +// PrintText emits diagnostics as plain text to w. +// +// If contextLines is nonnegative, it also prints the +// offending line, plus that many lines of context +// before and after the line. +func (g *Graph) PrintText(w io.Writer, contextLines int) error { + return writeTextDiagnostics(w, g.Roots, contextLines) +} + +func writeTextDiagnostics(w io.Writer, roots []*Action, contextLines int) error { + // De-duplicate diagnostics by position (not token.Pos) to + // avoid double-reporting in source files that belong to + // multiple packages, such as foo and foo.test. + // (We cannot assume that such repeated files were parsed + // only once and use syntax nodes as the key.) + type key struct { + pos token.Position + end token.Position + *analysis.Analyzer + message string + } + seen := make(map[key]bool) + + // TODO(adonovan): opt: plumb errors back from PrintPlain and avoid buffer. + buf := new(bytes.Buffer) + forEach(roots, func(act *Action) error { + if act.Err != nil { + fmt.Fprintf(w, "%s: %v\n", act.Analyzer.Name, act.Err) + } else if act.IsRoot { + for _, diag := range act.Diagnostics { + // We don't display Analyzer.Name/diag.Category + // as most users don't care. + + posn := act.Package.Fset.Position(diag.Pos) + end := act.Package.Fset.Position(diag.End) + k := key{posn, end, act.Analyzer, diag.Message} + if seen[k] { + continue // duplicate + } + seen[k] = true + + analysisflags.PrintPlain(buf, act.Package.Fset, contextLines, diag) + } + } + return nil + }) + _, err := w.Write(buf.Bytes()) + return err +} + +// PrintJSON emits diagnostics in JSON form to w. +// Diagnostics are shown only for the root nodes, +// but errors (if any) are shown for all dependencies. +func (g *Graph) PrintJSON(w io.Writer) error { + return writeJSONDiagnostics(w, g.Roots) +} + +func writeJSONDiagnostics(w io.Writer, roots []*Action) error { + tree := make(analysisflags.JSONTree) + forEach(roots, func(act *Action) error { + var diags []analysis.Diagnostic + if act.IsRoot { + diags = act.Diagnostics + } + tree.Add(act.Package.Fset, act.Package.ID, act.Analyzer.Name, diags, act.Err) + return nil + }) + return tree.Print(w) +} diff --git a/vendor/golang.org/x/tools/go/analysis/diagnostic.go b/vendor/golang.org/x/tools/go/analysis/diagnostic.go index ee083a2d68..f6118bec64 100644 --- a/vendor/golang.org/x/tools/go/analysis/diagnostic.go +++ b/vendor/golang.org/x/tools/go/analysis/diagnostic.go @@ -65,7 +65,9 @@ type RelatedInformation struct { // user can choose to apply to their code. Usually the SuggestedFix is // meant to fix the issue flagged by the diagnostic. // -// The TextEdits must not overlap, nor contain edits for other packages. +// The TextEdits must not overlap, nor contain edits for other +// packages. Edits need not be totally ordered, but the order +// determines how insertions at the same point will be applied. type SuggestedFix struct { // A verb phrase describing the fix, to be shown to // a user trying to decide whether to accept it. diff --git a/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go b/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go index ff14ff58f9..c2445575cf 100644 --- a/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go +++ b/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go @@ -250,21 +250,12 @@ const ( setFalse ) -func triStateFlag(name string, value triState, usage string) *triState { - flag.Var(&value, name, usage) - return &value -} - // triState implements flag.Value, flag.Getter, and flag.boolFlag. // They work like boolean flags: we can say vet -printf as well as vet -printf=true func (ts *triState) Get() interface{} { return *ts == setTrue } -func (ts triState) isTrue() bool { - return ts == setTrue -} - func (ts *triState) Set(value string) error { b, err := strconv.ParseBool(value) if err != nil { @@ -316,15 +307,22 @@ var vetLegacyFlags = map[string]string{ } // ---- output helpers common to all drivers ---- +// +// These functions should not depend on global state (flags)! +// Really they belong in a different package. + +// TODO(adonovan): don't accept an io.Writer if we don't report errors. +// Either accept a bytes.Buffer (infallible), or return a []byte. -// PrintPlain prints a diagnostic in plain text form, -// with context specified by the -c flag. -func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) { +// PrintPlain prints a diagnostic in plain text form. +// If contextLines is nonnegative, it also prints the +// offending line plus this many lines of context. +func PrintPlain(out io.Writer, fset *token.FileSet, contextLines int, diag analysis.Diagnostic) { posn := fset.Position(diag.Pos) - fmt.Fprintf(os.Stderr, "%s: %s\n", posn, diag.Message) + fmt.Fprintf(out, "%s: %s\n", posn, diag.Message) - // -c=N: show offending line plus N lines of context. - if Context >= 0 { + // show offending line plus N lines of context. + if contextLines >= 0 { posn := fset.Position(diag.Pos) end := fset.Position(diag.End) if !end.IsValid() { @@ -332,9 +330,9 @@ func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) { } data, _ := os.ReadFile(posn.Filename) lines := strings.Split(string(data), "\n") - for i := posn.Line - Context; i <= end.Line+Context; i++ { + for i := posn.Line - contextLines; i <= end.Line+contextLines; i++ { if 1 <= i && i <= len(lines) { - fmt.Fprintf(os.Stderr, "%d\t%s\n", i, lines[i-1]) + fmt.Fprintf(out, "%d\t%s\n", i, lines[i-1]) } } } @@ -438,10 +436,11 @@ func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis. } } -func (tree JSONTree) Print() { +func (tree JSONTree) Print(out io.Writer) error { data, err := json.MarshalIndent(tree, "", "\t") if err != nil { log.Panicf("internal error: JSON marshaling failed: %v", err) } - fmt.Printf("%s\n", data) + _, err = fmt.Fprintf(out, "%s\n", data) + return err } diff --git a/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go index 8a802831c3..fb3c47b162 100644 --- a/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go +++ b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go @@ -2,37 +2,40 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package checker defines the implementation of the checker commands. -// The same code drives the multi-analysis driver, the single-analysis -// driver that is conventionally provided for convenience along with -// each analysis package, and the test driver. +// Package internal/checker defines various implementation helpers for +// the singlechecker and multichecker packages, which provide the +// complete main function for an analysis driver executable +// based on go/packages. +// +// (Note: it is not used by the public 'checker' package, since the +// latter provides a set of pure functions for use as building blocks.) package checker +// TODO(adonovan): publish the JSON schema in go/analysis or analysisjson. + import ( - "bytes" - "encoding/gob" "flag" "fmt" "go/format" - "go/token" - "go/types" + "io" + "maps" + "log" "os" - "reflect" "runtime" "runtime/pprof" "runtime/trace" "sort" "strings" - "sync" "time" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/checker" + "golang.org/x/tools/go/analysis/internal" "golang.org/x/tools/go/analysis/internal/analysisflags" "golang.org/x/tools/go/packages" "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/diff" - "golang.org/x/tools/internal/robustio" ) var ( @@ -52,8 +55,12 @@ var ( // IncludeTests indicates whether test files should be analyzed too. IncludeTests = true - // Fix determines whether to apply all suggested fixes. + // Fix determines whether to apply (!Diff) or display (Diff) all suggested fixes. Fix bool + + // Diff causes the file updates to be displayed, but not applied. + // This flag has no effect unless Fix is true. + Diff bool ) // RegisterFlags registers command-line flags used by the analysis driver. @@ -69,6 +76,7 @@ func RegisterFlags() { flag.BoolVar(&IncludeTests, "test", IncludeTests, "indicates whether test files should be analyzed, too") flag.BoolVar(&Fix, "fix", false, "apply all suggested fixes") + flag.BoolVar(&Diff, "diff", false, "with -fix, don't update the files, but print a unified diff") } // Run loads the packages specified by args using go/packages, @@ -78,7 +86,7 @@ func RegisterFlags() { // It provides most of the logic for the main functions of both the // singlechecker and the multi-analysis commands. // It returns the appropriate exit code. -func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) { +func Run(args []string, analyzers []*analysis.Analyzer) int { if CPUProfile != "" { f, err := os.Create(CPUProfile) if err != nil { @@ -137,6 +145,9 @@ func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) { return 1 } + // TODO(adonovan): simplify exit code logic by using a single + // exit code variable and applying "code = max(code, X)" each + // time an error of code X occurs. pkgsExitCode := 0 // Print package and module errors regardless of RunDespiteErrors. // Do not exit if there are errors, yet. @@ -144,31 +155,117 @@ func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) { pkgsExitCode = 1 } - // Run the analyzers. On each package with (transitive) - // errors, we run only the subset of analyzers that are - // marked (and whose transitive requirements are also - // marked) with RunDespiteErrors. - roots := analyze(initial, analyzers) + var factLog io.Writer + if dbg('f') { + factLog = os.Stderr + } + + // Run the analysis. + opts := &checker.Options{ + SanityCheck: dbg('s'), + Sequential: dbg('p'), + FactLog: factLog, + } + if dbg('v') { + log.Printf("building graph of analysis passes") + } + graph, err := checker.Analyze(analyzers, initial, opts) + if err != nil { + log.Print(err) + return 1 + } - // Apply fixes. + // Don't print the diagnostics, + // but apply all fixes from the root actions. if Fix { - if err := applyFixes(roots); err != nil { + if err := applyFixes(graph.Roots, Diff); err != nil { // Fail when applying fixes failed. log.Print(err) return 1 } + // TODO(adonovan): don't proceed to print the text or JSON output + // if we applied fixes; stop here. + // + // return pkgsExitCode } // Print the results. If !RunDespiteErrors and there // are errors in the packages, this will have 0 exit // code. Otherwise, we prefer to return exit code // indicating diagnostics. - if diagExitCode := printDiagnostics(roots); diagExitCode != 0 { + if diagExitCode := printDiagnostics(graph); diagExitCode != 0 { return diagExitCode // there were diagnostics } return pkgsExitCode // package errors but no diagnostics } +// printDiagnostics prints diagnostics in text or JSON form +// and returns the appropriate exit code. +func printDiagnostics(graph *checker.Graph) (exitcode int) { + // Print the results. + // With -json, the exit code is always zero. + if analysisflags.JSON { + if err := graph.PrintJSON(os.Stdout); err != nil { + return 1 + } + } else { + if err := graph.PrintText(os.Stderr, analysisflags.Context); err != nil { + return 1 + } + + // Compute the exit code. + var numErrors, rootDiags int + // TODO(adonovan): use "for act := range graph.All() { ... }" in go1.23. + graph.All()(func(act *checker.Action) bool { + if act.Err != nil { + numErrors++ + } else if act.IsRoot { + rootDiags += len(act.Diagnostics) + } + return true + }) + if numErrors > 0 { + exitcode = 1 // analysis failed, at least partially + } else if rootDiags > 0 { + exitcode = 3 // successfully produced diagnostics + } + } + + // Print timing info. + if dbg('t') { + if !dbg('p') { + log.Println("Warning: times are mostly GC/scheduler noise; use -debug=tp to disable parallelism") + } + + var list []*checker.Action + var total time.Duration + // TODO(adonovan): use "for act := range graph.All() { ... }" in go1.23. + graph.All()(func(act *checker.Action) bool { + list = append(list, act) + total += act.Duration + return true + }) + + // Print actions accounting for 90% of the total. + sort.Slice(list, func(i, j int) bool { + return list[i].Duration > list[j].Duration + }) + var sum time.Duration + for _, act := range list { + fmt.Fprintf(os.Stderr, "%s\t%s\n", act.Duration, act) + sum += act.Duration + if sum >= total*9/10 { + break + } + } + if total > sum { + fmt.Fprintf(os.Stderr, "%s\tall others\n", total-sum) + } + } + + return exitcode +} + // load loads the initial packages. Returns only top-level loading // errors. Does not consider errors in packages. func load(patterns []string, allSyntax bool) ([]*packages.Package, error) { @@ -178,7 +275,13 @@ func load(patterns []string, allSyntax bool) ([]*packages.Package, error) { } mode |= packages.NeedModule conf := packages.Config{ - Mode: mode, + Mode: mode, + // Ensure that child process inherits correct alias of PWD. + // (See discussion at Dir field of [exec.Command].) + // However, this currently breaks some tests. + // TODO(adonovan): Investigate. + // + // Dir: os.Getenv("PWD"), Tests: IncludeTests, } initial, err := packages.Load(&conf, patterns...) @@ -188,408 +291,257 @@ func load(patterns []string, allSyntax bool) ([]*packages.Package, error) { return initial, err } -// TestAnalyzer applies an analyzer to a set of packages (and their -// dependencies if necessary) and returns the results. -// The analyzer must be valid according to [analysis.Validate]. +// applyFixes attempts to apply the first suggested fix associated +// with each diagnostic reported by the specified actions. +// All fixes must have been validated by [analysisinternal.ValidateFixes]. // -// Facts about pkg are returned in a map keyed by object; package facts -// have a nil key. +// Each fix is treated as an independent change; fixes are merged in +// an arbitrary deterministic order as if by a three-way diff tool +// such as the UNIX diff3 command or 'git merge'. Any fix that cannot be +// cleanly merged is discarded, in which case the final summary tells +// the user to re-run the tool. +// TODO(adonovan): make the checker tool re-run the analysis itself. // -// This entry point is used only by analysistest. -func TestAnalyzer(a *analysis.Analyzer, pkgs []*packages.Package) []*TestAnalyzerResult { - var results []*TestAnalyzerResult - for _, act := range analyze(pkgs, []*analysis.Analyzer{a}) { - facts := make(map[types.Object][]analysis.Fact) - for key, fact := range act.objectFacts { - if key.obj.Pkg() == act.pass.Pkg { - facts[key.obj] = append(facts[key.obj], fact) - } - } - for key, fact := range act.packageFacts { - if key.pkg == act.pass.Pkg { - facts[nil] = append(facts[nil], fact) - } - } - - results = append(results, &TestAnalyzerResult{act.pass, act.diagnostics, facts, act.result, act.err}) - } - return results -} - -type TestAnalyzerResult struct { - Pass *analysis.Pass - Diagnostics []analysis.Diagnostic - Facts map[types.Object][]analysis.Fact - Result interface{} - Err error -} - -func analyze(pkgs []*packages.Package, analyzers []*analysis.Analyzer) []*action { - // Construct the action graph. - if dbg('v') { - log.Printf("building graph of analysis passes") - } +// When the same file is analyzed as a member of both a primary +// package "p" and a test-augmented package "p [p.test]", there may be +// duplicate diagnostics and fixes. One set of fixes will be applied +// and the other will be discarded; but re-running the tool may then +// show zero fixes, which may cause the confused user to wonder what +// happened to the other ones. +// TODO(adonovan): consider pre-filtering completely identical fixes. +// +// A common reason for overlapping fixes is duplicate additions of the +// same import. The merge algorithm may often cleanly resolve such +// fixes, coalescing identical edits, but the merge may sometimes be +// confused by nearby changes. +// +// Even when merging succeeds, there is no guarantee that the +// composition of the two fixes is semantically correct. Coalescing +// identical edits is appropriate for imports, but not for, say, +// increments to a counter variable; the correct resolution in that +// case might be to increment it twice. Or consider two fixes that +// each delete the penultimate reference to an import or local +// variable: each fix is sound individually, and they may be textually +// distant from each other, but when both are applied, the program is +// no longer valid because it has an unreferenced import or local +// variable. +// TODO(adonovan): investigate replacing the final "gofmt" step with a +// formatter that applies the unused-import deletion logic of +// "goimports". +// +// Merging depends on both the order of fixes and they order of edits +// within them. For example, if three fixes add import "a" twice and +// import "b" once, the two imports of "a" may be combined if they +// appear in order [a, a, b], or not if they appear as [a, b, a]. +// TODO(adonovan): investigate an algebraic approach to imports; +// that is, for fixes to Go source files, convert changes within the +// import(...) portion of the file into semantic edits, compose those +// edits algebraically, then convert the result back to edits. +// +// applyFixes returns success if all fixes are valid, could be cleanly +// merged, and the corresponding files were successfully updated. +// +// If showDiff, instead of updating the files it display the final +// patch composed of all the cleanly merged fixes. +// +// TODO(adonovan): handle file-system level aliases such as symbolic +// links using robustio.FileID. +func applyFixes(actions []*checker.Action, showDiff bool) error { - // Each graph node (action) is one unit of analysis. - // Edges express package-to-package (vertical) dependencies, - // and analysis-to-analysis (horizontal) dependencies. - type key struct { - *analysis.Analyzer - *packages.Package + // Select fixes to apply. + // + // If there are several for a given Diagnostic, choose the first. + // Preserve the order of iteration, for determinism. + type fixact struct { + fix *analysis.SuggestedFix + act *checker.Action } - actions := make(map[key]*action) - - var mkAction func(a *analysis.Analyzer, pkg *packages.Package) *action - mkAction = func(a *analysis.Analyzer, pkg *packages.Package) *action { - k := key{a, pkg} - act, ok := actions[k] - if !ok { - act = &action{a: a, pkg: pkg} - - // Add a dependency on each required analyzers. - for _, req := range a.Requires { - act.deps = append(act.deps, mkAction(req, pkg)) - } - - // An analysis that consumes/produces facts - // must run on the package's dependencies too. - if len(a.FactTypes) > 0 { - paths := make([]string, 0, len(pkg.Imports)) - for path := range pkg.Imports { - paths = append(paths, path) - } - sort.Strings(paths) // for determinism - for _, path := range paths { - dep := mkAction(a, pkg.Imports[path]) - act.deps = append(act.deps, dep) + var fixes []*fixact + for _, act := range actions { + for _, diag := range act.Diagnostics { + for i := range diag.SuggestedFixes { + fix := &diag.SuggestedFixes[i] + if i == 0 { + fixes = append(fixes, &fixact{fix, act}) + } else { + // TODO(adonovan): abstract the logger. + log.Printf("%s: ignoring alternative fix %q", act, fix.Message) } } - - actions[k] = act } - return act } - // Build nodes for initial packages. - var roots []*action - for _, a := range analyzers { - for _, pkg := range pkgs { - root := mkAction(a, pkg) - root.isroot = true - roots = append(roots, root) - } - } - - // Execute the graph in parallel. - execAll(roots) - - return roots -} - -func applyFixes(roots []*action) error { - // visit all of the actions and accumulate the suggested edits. - paths := make(map[robustio.FileID]string) - editsByAction := make(map[robustio.FileID]map[*action][]diff.Edit) - visited := make(map[*action]bool) - var apply func(*action) error - var visitAll func(actions []*action) error - visitAll = func(actions []*action) error { - for _, act := range actions { - if !visited[act] { - visited[act] = true - if err := visitAll(act.deps); err != nil { - return err - } - if err := apply(act); err != nil { - return err - } + // Read file content on demand, from the virtual + // file system that fed the analyzer (see #62292). + // + // This cache assumes that all successful reads for the same + // file name return the same content. + // (It is tempting to group fixes by package and do the + // merge/apply/format steps one package at a time, but + // packages are not disjoint, due to test variants, so this + // would not really address the issue.) + baselineContent := make(map[string][]byte) + getBaseline := func(readFile analysisinternal.ReadFileFunc, filename string) ([]byte, error) { + content, ok := baselineContent[filename] + if !ok { + var err error + content, err = readFile(filename) + if err != nil { + return nil, err } + baselineContent[filename] = content } - return nil + return content, nil } - apply = func(act *action) error { - editsForTokenFile := make(map[*token.File][]diff.Edit) - for _, diag := range act.diagnostics { - for _, sf := range diag.SuggestedFixes { - for _, edit := range sf.TextEdits { - // Validate the edit. - // Any error here indicates a bug in the analyzer. - start, end := edit.Pos, edit.End - file := act.pkg.Fset.File(start) - if file == nil { - return fmt.Errorf("analysis %q suggests invalid fix: missing file info for pos (%v)", - act.a.Name, start) - } - if !end.IsValid() { - end = start - } - if start > end { - return fmt.Errorf("analysis %q suggests invalid fix: pos (%v) > end (%v)", - act.a.Name, start, end) - } - if eof := token.Pos(file.Base() + file.Size()); end > eof { - return fmt.Errorf("analysis %q suggests invalid fix: end (%v) past end of file (%v)", - act.a.Name, end, eof) - } - edit := diff.Edit{ - Start: file.Offset(start), - End: file.Offset(end), - New: string(edit.NewText), - } - editsForTokenFile[file] = append(editsForTokenFile[file], edit) - } - } - } + // Apply each fix, updating the current state + // only if the entire fix can be cleanly merged. + accumulatedEdits := make(map[string][]diff.Edit) + goodFixes := 0 +fixloop: + for _, fixact := range fixes { + readFile := internal.Pass(fixact.act).ReadFile + + // Convert analysis.TextEdits to diff.Edits, grouped by file. + // Precondition: a prior call to validateFix succeeded. + fileEdits := make(map[string][]diff.Edit) + fset := fixact.act.Package.Fset + for _, edit := range fixact.fix.TextEdits { + file := fset.File(edit.Pos) - for f, edits := range editsForTokenFile { - id, _, err := robustio.GetFileID(f.Name()) + baseline, err := getBaseline(readFile, file.Name()) if err != nil { - return err + log.Printf("skipping fix to file %s: %v", file.Name(), err) + continue fixloop } - if _, hasId := paths[id]; !hasId { - paths[id] = f.Name() - editsByAction[id] = make(map[*action][]diff.Edit) - } - editsByAction[id][act] = edits - } - return nil - } - - if err := visitAll(roots); err != nil { - return err - } - // Validate and group the edits to each actual file. - editsByPath := make(map[string][]diff.Edit) - for id, actToEdits := range editsByAction { - path := paths[id] - actions := make([]*action, 0, len(actToEdits)) - for act := range actToEdits { - actions = append(actions, act) - } - - // Does any action create conflicting edits? - for _, act := range actions { - edits := actToEdits[act] - if _, invalid := validateEdits(edits); invalid > 0 { - name, x, y := act.a.Name, edits[invalid-1], edits[invalid] - return diff3Conflict(path, name, name, []diff.Edit{x}, []diff.Edit{y}) + // We choose to treat size mismatch as a serious error, + // as it indicates a concurrent write to at least one file, + // and possibly others (consider a git checkout, for example). + if file.Size() != len(baseline) { + return fmt.Errorf("concurrent file modification detected in file %s (size changed from %d -> %d bytes); aborting fix", + file.Name(), file.Size(), len(baseline)) } - } - // Does any pair of different actions create edits that conflict? - for j := range actions { - for k := range actions[:j] { - x, y := actions[j], actions[k] - if x.a.Name > y.a.Name { - x, y = y, x - } - xedits, yedits := actToEdits[x], actToEdits[y] - combined := append(xedits, yedits...) - if _, invalid := validateEdits(combined); invalid > 0 { - // TODO: consider applying each action's consistent list of edits entirely, - // and then using a three-way merge (such as GNU diff3) on the resulting - // files to report more precisely the parts that actually conflict. - return diff3Conflict(path, x.a.Name, y.a.Name, xedits, yedits) + fileEdits[file.Name()] = append(fileEdits[file.Name()], diff.Edit{ + Start: file.Offset(edit.Pos), + End: file.Offset(edit.End), + New: string(edit.NewText), + }) + } + + // Apply each set of edits by merging atop + // the previous accumulated state. + after := make(map[string][]diff.Edit) + for file, edits := range fileEdits { + if prev := accumulatedEdits[file]; len(prev) > 0 { + merged, ok := diff.Merge(prev, edits) + if !ok { + // debugging + if false { + log.Printf("%s: fix %s conflicts", fixact.act, fixact.fix.Message) + } + continue fixloop // conflict } + edits = merged } + after[file] = edits } - var edits []diff.Edit - for act := range actToEdits { - edits = append(edits, actToEdits[act]...) + // The entire fix applied cleanly; commit it. + goodFixes++ + maps.Copy(accumulatedEdits, after) + // debugging + if false { + log.Printf("%s: fix %s applied", fixact.act, fixact.fix.Message) } - editsByPath[path], _ = validateEdits(edits) // remove duplicates. already validated. } + badFixes := len(fixes) - goodFixes - // Now we've got a set of valid edits for each file. Apply them. - for path, edits := range editsByPath { - // TODO(adonovan): this should really work on the same - // gulp from the file system that fed the analyzer (see #62292). - contents, err := os.ReadFile(path) - if err != nil { - return err + // Show diff or update files to final state. + var files []string + for file := range accumulatedEdits { + files = append(files, file) + } + sort.Strings(files) // for deterministic -diff + var filesUpdated, totalFiles int + for _, file := range files { + edits := accumulatedEdits[file] + if len(edits) == 0 { + continue // the diffs annihilated (a miracle?) } - out, err := diff.ApplyBytes(contents, edits) + // Apply accumulated fixes. + baseline := baselineContent[file] // (cache hit) + final, err := diff.ApplyBytes(baseline, edits) if err != nil { - return err + log.Fatalf("internal error in diff.ApplyBytes: %v", err) } - // Try to format the file. - if formatted, err := format.Source(out); err == nil { - out = formatted + // Attempt to format each file. + if formatted, err := format.Source(final); err == nil { + final = formatted } - if err := os.WriteFile(path, out, 0644); err != nil { - return err - } - } - return nil -} + if showDiff { + // Since we formatted the file, we need to recompute the diff. + unified := diff.Unified(file+" (old)", file+" (new)", string(baseline), string(final)) + // TODO(adonovan): abstract the I/O. + os.Stdout.WriteString(unified) -// validateEdits returns a list of edits that is sorted and -// contains no duplicate edits. Returns the index of some -// overlapping adjacent edits if there is one and <0 if the -// edits are valid. -func validateEdits(edits []diff.Edit) ([]diff.Edit, int) { - if len(edits) == 0 { - return nil, -1 - } - equivalent := func(x, y diff.Edit) bool { - return x.Start == y.Start && x.End == y.End && x.New == y.New - } - diff.SortEdits(edits) - unique := []diff.Edit{edits[0]} - invalid := -1 - for i := 1; i < len(edits); i++ { - prev, cur := edits[i-1], edits[i] - // We skip over equivalent edits without considering them - // an error. This handles identical edits coming from the - // multiple ways of loading a package into a - // *go/packages.Packages for testing, e.g. packages "p" and "p [p.test]". - if !equivalent(prev, cur) { - unique = append(unique, cur) - if prev.End > cur.Start { - invalid = i + } else { + // write + totalFiles++ + // TODO(adonovan): abstract the I/O. + if err := os.WriteFile(file, final, 0644); err != nil { + log.Println(err) + continue } + filesUpdated++ } } - return unique, invalid -} -// diff3Conflict returns an error describing two conflicting sets of -// edits on a file at path. -func diff3Conflict(path string, xlabel, ylabel string, xedits, yedits []diff.Edit) error { - contents, err := os.ReadFile(path) - if err != nil { - return err - } - oldlabel, old := "base", string(contents) + // TODO(adonovan): consider returning a structured result that + // maps each SuggestedFix to its status: + // - invalid + // - secondary, not selected + // - applied + // - had conflicts. + // and a mapping from each affected file to: + // - its final/original content pair, and + // - whether formatting was successful. + // Then file writes and the UI can be applied by the caller + // in whatever form they like. - xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits, diff.DefaultContextLines) - if err != nil { - return err - } - ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits, diff.DefaultContextLines) - if err != nil { - return err - } - - return fmt.Errorf("conflicting edits from %s and %s on %s\nfirst edits:\n%s\nsecond edits:\n%s", - xlabel, ylabel, path, xdiff, ydiff) -} - -// printDiagnostics prints the diagnostics for the root packages in either -// plain text or JSON format. JSON format also includes errors for any -// dependencies. -// -// It returns the exitcode: in plain mode, 0 for success, 1 for analysis -// errors, and 3 for diagnostics. We avoid 2 since the flag package uses -// it. JSON mode always succeeds at printing errors and diagnostics in a -// structured form to stdout. -func printDiagnostics(roots []*action) (exitcode int) { - // Print the output. + // If victory was incomplete, report an error that indicates partial progress. // - // Print diagnostics only for root packages, - // but errors for all packages. - printed := make(map[*action]bool) - var print func(*action) - var visitAll func(actions []*action) - visitAll = func(actions []*action) { - for _, act := range actions { - if !printed[act] { - printed[act] = true - visitAll(act.deps) - print(act) - } - } - } - - if analysisflags.JSON { - // JSON output - tree := make(analysisflags.JSONTree) - print = func(act *action) { - var diags []analysis.Diagnostic - if act.isroot { - diags = act.diagnostics - } - tree.Add(act.pkg.Fset, act.pkg.ID, act.a.Name, diags, act.err) - } - visitAll(roots) - tree.Print() - } else { - // plain text output - - // De-duplicate diagnostics by position (not token.Pos) to - // avoid double-reporting in source files that belong to - // multiple packages, such as foo and foo.test. - type key struct { - pos token.Position - end token.Position - *analysis.Analyzer - message string - } - seen := make(map[key]bool) - - print = func(act *action) { - if act.err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", act.a.Name, act.err) - exitcode = 1 // analysis failed, at least partially - return - } - if act.isroot { - for _, diag := range act.diagnostics { - // We don't display a.Name/f.Category - // as most users don't care. - - posn := act.pkg.Fset.Position(diag.Pos) - end := act.pkg.Fset.Position(diag.End) - k := key{posn, end, act.a, diag.Message} - if seen[k] { - continue // duplicate - } - seen[k] = true - - analysisflags.PrintPlain(act.pkg.Fset, diag) - } - } - } - visitAll(roots) - - if exitcode == 0 && len(seen) > 0 { - exitcode = 3 // successfully produced diagnostics - } - } - - // Print timing info. - if dbg('t') { - if !dbg('p') { - log.Println("Warning: times are mostly GC/scheduler noise; use -debug=tp to disable parallelism") - } - var all []*action - var total time.Duration - for act := range printed { - all = append(all, act) - total += act.duration - } - sort.Slice(all, func(i, j int) bool { - return all[i].duration > all[j].duration - }) - - // Print actions accounting for 90% of the total. - var sum time.Duration - for _, act := range all { - fmt.Fprintf(os.Stderr, "%s\t%s\n", act.duration, act) - sum += act.duration - if sum >= total*9/10 { - break - } + // badFixes > 0 indicates that we decided not to attempt some + // fixes due to conflicts or failure to read the source; still + // it's a relatively benign situation since the user can + // re-run the tool, and we may still make progress. + // + // filesUpdated < totalFiles indicates that some file updates + // failed. This should be rare, but is a serious error as it + // may apply half a fix, or leave the files in a bad state. + // + // These numbers are potentially misleading: + // The denominator includes duplicate conflicting fixes due to + // common files in packages "p" and "p [p.test]", which may + // have been fixed fixed and won't appear in the re-run. + // TODO(adonovan): eliminate identical fixes as an initial + // filtering step. + // + // TODO(adonovan): should we log that n files were updated in case of total victory? + if badFixes > 0 || filesUpdated < totalFiles { + if showDiff { + return fmt.Errorf("%d of %d fixes skipped (e.g. due to conflicts)", badFixes, len(fixes)) + } else { + return fmt.Errorf("applied %d of %d fixes; %d files updated. (Re-run the command to apply more.)", + goodFixes, len(fixes), filesUpdated) } } - return exitcode + return nil } // needFacts reports whether any analysis required by the specified set @@ -612,373 +564,4 @@ func needFacts(analyzers []*analysis.Analyzer) bool { return false } -// An action represents one unit of analysis work: the application of -// one analysis to one package. Actions form a DAG, both within a -// package (as different analyzers are applied, either in sequence or -// parallel), and across packages (as dependencies are analyzed). -type action struct { - once sync.Once - a *analysis.Analyzer - pkg *packages.Package - pass *analysis.Pass - isroot bool - deps []*action - objectFacts map[objectFactKey]analysis.Fact - packageFacts map[packageFactKey]analysis.Fact - result interface{} - diagnostics []analysis.Diagnostic - err error - duration time.Duration -} - -type objectFactKey struct { - obj types.Object - typ reflect.Type -} - -type packageFactKey struct { - pkg *types.Package - typ reflect.Type -} - -func (act *action) String() string { - return fmt.Sprintf("%s@%s", act.a, act.pkg) -} - -func execAll(actions []*action) { - sequential := dbg('p') - var wg sync.WaitGroup - for _, act := range actions { - wg.Add(1) - work := func(act *action) { - act.exec() - wg.Done() - } - if sequential { - work(act) - } else { - go work(act) - } - } - wg.Wait() -} - -func (act *action) exec() { act.once.Do(act.execOnce) } - -func (act *action) execOnce() { - // Analyze dependencies. - execAll(act.deps) - - // TODO(adonovan): uncomment this during profiling. - // It won't build pre-go1.11 but conditional compilation - // using build tags isn't warranted. - // - // ctx, task := trace.NewTask(context.Background(), "exec") - // trace.Log(ctx, "pass", act.String()) - // defer task.End() - - // Record time spent in this node but not its dependencies. - // In parallel mode, due to GC/scheduler contention, the - // time is 5x higher than in sequential mode, even with a - // semaphore limiting the number of threads here. - // So use -debug=tp. - if dbg('t') { - t0 := time.Now() - defer func() { act.duration = time.Since(t0) }() - } - - // Report an error if any dependency failed. - var failed []string - for _, dep := range act.deps { - if dep.err != nil { - failed = append(failed, dep.String()) - } - } - if failed != nil { - sort.Strings(failed) - act.err = fmt.Errorf("failed prerequisites: %s", strings.Join(failed, ", ")) - return - } - - // Plumb the output values of the dependencies - // into the inputs of this action. Also facts. - inputs := make(map[*analysis.Analyzer]interface{}) - act.objectFacts = make(map[objectFactKey]analysis.Fact) - act.packageFacts = make(map[packageFactKey]analysis.Fact) - for _, dep := range act.deps { - if dep.pkg == act.pkg { - // Same package, different analysis (horizontal edge): - // in-memory outputs of prerequisite analyzers - // become inputs to this analysis pass. - inputs[dep.a] = dep.result - - } else if dep.a == act.a { // (always true) - // Same analysis, different package (vertical edge): - // serialized facts produced by prerequisite analysis - // become available to this analysis pass. - inheritFacts(act, dep) - } - } - - module := &analysis.Module{} // possibly empty (non nil) in go/analysis drivers. - if mod := act.pkg.Module; mod != nil { - module.Path = mod.Path - module.Version = mod.Version - module.GoVersion = mod.GoVersion - } - - // Run the analysis. - pass := &analysis.Pass{ - Analyzer: act.a, - Fset: act.pkg.Fset, - Files: act.pkg.Syntax, - OtherFiles: act.pkg.OtherFiles, - IgnoredFiles: act.pkg.IgnoredFiles, - Pkg: act.pkg.Types, - TypesInfo: act.pkg.TypesInfo, - TypesSizes: act.pkg.TypesSizes, - TypeErrors: act.pkg.TypeErrors, - Module: module, - - ResultOf: inputs, - Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) }, - ImportObjectFact: act.importObjectFact, - ExportObjectFact: act.exportObjectFact, - ImportPackageFact: act.importPackageFact, - ExportPackageFact: act.exportPackageFact, - AllObjectFacts: act.allObjectFacts, - AllPackageFacts: act.allPackageFacts, - } - pass.ReadFile = analysisinternal.MakeReadFile(pass) - act.pass = pass - - var err error - if act.pkg.IllTyped && !pass.Analyzer.RunDespiteErrors { - err = fmt.Errorf("analysis skipped due to errors in package") - } else { - act.result, err = pass.Analyzer.Run(pass) - if err == nil { - if got, want := reflect.TypeOf(act.result), pass.Analyzer.ResultType; got != want { - err = fmt.Errorf( - "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v", - pass.Pkg.Path(), pass.Analyzer, got, want) - } - } - } - if err == nil { // resolve diagnostic URLs - for i := range act.diagnostics { - if url, uerr := analysisflags.ResolveURL(act.a, act.diagnostics[i]); uerr == nil { - act.diagnostics[i].URL = url - } else { - err = uerr // keep the last error - } - } - } - act.err = err - - // disallow calls after Run - pass.ExportObjectFact = nil - pass.ExportPackageFact = nil -} - -// inheritFacts populates act.facts with -// those it obtains from its dependency, dep. -func inheritFacts(act, dep *action) { - serialize := dbg('s') - - for key, fact := range dep.objectFacts { - // Filter out facts related to objects - // that are irrelevant downstream - // (equivalently: not in the compiler export data). - if !exportedFrom(key.obj, dep.pkg.Types) { - if false { - log.Printf("%v: discarding %T fact from %s for %s: %s", act, fact, dep, key.obj, fact) - } - continue - } - - // Optionally serialize/deserialize fact - // to verify that it works across address spaces. - if serialize { - encodedFact, err := codeFact(fact) - if err != nil { - log.Panicf("internal error: encoding of %T fact failed in %v: %v", fact, act, err) - } - fact = encodedFact - } - - if false { - log.Printf("%v: inherited %T fact for %s: %s", act, fact, key.obj, fact) - } - act.objectFacts[key] = fact - } - - for key, fact := range dep.packageFacts { - // TODO: filter out facts that belong to - // packages not mentioned in the export data - // to prevent side channels. - - // Optionally serialize/deserialize fact - // to verify that it works across address spaces - // and is deterministic. - if serialize { - encodedFact, err := codeFact(fact) - if err != nil { - log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) - } - fact = encodedFact - } - - if false { - log.Printf("%v: inherited %T fact for %s: %s", act, fact, key.pkg.Path(), fact) - } - act.packageFacts[key] = fact - } -} - -// codeFact encodes then decodes a fact, -// just to exercise that logic. -func codeFact(fact analysis.Fact) (analysis.Fact, error) { - // We encode facts one at a time. - // A real modular driver would emit all facts - // into one encoder to improve gob efficiency. - var buf bytes.Buffer - if err := gob.NewEncoder(&buf).Encode(fact); err != nil { - return nil, err - } - - // Encode it twice and assert that we get the same bits. - // This helps detect nondeterministic Gob encoding (e.g. of maps). - var buf2 bytes.Buffer - if err := gob.NewEncoder(&buf2).Encode(fact); err != nil { - return nil, err - } - if !bytes.Equal(buf.Bytes(), buf2.Bytes()) { - return nil, fmt.Errorf("encoding of %T fact is nondeterministic", fact) - } - - new := reflect.New(reflect.TypeOf(fact).Elem()).Interface().(analysis.Fact) - if err := gob.NewDecoder(&buf).Decode(new); err != nil { - return nil, err - } - return new, nil -} - -// exportedFrom reports whether obj may be visible to a package that imports pkg. -// This includes not just the exported members of pkg, but also unexported -// constants, types, fields, and methods, perhaps belonging to other packages, -// that find there way into the API. -// This is an overapproximation of the more accurate approach used by -// gc export data, which walks the type graph, but it's much simpler. -// -// TODO(adonovan): do more accurate filtering by walking the type graph. -func exportedFrom(obj types.Object, pkg *types.Package) bool { - switch obj := obj.(type) { - case *types.Func: - return obj.Exported() && obj.Pkg() == pkg || - obj.Type().(*types.Signature).Recv() != nil - case *types.Var: - if obj.IsField() { - return true - } - // we can't filter more aggressively than this because we need - // to consider function parameters exported, but have no way - // of telling apart function parameters from local variables. - return obj.Pkg() == pkg - case *types.TypeName, *types.Const: - return true - } - return false // Nil, Builtin, Label, or PkgName -} - -// importObjectFact implements Pass.ImportObjectFact. -// Given a non-nil pointer ptr of type *T, where *T satisfies Fact, -// importObjectFact copies the fact value to *ptr. -func (act *action) importObjectFact(obj types.Object, ptr analysis.Fact) bool { - if obj == nil { - panic("nil object") - } - key := objectFactKey{obj, factType(ptr)} - if v, ok := act.objectFacts[key]; ok { - reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem()) - return true - } - return false -} - -// exportObjectFact implements Pass.ExportObjectFact. -func (act *action) exportObjectFact(obj types.Object, fact analysis.Fact) { - if act.pass.ExportObjectFact == nil { - log.Panicf("%s: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact) - } - - if obj.Pkg() != act.pkg.Types { - log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package", - act.a, act.pkg, obj, fact) - } - - key := objectFactKey{obj, factType(fact)} - act.objectFacts[key] = fact // clobber any existing entry - if dbg('f') { - objstr := types.ObjectString(obj, (*types.Package).Name) - fmt.Fprintf(os.Stderr, "%s: object %s has fact %s\n", - act.pkg.Fset.Position(obj.Pos()), objstr, fact) - } -} - -// allObjectFacts implements Pass.AllObjectFacts. -func (act *action) allObjectFacts() []analysis.ObjectFact { - facts := make([]analysis.ObjectFact, 0, len(act.objectFacts)) - for k := range act.objectFacts { - facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: act.objectFacts[k]}) - } - return facts -} - -// importPackageFact implements Pass.ImportPackageFact. -// Given a non-nil pointer ptr of type *T, where *T satisfies Fact, -// fact copies the fact value to *ptr. -func (act *action) importPackageFact(pkg *types.Package, ptr analysis.Fact) bool { - if pkg == nil { - panic("nil package") - } - key := packageFactKey{pkg, factType(ptr)} - if v, ok := act.packageFacts[key]; ok { - reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem()) - return true - } - return false -} - -// exportPackageFact implements Pass.ExportPackageFact. -func (act *action) exportPackageFact(fact analysis.Fact) { - if act.pass.ExportPackageFact == nil { - log.Panicf("%s: Pass.ExportPackageFact(%T) called after Run", act, fact) - } - - key := packageFactKey{act.pass.Pkg, factType(fact)} - act.packageFacts[key] = fact // clobber any existing entry - if dbg('f') { - fmt.Fprintf(os.Stderr, "%s: package %s has fact %s\n", - act.pkg.Fset.Position(act.pass.Files[0].Pos()), act.pass.Pkg.Path(), fact) - } -} - -func factType(fact analysis.Fact) reflect.Type { - t := reflect.TypeOf(fact) - if t.Kind() != reflect.Ptr { - log.Fatalf("invalid Fact type: got %T, want pointer", fact) - } - return t -} - -// allPackageFacts implements Pass.AllPackageFacts. -func (act *action) allPackageFacts() []analysis.PackageFact { - facts := make([]analysis.PackageFact, 0, len(act.packageFacts)) - for k := range act.packageFacts { - facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: act.packageFacts[k]}) - } - return facts -} - func dbg(b byte) bool { return strings.IndexByte(Debug, b) >= 0 } diff --git a/vendor/golang.org/x/tools/go/analysis/internal/internal.go b/vendor/golang.org/x/tools/go/analysis/internal/internal.go new file mode 100644 index 0000000000..e7c8247fd3 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/internal/internal.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +import "golang.org/x/tools/go/analysis" + +// This function is set by the checker package to provide +// backdoor access to the private Pass field +// of the checker.Action type, for use by analysistest. +var Pass func(interface{}) *analysis.Pass diff --git a/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index 71ebbfaef1..82c3db6a39 100644 --- a/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go +++ b/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -51,7 +51,6 @@ import ( "golang.org/x/tools/go/analysis/internal/analysisflags" "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/facts" - "golang.org/x/tools/internal/versions" ) // A Config describes a compilation unit to be analyzed. @@ -145,7 +144,7 @@ func Run(configFile string, analyzers []*analysis.Analyzer) { for _, res := range results { tree.Add(fset, cfg.ID, res.a.Name, res.diagnostics, res.err) } - tree.Print() + tree.Print(os.Stdout) } else { // plain text exit := 0 @@ -157,7 +156,7 @@ func Run(configFile string, analyzers []*analysis.Analyzer) { } for _, res := range results { for _, diag := range res.diagnostics { - analysisflags.PrintPlain(fset, diag) + analysisflags.PrintPlain(os.Stderr, fset, analysisflags.Context, diag) exit = 1 } } @@ -257,15 +256,15 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re GoVersion: cfg.GoVersion, } info := &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Implicits: make(map[ast.Node]types.Object), - Instances: make(map[*ast.Ident]types.Instance), - Scopes: make(map[ast.Node]*types.Scope), - Selections: make(map[*ast.SelectorExpr]*types.Selection), + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), + Scopes: make(map[ast.Node]*types.Scope), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + FileVersions: make(map[*ast.File]string), } - versions.InitFileVersions(info) pkg, err := tc.Check(cfg.ImportPath, fset, files, info) if err != nil { @@ -368,17 +367,26 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re } pass := &analysis.Pass{ - Analyzer: a, - Fset: fset, - Files: files, - OtherFiles: cfg.NonGoFiles, - IgnoredFiles: cfg.IgnoredFiles, - Pkg: pkg, - TypesInfo: info, - TypesSizes: tc.Sizes, - TypeErrors: nil, // unitchecker doesn't RunDespiteErrors - ResultOf: inputs, - Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) }, + Analyzer: a, + Fset: fset, + Files: files, + OtherFiles: cfg.NonGoFiles, + IgnoredFiles: cfg.IgnoredFiles, + Pkg: pkg, + TypesInfo: info, + TypesSizes: tc.Sizes, + TypeErrors: nil, // unitchecker doesn't RunDespiteErrors + ResultOf: inputs, + Report: func(d analysis.Diagnostic) { + // Unitchecker doesn't apply fixes, but it does report them in the JSON output. + if err := analysisinternal.ValidateFixes(fset, a, d.SuggestedFixes); err != nil { + // Since we have diagnostics, the exit code will be nonzero, + // so logging these errors is sufficient. + log.Println(err) + d.SuggestedFixes = nil + } + act.diagnostics = append(act.diagnostics, d) + }, ImportObjectFact: facts.ImportObjectFact, ExportObjectFact: facts.ExportObjectFact, AllObjectFacts: func() []analysis.ObjectFact { return facts.AllObjectFacts(factFilter) }, @@ -387,7 +395,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re AllPackageFacts: func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) }, Module: module, } - pass.ReadFile = analysisinternal.MakeReadFile(pass) + pass.ReadFile = analysisinternal.CheckedReadFile(pass, os.ReadFile) t0 := time.Now() act.result, act.err = a.Run(pass) diff --git a/vendor/golang.org/x/tools/go/ast/astutil/imports.go b/vendor/golang.org/x/tools/go/ast/astutil/imports.go index 18d1adb05d..a6b5ed0a89 100644 --- a/vendor/golang.org/x/tools/go/ast/astutil/imports.go +++ b/vendor/golang.org/x/tools/go/ast/astutil/imports.go @@ -344,7 +344,12 @@ func RewriteImport(fset *token.FileSet, f *ast.File, oldPath, newPath string) (r } // UsesImport reports whether a given import is used. +// The provided File must have been parsed with syntactic object resolution +// (not using go/parser.SkipObjectResolution). func UsesImport(f *ast.File, path string) (used bool) { + if f.Scope == nil { + panic("file f was not parsed with syntactic object resolution") + } spec := importSpec(f, path) if spec == nil { return diff --git a/vendor/golang.org/x/tools/go/ast/astutil/util.go b/vendor/golang.org/x/tools/go/ast/astutil/util.go index 6bdcf70ac2..ca71e3e105 100644 --- a/vendor/golang.org/x/tools/go/ast/astutil/util.go +++ b/vendor/golang.org/x/tools/go/ast/astutil/util.go @@ -7,13 +7,5 @@ package astutil import "go/ast" // Unparen returns e with any enclosing parentheses stripped. -// TODO(adonovan): use go1.22's ast.Unparen. -func Unparen(e ast.Expr) ast.Expr { - for { - p, ok := e.(*ast.ParenExpr) - if !ok { - return e - } - e = p.X - } -} +// Deprecated: use [ast.Unparen]. +func Unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) } diff --git a/vendor/golang.org/x/tools/go/ast/inspector/inspector.go b/vendor/golang.org/x/tools/go/ast/inspector/inspector.go index 1fc1de0bd1..0d5050fe40 100644 --- a/vendor/golang.org/x/tools/go/ast/inspector/inspector.go +++ b/vendor/golang.org/x/tools/go/ast/inspector/inspector.go @@ -36,6 +36,9 @@ package inspector import ( "go/ast" + _ "unsafe" + + "golang.org/x/tools/internal/astutil/edge" ) // An Inspector provides methods for inspecting @@ -44,6 +47,24 @@ type Inspector struct { events []event } +//go:linkname events +func events(in *Inspector) []event { return in.events } + +func packEdgeKindAndIndex(ek edge.Kind, index int) int32 { + return int32(uint32(index+1)<<7 | uint32(ek)) +} + +// unpackEdgeKindAndIndex unpacks the edge kind and edge index (within +// an []ast.Node slice) from the parent field of a pop event. +// +//go:linkname unpackEdgeKindAndIndex +func unpackEdgeKindAndIndex(x int32) (edge.Kind, int) { + // The "parent" field of a pop node holds the + // edge Kind in the lower 7 bits and the index+1 + // in the upper 25. + return edge.Kind(x & 0x7f), int(x>>7) - 1 +} + // New returns an Inspector for the specified syntax trees. func New(files []*ast.File) *Inspector { return &Inspector{traverse(files)} @@ -52,9 +73,10 @@ func New(files []*ast.File) *Inspector { // An event represents a push or a pop // of an ast.Node during a traversal. type event struct { - node ast.Node - typ uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events - index int // index of corresponding push or pop event + node ast.Node + typ uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events + index int32 // index of corresponding push or pop event + parent int32 // index of parent's push node (push nodes only), or packed edge kind/index (pop nodes only) } // TODO: Experiment with storing only the second word of event.node (unsafe.Pointer). @@ -73,8 +95,17 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // check, Preorder is almost twice as fast as Nodes. The two // features seem to contribute similar slowdowns (~1.4x each). + // This function is equivalent to the PreorderSeq call below, + // but to avoid the additional dynamic call (which adds 13-35% + // to the benchmarks), we expand it out. + // + // in.PreorderSeq(types...)(func(n ast.Node) bool { + // f(n) + // return true + // }) + mask := maskOf(types) - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -104,7 +135,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // matches an element of the types slice. func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proceed bool)) { mask := maskOf(types) - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -138,7 +169,7 @@ func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proc func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (proceed bool)) { mask := maskOf(types) var stack []ast.Node - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -171,50 +202,83 @@ func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, s // traverse builds the table of events representing a traversal. func traverse(files []*ast.File) []event { // Preallocate approximate number of events - // based on source file extent. + // based on source file extent of the declarations. + // (We use End-Pos not FileStart-FileEnd to neglect + // the effect of long doc comments.) // This makes traverse faster by 4x (!). var extent int for _, f := range files { extent += int(f.End() - f.Pos()) } // This estimate is based on the net/http package. - capacity := extent * 33 / 100 - if capacity > 1e6 { - capacity = 1e6 // impose some reasonable maximum + capacity := min(extent*33/100, 1e6) // impose some reasonable maximum (1M) + + v := &visitor{ + events: make([]event, 0, capacity), + stack: []item{{index: -1}}, // include an extra event so file nodes have a parent } - events := make([]event, 0, capacity) + for _, file := range files { + walk(v, edge.Invalid, -1, file) + } + return v.events +} - var stack []event - stack = append(stack, event{}) // include an extra event so file nodes have a parent - for _, f := range files { - ast.Inspect(f, func(n ast.Node) bool { - if n != nil { - // push - ev := event{ - node: n, - typ: 0, // temporarily used to accumulate type bits of subtree - index: len(events), // push event temporarily holds own index - } - stack = append(stack, ev) - events = append(events, ev) - } else { - // pop - top := len(stack) - 1 - ev := stack[top] - typ := typeOf(ev.node) - push := ev.index - parent := top - 1 - - events[push].typ = typ // set type of push - stack[parent].typ |= typ | ev.typ // parent's typ contains push and pop's typs. - events[push].index = len(events) // make push refer to pop - - stack = stack[:top] - events = append(events, ev) - } - return true - }) +type visitor struct { + events []event + stack []item +} + +type item struct { + index int32 // index of current node's push event + parentIndex int32 // index of parent node's push event + typAccum uint64 // accumulated type bits of current node's descendents + edgeKindAndIndex int32 // edge.Kind and index, bit packed +} + +func (v *visitor) push(ek edge.Kind, eindex int, node ast.Node) { + var ( + index = int32(len(v.events)) + parentIndex = v.stack[len(v.stack)-1].index + ) + v.events = append(v.events, event{ + node: node, + parent: parentIndex, + typ: typeOf(node), + index: 0, // (pop index is set later by visitor.pop) + }) + v.stack = append(v.stack, item{ + index: index, + parentIndex: parentIndex, + edgeKindAndIndex: packEdgeKindAndIndex(ek, eindex), + }) + + // 2B nodes ought to be enough for anyone! + if int32(len(v.events)) < 0 { + panic("event index exceeded int32") } - return events + // 32M elements in an []ast.Node ought to be enough for anyone! + if ek2, eindex2 := unpackEdgeKindAndIndex(packEdgeKindAndIndex(ek, eindex)); ek2 != ek || eindex2 != eindex { + panic("Node slice index exceeded uint25") + } +} + +func (v *visitor) pop(node ast.Node) { + top := len(v.stack) - 1 + current := v.stack[top] + + push := &v.events[current.index] + parent := &v.stack[top-1] + + push.index = int32(len(v.events)) // make push event refer to pop + parent.typAccum |= current.typAccum | push.typ // accumulate type bits into parent + + v.stack = v.stack[:top] + + v.events = append(v.events, event{ + node: node, + typ: current.typAccum, + index: current.index, + parent: current.edgeKindAndIndex, // see [unpackEdgeKindAndIndex] + }) } diff --git a/vendor/golang.org/x/tools/go/ast/inspector/iter.go b/vendor/golang.org/x/tools/go/ast/inspector/iter.go new file mode 100644 index 0000000000..c576dc70ac --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/inspector/iter.go @@ -0,0 +1,85 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.23 + +package inspector + +import ( + "go/ast" + "iter" +) + +// PreorderSeq returns an iterator that visits all the +// nodes of the files supplied to New in depth-first order. +// It visits each node n before n's children. +// The complete traversal sequence is determined by ast.Inspect. +// +// The types argument, if non-empty, enables type-based +// filtering of events: only nodes whose type matches an +// element of the types slice are included in the sequence. +func (in *Inspector) PreorderSeq(types ...ast.Node) iter.Seq[ast.Node] { + + // This implementation is identical to Preorder, + // except that it supports breaking out of the loop. + + return func(yield func(ast.Node) bool) { + mask := maskOf(types) + for i := int32(0); i < int32(len(in.events)); { + ev := in.events[i] + if ev.index > i { + // push + if ev.typ&mask != 0 { + if !yield(ev.node) { + break + } + } + pop := ev.index + if in.events[pop].typ&mask == 0 { + // Subtrees do not contain types: skip them and pop. + i = pop + 1 + continue + } + } + i++ + } + } +} + +// All[N] returns an iterator over all the nodes of type N. +// N must be a pointer-to-struct type that implements ast.Node. +// +// Example: +// +// for call := range All[*ast.CallExpr](in) { ... } +func All[N interface { + *S + ast.Node +}, S any](in *Inspector) iter.Seq[N] { + + // To avoid additional dynamic call overheads, + // we duplicate rather than call the logic of PreorderSeq. + + mask := typeOf((N)(nil)) + return func(yield func(N) bool) { + for i := int32(0); i < int32(len(in.events)); { + ev := in.events[i] + if ev.index > i { + // push + if ev.typ&mask != 0 { + if !yield(ev.node.(N)) { + break + } + } + pop := ev.index + if in.events[pop].typ&mask == 0 { + // Subtrees do not contain types: skip them and pop. + i = pop + 1 + continue + } + } + i++ + } + } +} diff --git a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go index 2a872f89d4..9778448457 100644 --- a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go +++ b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go @@ -12,6 +12,8 @@ package inspector import ( "go/ast" "math" + + _ "unsafe" ) const ( @@ -215,8 +217,9 @@ func typeOf(n ast.Node) uint64 { return 0 } +//go:linkname maskOf func maskOf(nodes []ast.Node) uint64 { - if nodes == nil { + if len(nodes) == 0 { return math.MaxUint64 // match all node types } var mask uint64 diff --git a/vendor/golang.org/x/tools/go/ast/inspector/walk.go b/vendor/golang.org/x/tools/go/ast/inspector/walk.go new file mode 100644 index 0000000000..5a42174a0a --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/inspector/walk.go @@ -0,0 +1,341 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package inspector + +// This file is a fork of ast.Inspect to reduce unnecessary dynamic +// calls and to gather edge information. +// +// Consistency with the original is ensured by TestInspectAllNodes. + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/internal/astutil/edge" +) + +func walkList[N ast.Node](v *visitor, ek edge.Kind, list []N) { + for i, node := range list { + walk(v, ek, i, node) + } +} + +func walk(v *visitor, ek edge.Kind, index int, node ast.Node) { + v.push(ek, index, node) + + // walk children + // (the order of the cases matches the order + // of the corresponding node types in ast.go) + switch n := node.(type) { + // Comments and fields + case *ast.Comment: + // nothing to do + + case *ast.CommentGroup: + walkList(v, edge.CommentGroup_List, n.List) + + case *ast.Field: + if n.Doc != nil { + walk(v, edge.Field_Doc, -1, n.Doc) + } + walkList(v, edge.Field_Names, n.Names) + if n.Type != nil { + walk(v, edge.Field_Type, -1, n.Type) + } + if n.Tag != nil { + walk(v, edge.Field_Tag, -1, n.Tag) + } + if n.Comment != nil { + walk(v, edge.Field_Comment, -1, n.Comment) + } + + case *ast.FieldList: + walkList(v, edge.FieldList_List, n.List) + + // Expressions + case *ast.BadExpr, *ast.Ident, *ast.BasicLit: + // nothing to do + + case *ast.Ellipsis: + if n.Elt != nil { + walk(v, edge.Ellipsis_Elt, -1, n.Elt) + } + + case *ast.FuncLit: + walk(v, edge.FuncLit_Type, -1, n.Type) + walk(v, edge.FuncLit_Body, -1, n.Body) + + case *ast.CompositeLit: + if n.Type != nil { + walk(v, edge.CompositeLit_Type, -1, n.Type) + } + walkList(v, edge.CompositeLit_Elts, n.Elts) + + case *ast.ParenExpr: + walk(v, edge.ParenExpr_X, -1, n.X) + + case *ast.SelectorExpr: + walk(v, edge.SelectorExpr_X, -1, n.X) + walk(v, edge.SelectorExpr_Sel, -1, n.Sel) + + case *ast.IndexExpr: + walk(v, edge.IndexExpr_X, -1, n.X) + walk(v, edge.IndexExpr_Index, -1, n.Index) + + case *ast.IndexListExpr: + walk(v, edge.IndexListExpr_X, -1, n.X) + walkList(v, edge.IndexListExpr_Indices, n.Indices) + + case *ast.SliceExpr: + walk(v, edge.SliceExpr_X, -1, n.X) + if n.Low != nil { + walk(v, edge.SliceExpr_Low, -1, n.Low) + } + if n.High != nil { + walk(v, edge.SliceExpr_High, -1, n.High) + } + if n.Max != nil { + walk(v, edge.SliceExpr_Max, -1, n.Max) + } + + case *ast.TypeAssertExpr: + walk(v, edge.TypeAssertExpr_X, -1, n.X) + if n.Type != nil { + walk(v, edge.TypeAssertExpr_Type, -1, n.Type) + } + + case *ast.CallExpr: + walk(v, edge.CallExpr_Fun, -1, n.Fun) + walkList(v, edge.CallExpr_Args, n.Args) + + case *ast.StarExpr: + walk(v, edge.StarExpr_X, -1, n.X) + + case *ast.UnaryExpr: + walk(v, edge.UnaryExpr_X, -1, n.X) + + case *ast.BinaryExpr: + walk(v, edge.BinaryExpr_X, -1, n.X) + walk(v, edge.BinaryExpr_Y, -1, n.Y) + + case *ast.KeyValueExpr: + walk(v, edge.KeyValueExpr_Key, -1, n.Key) + walk(v, edge.KeyValueExpr_Value, -1, n.Value) + + // Types + case *ast.ArrayType: + if n.Len != nil { + walk(v, edge.ArrayType_Len, -1, n.Len) + } + walk(v, edge.ArrayType_Elt, -1, n.Elt) + + case *ast.StructType: + walk(v, edge.StructType_Fields, -1, n.Fields) + + case *ast.FuncType: + if n.TypeParams != nil { + walk(v, edge.FuncType_TypeParams, -1, n.TypeParams) + } + if n.Params != nil { + walk(v, edge.FuncType_Params, -1, n.Params) + } + if n.Results != nil { + walk(v, edge.FuncType_Results, -1, n.Results) + } + + case *ast.InterfaceType: + walk(v, edge.InterfaceType_Methods, -1, n.Methods) + + case *ast.MapType: + walk(v, edge.MapType_Key, -1, n.Key) + walk(v, edge.MapType_Value, -1, n.Value) + + case *ast.ChanType: + walk(v, edge.ChanType_Value, -1, n.Value) + + // Statements + case *ast.BadStmt: + // nothing to do + + case *ast.DeclStmt: + walk(v, edge.DeclStmt_Decl, -1, n.Decl) + + case *ast.EmptyStmt: + // nothing to do + + case *ast.LabeledStmt: + walk(v, edge.LabeledStmt_Label, -1, n.Label) + walk(v, edge.LabeledStmt_Stmt, -1, n.Stmt) + + case *ast.ExprStmt: + walk(v, edge.ExprStmt_X, -1, n.X) + + case *ast.SendStmt: + walk(v, edge.SendStmt_Chan, -1, n.Chan) + walk(v, edge.SendStmt_Value, -1, n.Value) + + case *ast.IncDecStmt: + walk(v, edge.IncDecStmt_X, -1, n.X) + + case *ast.AssignStmt: + walkList(v, edge.AssignStmt_Lhs, n.Lhs) + walkList(v, edge.AssignStmt_Rhs, n.Rhs) + + case *ast.GoStmt: + walk(v, edge.GoStmt_Call, -1, n.Call) + + case *ast.DeferStmt: + walk(v, edge.DeferStmt_Call, -1, n.Call) + + case *ast.ReturnStmt: + walkList(v, edge.ReturnStmt_Results, n.Results) + + case *ast.BranchStmt: + if n.Label != nil { + walk(v, edge.BranchStmt_Label, -1, n.Label) + } + + case *ast.BlockStmt: + walkList(v, edge.BlockStmt_List, n.List) + + case *ast.IfStmt: + if n.Init != nil { + walk(v, edge.IfStmt_Init, -1, n.Init) + } + walk(v, edge.IfStmt_Cond, -1, n.Cond) + walk(v, edge.IfStmt_Body, -1, n.Body) + if n.Else != nil { + walk(v, edge.IfStmt_Else, -1, n.Else) + } + + case *ast.CaseClause: + walkList(v, edge.CaseClause_List, n.List) + walkList(v, edge.CaseClause_Body, n.Body) + + case *ast.SwitchStmt: + if n.Init != nil { + walk(v, edge.SwitchStmt_Init, -1, n.Init) + } + if n.Tag != nil { + walk(v, edge.SwitchStmt_Tag, -1, n.Tag) + } + walk(v, edge.SwitchStmt_Body, -1, n.Body) + + case *ast.TypeSwitchStmt: + if n.Init != nil { + walk(v, edge.TypeSwitchStmt_Init, -1, n.Init) + } + walk(v, edge.TypeSwitchStmt_Assign, -1, n.Assign) + walk(v, edge.TypeSwitchStmt_Body, -1, n.Body) + + case *ast.CommClause: + if n.Comm != nil { + walk(v, edge.CommClause_Comm, -1, n.Comm) + } + walkList(v, edge.CommClause_Body, n.Body) + + case *ast.SelectStmt: + walk(v, edge.SelectStmt_Body, -1, n.Body) + + case *ast.ForStmt: + if n.Init != nil { + walk(v, edge.ForStmt_Init, -1, n.Init) + } + if n.Cond != nil { + walk(v, edge.ForStmt_Cond, -1, n.Cond) + } + if n.Post != nil { + walk(v, edge.ForStmt_Post, -1, n.Post) + } + walk(v, edge.ForStmt_Body, -1, n.Body) + + case *ast.RangeStmt: + if n.Key != nil { + walk(v, edge.RangeStmt_Key, -1, n.Key) + } + if n.Value != nil { + walk(v, edge.RangeStmt_Value, -1, n.Value) + } + walk(v, edge.RangeStmt_X, -1, n.X) + walk(v, edge.RangeStmt_Body, -1, n.Body) + + // Declarations + case *ast.ImportSpec: + if n.Doc != nil { + walk(v, edge.ImportSpec_Doc, -1, n.Doc) + } + if n.Name != nil { + walk(v, edge.ImportSpec_Name, -1, n.Name) + } + walk(v, edge.ImportSpec_Path, -1, n.Path) + if n.Comment != nil { + walk(v, edge.ImportSpec_Comment, -1, n.Comment) + } + + case *ast.ValueSpec: + if n.Doc != nil { + walk(v, edge.ValueSpec_Doc, -1, n.Doc) + } + walkList(v, edge.ValueSpec_Names, n.Names) + if n.Type != nil { + walk(v, edge.ValueSpec_Type, -1, n.Type) + } + walkList(v, edge.ValueSpec_Values, n.Values) + if n.Comment != nil { + walk(v, edge.ValueSpec_Comment, -1, n.Comment) + } + + case *ast.TypeSpec: + if n.Doc != nil { + walk(v, edge.TypeSpec_Doc, -1, n.Doc) + } + walk(v, edge.TypeSpec_Name, -1, n.Name) + if n.TypeParams != nil { + walk(v, edge.TypeSpec_TypeParams, -1, n.TypeParams) + } + walk(v, edge.TypeSpec_Type, -1, n.Type) + if n.Comment != nil { + walk(v, edge.TypeSpec_Comment, -1, n.Comment) + } + + case *ast.BadDecl: + // nothing to do + + case *ast.GenDecl: + if n.Doc != nil { + walk(v, edge.GenDecl_Doc, -1, n.Doc) + } + walkList(v, edge.GenDecl_Specs, n.Specs) + + case *ast.FuncDecl: + if n.Doc != nil { + walk(v, edge.FuncDecl_Doc, -1, n.Doc) + } + if n.Recv != nil { + walk(v, edge.FuncDecl_Recv, -1, n.Recv) + } + walk(v, edge.FuncDecl_Name, -1, n.Name) + walk(v, edge.FuncDecl_Type, -1, n.Type) + if n.Body != nil { + walk(v, edge.FuncDecl_Body, -1, n.Body) + } + + case *ast.File: + if n.Doc != nil { + walk(v, edge.File_Doc, -1, n.Doc) + } + walk(v, edge.File_Name, -1, n.Name) + walkList(v, edge.File_Decls, n.Decls) + // don't walk n.Comments - they have been + // visited already through the individual + // nodes + + default: + // (includes *ast.Package) + panic(fmt.Sprintf("Walk: unexpected node type %T", n)) + } + + v.pop(node) +} diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go index 137cc8df1d..65fe2628e9 100644 --- a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go +++ b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go @@ -2,22 +2,64 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package gcexportdata provides functions for locating, reading, and -// writing export data files containing type information produced by the -// gc compiler. This package supports go1.7 export data format and all -// later versions. -// -// Although it might seem convenient for this package to live alongside -// go/types in the standard library, this would cause version skew -// problems for developer tools that use it, since they must be able to -// consume the outputs of the gc compiler both before and after a Go -// update such as from Go 1.7 to Go 1.8. Because this package lives in -// golang.org/x/tools, sites can update their version of this repo some -// time before the Go 1.8 release and rebuild and redeploy their -// developer tools, which will then be able to consume both Go 1.7 and -// Go 1.8 export data files, so they will work before and after the -// Go update. (See discussion at https://golang.org/issue/15651.) -package gcexportdata // import "golang.org/x/tools/go/gcexportdata" +// Package gcexportdata provides functions for reading and writing +// export data, which is a serialized description of the API of a Go +// package including the names, kinds, types, and locations of all +// exported declarations. +// +// The standard Go compiler (cmd/compile) writes an export data file +// for each package it compiles, which it later reads when compiling +// packages that import the earlier one. The compiler must thus +// contain logic to both write and read export data. +// (See the "Export" section in the cmd/compile/README file.) +// +// The [Read] function in this package can read files produced by the +// compiler, producing [go/types] data structures. As a matter of +// policy, Read supports export data files produced by only the last +// two Go releases plus tip; see https://go.dev/issue/68898. The +// export data files produced by the compiler contain additional +// details related to generics, inlining, and other optimizations that +// cannot be decoded by the [Read] function. +// +// In files written by the compiler, the export data is not at the +// start of the file. Before calling Read, use [NewReader] to locate +// the desired portion of the file. +// +// The [Write] function in this package encodes the exported API of a +// Go package ([types.Package]) as a file. Such files can be later +// decoded by Read, but cannot be consumed by the compiler. +// +// # Future changes +// +// Although Read supports the formats written by both Write and the +// compiler, the two are quite different, and there is an open +// proposal (https://go.dev/issue/69491) to separate these APIs. +// +// Under that proposal, this package would ultimately provide only the +// Read operation for compiler export data, which must be defined in +// this module (golang.org/x/tools), not in the standard library, to +// avoid version skew for developer tools that need to read compiler +// export data both before and after a Go release, such as from Go +// 1.23 to Go 1.24. Because this package lives in the tools module, +// clients can update their version of the module some time before the +// Go 1.24 release and rebuild and redeploy their tools, which will +// then be able to consume both Go 1.23 and Go 1.24 export data files, +// so they will work before and after the Go update. (See discussion +// at https://go.dev/issue/15651.) +// +// The operations to import and export [go/types] data structures +// would be defined in the go/types package as Import and Export. +// [Write] would (eventually) delegate to Export, +// and [Read], when it detects a file produced by Export, +// would delegate to Import. +// +// # Deprecations +// +// The [NewImporter] and [Find] functions are deprecated and should +// not be used in new code. The [WriteBundle] and [ReadBundle] +// functions are experimental, and there is an open proposal to +// deprecate them (https://go.dev/issue/69573). +package gcexportdata import ( "bufio" @@ -64,24 +106,18 @@ func Find(importPath, srcDir string) (filename, path string) { // additional trailing data beyond the end of the export data. func NewReader(r io.Reader) (io.Reader, error) { buf := bufio.NewReader(r) - _, size, err := gcimporter.FindExportData(buf) + size, err := gcimporter.FindExportData(buf) if err != nil { return nil, err } - if size >= 0 { - // We were given an archive and found the __.PKGDEF in it. - // This tells us the size of the export data, and we don't - // need to return the entire file. - return &io.LimitedReader{ - R: buf, - N: size, - }, nil - } else { - // We were given an object file. As such, we don't know how large - // the export data is and must return the entire file. - return buf, nil - } + // We were given an archive and found the __.PKGDEF in it. + // This tells us the size of the export data, and we don't + // need to return the entire file. + return &io.LimitedReader{ + R: buf, + N: size, + }, nil } // readAll works the same way as io.ReadAll, but avoids allocations and copies @@ -100,6 +136,11 @@ func readAll(r io.Reader) ([]byte, error) { // Read reads export data from in, decodes it, and returns type // information for the package. // +// Read is capable of reading export data produced by [Write] at the +// same source code version, or by the last two Go releases (plus tip) +// of the standard Go compiler. Reading files from older compilers may +// produce an error. +// // The package path (effectively its linker symbol prefix) is // specified by path, since unlike the package name, this information // may not be recorded in the export data. @@ -128,14 +169,26 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, // (from "version"). Select appropriate importer. if len(data) > 0 { switch data[0] { - case 'v', 'c', 'd': // binary, till go1.10 + case 'v', 'c', 'd': + // binary, produced by cmd/compile till go1.10 return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0]) - case 'i': // indexed, till go1.19 + case 'i': + // indexed, produced by cmd/compile till go1.19, + // and also by [Write]. + // + // If proposal #69491 is accepted, go/types + // serialization will be implemented by + // types.Export, to which Write would eventually + // delegate (explicitly dropping any pretence at + // inter-version Write-Read compatibility). + // This [Read] function would delegate to types.Import + // when it detects that the file was produced by Export. _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) return pkg, err - case 'u': // unified, from go1.20 + case 'u': + // unified, produced by cmd/compile since go1.20 _, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path) return pkg, err diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/vendor/golang.org/x/tools/go/packages/doc.go index 3531ac8f5f..f1931d10ee 100644 --- a/vendor/golang.org/x/tools/go/packages/doc.go +++ b/vendor/golang.org/x/tools/go/packages/doc.go @@ -64,7 +64,7 @@ graph using the Imports fields. The Load function can be configured by passing a pointer to a Config as the first argument. A nil Config is equivalent to the zero Config, which -causes Load to run in LoadFiles mode, collecting minimal information. +causes Load to run in [LoadFiles] mode, collecting minimal information. See the documentation for type Config for details. As noted earlier, the Config.Mode controls the amount of detail @@ -72,14 +72,14 @@ reported about the loaded packages. See the documentation for type LoadMode for details. Most tools should pass their command-line arguments (after any flags) -uninterpreted to [Load], so that it can interpret them +uninterpreted to Load, so that it can interpret them according to the conventions of the underlying build system. See the Example function for typical usage. # The driver protocol -[Load] may be used to load Go packages even in Go projects that use +Load may be used to load Go packages even in Go projects that use alternative build systems, by installing an appropriate "driver" program for the build system and specifying its location in the GOPACKAGESDRIVER environment variable. @@ -97,6 +97,15 @@ JSON-encoded [DriverRequest] message providing additional information is written to the driver's standard input. The driver must write a JSON-encoded [DriverResponse] message to its standard output. (This message differs from the JSON schema produced by 'go list'.) + +The value of the PWD environment variable seen by the driver process +is the preferred name of its working directory. (The working directory +may have other aliases due to symbolic links; see the comment on the +Dir field of [exec.Cmd] for related information.) +When the driver process emits in its response the name of a file +that is a descendant of this directory, it must use an absolute path +that has the value of PWD as a prefix, to ensure that the returned +filenames satisfy the original query. */ package packages // import "golang.org/x/tools/go/packages" diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go index c2b4b711b5..91bd62e83b 100644 --- a/vendor/golang.org/x/tools/go/packages/external.go +++ b/vendor/golang.org/x/tools/go/packages/external.go @@ -13,6 +13,7 @@ import ( "fmt" "os" "os/exec" + "slices" "strings" ) @@ -79,10 +80,10 @@ type DriverResponse struct { // driver is the type for functions that query the build system for the // packages named by the patterns. -type driver func(cfg *Config, patterns ...string) (*DriverResponse, error) +type driver func(cfg *Config, patterns []string) (*DriverResponse, error) // findExternalDriver returns the file path of a tool that supplies -// the build system package structure, or "" if not found." +// the build system package structure, or "" if not found. // If GOPACKAGESDRIVER is set in the environment findExternalTool returns its // value, otherwise it searches for a binary named gopackagesdriver on the PATH. func findExternalDriver(cfg *Config) driver { @@ -103,7 +104,7 @@ func findExternalDriver(cfg *Config) driver { return nil } } - return func(cfg *Config, words ...string) (*DriverResponse, error) { + return func(cfg *Config, patterns []string) (*DriverResponse, error) { req, err := json.Marshal(DriverRequest{ Mode: cfg.Mode, Env: cfg.Env, @@ -117,7 +118,7 @@ func findExternalDriver(cfg *Config) driver { buf := new(bytes.Buffer) stderr := new(bytes.Buffer) - cmd := exec.CommandContext(cfg.Context, tool, words...) + cmd := exec.CommandContext(cfg.Context, tool, patterns...) cmd.Dir = cfg.Dir // The cwd gets resolved to the real path. On Darwin, where // /tmp is a symlink, this breaks anything that expects the @@ -131,7 +132,7 @@ func findExternalDriver(cfg *Config) driver { // command. // // (See similar trick in Invocation.run in ../../internal/gocommand/invoke.go) - cmd.Env = append(slicesClip(cfg.Env), "PWD="+cfg.Dir) + cmd.Env = append(slices.Clip(cfg.Env), "PWD="+cfg.Dir) cmd.Stdin = bytes.NewReader(req) cmd.Stdout = buf cmd.Stderr = stderr @@ -150,7 +151,3 @@ func findExternalDriver(cfg *Config) driver { return &response, nil } } - -// slicesClip removes unused capacity from the slice, returning s[:len(s):len(s)]. -// TODO(adonovan): use go1.21 slices.Clip. -func slicesClip[S ~[]E, E any](s S) S { return s[:len(s):len(s)] } diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go index 1a3a5b44f5..0458b4f9c4 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -80,6 +80,12 @@ type golistState struct { cfg *Config ctx context.Context + runner *gocommand.Runner + + // overlay is the JSON file that encodes the Config.Overlay + // mapping, used by 'go list -overlay=...'. + overlay string + envOnce sync.Once goEnvError error goEnv map[string]string @@ -127,7 +133,10 @@ func (state *golistState) mustGetEnv() map[string]string { // goListDriver uses the go list command to interpret the patterns and produce // the build system package structure. // See driver for more details. -func goListDriver(cfg *Config, patterns ...string) (_ *DriverResponse, err error) { +// +// overlay is the JSON file that encodes the cfg.Overlay +// mapping, used by 'go list -overlay=...' +func goListDriver(cfg *Config, runner *gocommand.Runner, overlay string, patterns []string) (_ *DriverResponse, err error) { // Make sure that any asynchronous go commands are killed when we return. parentCtx := cfg.Context if parentCtx == nil { @@ -142,13 +151,15 @@ func goListDriver(cfg *Config, patterns ...string) (_ *DriverResponse, err error cfg: cfg, ctx: ctx, vendorDirs: map[string]bool{}, + overlay: overlay, + runner: runner, } // Fill in response.Sizes asynchronously if necessary. - if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 { + if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 { errCh := make(chan error) go func() { - compiler, arch, err := getSizesForArgs(ctx, state.cfgInvocation(), cfg.gocmdRunner) + compiler, arch, err := getSizesForArgs(ctx, state.cfgInvocation(), runner) response.dr.Compiler = compiler response.dr.Arch = arch errCh <- err @@ -311,6 +322,7 @@ type jsonPackage struct { ImportPath string Dir string Name string + Target string Export string GoFiles []string CompiledGoFiles []string @@ -494,13 +506,15 @@ func (state *golistState) createDriverResponse(words ...string) (*DriverResponse pkg := &Package{ Name: p.Name, ID: p.ImportPath, + Dir: p.Dir, + Target: p.Target, GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles), CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles), OtherFiles: absJoin(p.Dir, otherFiles(p)...), EmbedFiles: absJoin(p.Dir, p.EmbedFiles), EmbedPatterns: absJoin(p.Dir, p.EmbedPatterns), IgnoredFiles: absJoin(p.Dir, p.IgnoredGoFiles, p.IgnoredOtherFiles), - forTest: p.ForTest, + ForTest: p.ForTest, depsErrors: p.DepsErrors, Module: p.Module, } @@ -681,7 +695,7 @@ func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool { // getGoVersion returns the effective minor version of the go command. func (state *golistState) getGoVersion() (int, error) { state.goVersionOnce.Do(func() { - state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner) + state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.runner) }) return state.goVersion, state.goVersionError } @@ -751,7 +765,7 @@ func jsonFlag(cfg *Config, goVersion int) string { } } addFields("Name", "ImportPath", "Error") // These fields are always needed - if cfg.Mode&NeedFiles != 0 || cfg.Mode&NeedTypes != 0 { + if cfg.Mode&NeedFiles != 0 || cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 { addFields("Dir", "GoFiles", "IgnoredGoFiles", "IgnoredOtherFiles", "CFiles", "CgoFiles", "CXXFiles", "MFiles", "HFiles", "FFiles", "SFiles", "SwigFiles", "SwigCXXFiles", "SysoFiles") @@ -759,7 +773,7 @@ func jsonFlag(cfg *Config, goVersion int) string { addFields("TestGoFiles", "XTestGoFiles") } } - if cfg.Mode&NeedTypes != 0 { + if cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 { // CompiledGoFiles seems to be required for the test case TestCgoNoSyntax, // even when -compiled isn't passed in. // TODO(#52435): Should we make the test ask for -compiled, or automatically @@ -784,7 +798,7 @@ func jsonFlag(cfg *Config, goVersion int) string { // Request Dir in the unlikely case Export is not absolute. addFields("Dir", "Export") } - if cfg.Mode&needInternalForTest != 0 { + if cfg.Mode&NeedForTest != 0 { addFields("ForTest") } if cfg.Mode&needInternalDepsErrors != 0 { @@ -799,6 +813,9 @@ func jsonFlag(cfg *Config, goVersion int) string { if cfg.Mode&NeedEmbedPatterns != 0 { addFields("EmbedPatterns") } + if cfg.Mode&NeedTarget != 0 { + addFields("Target") + } return "-json=" + strings.Join(fields, ",") } @@ -840,7 +857,7 @@ func (state *golistState) cfgInvocation() gocommand.Invocation { Env: cfg.Env, Logf: cfg.Logf, WorkingDir: cfg.Dir, - Overlay: cfg.goListOverlayFile, + Overlay: state.overlay, } } @@ -851,11 +868,8 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, inv := state.cfgInvocation() inv.Verb = verb inv.Args = args - gocmdRunner := cfg.gocmdRunner - if gocmdRunner == nil { - gocmdRunner = &gocommand.Runner{} - } - stdout, stderr, friendlyErr, err := gocmdRunner.RunRaw(cfg.Context, inv) + + stdout, stderr, friendlyErr, err := state.runner.RunRaw(cfg.Context, inv) if err != nil { // Check for 'go' executable not being found. if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound { @@ -879,6 +893,12 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, return nil, friendlyErr } + // Return an error if 'go list' failed due to missing tools in + // $GOROOT/pkg/tool/$GOOS_$GOARCH (#69606). + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), `go: no such tool`) { + return nil, friendlyErr + } + // Is there an error running the C compiler in cgo? This will be reported in the "Error" field // and should be suppressed by go list -e. // diff --git a/vendor/golang.org/x/tools/go/packages/loadmode_string.go b/vendor/golang.org/x/tools/go/packages/loadmode_string.go index 5c080d21b5..69eec9f44d 100644 --- a/vendor/golang.org/x/tools/go/packages/loadmode_string.go +++ b/vendor/golang.org/x/tools/go/packages/loadmode_string.go @@ -9,49 +9,48 @@ import ( "strings" ) -var allModes = []LoadMode{ - NeedName, - NeedFiles, - NeedCompiledGoFiles, - NeedImports, - NeedDeps, - NeedExportFile, - NeedTypes, - NeedSyntax, - NeedTypesInfo, - NeedTypesSizes, +var modes = [...]struct { + mode LoadMode + name string +}{ + {NeedName, "NeedName"}, + {NeedFiles, "NeedFiles"}, + {NeedCompiledGoFiles, "NeedCompiledGoFiles"}, + {NeedImports, "NeedImports"}, + {NeedDeps, "NeedDeps"}, + {NeedExportFile, "NeedExportFile"}, + {NeedTypes, "NeedTypes"}, + {NeedSyntax, "NeedSyntax"}, + {NeedTypesInfo, "NeedTypesInfo"}, + {NeedTypesSizes, "NeedTypesSizes"}, + {NeedForTest, "NeedForTest"}, + {NeedModule, "NeedModule"}, + {NeedEmbedFiles, "NeedEmbedFiles"}, + {NeedEmbedPatterns, "NeedEmbedPatterns"}, + {NeedTarget, "NeedTarget"}, } -var modeStrings = []string{ - "NeedName", - "NeedFiles", - "NeedCompiledGoFiles", - "NeedImports", - "NeedDeps", - "NeedExportFile", - "NeedTypes", - "NeedSyntax", - "NeedTypesInfo", - "NeedTypesSizes", -} - -func (mod LoadMode) String() string { - m := mod - if m == 0 { +func (mode LoadMode) String() string { + if mode == 0 { return "LoadMode(0)" } var out []string - for i, x := range allModes { - if x > m { - break + // named bits + for _, item := range modes { + if (mode & item.mode) != 0 { + mode ^= item.mode + out = append(out, item.name) } - if (m & x) != 0 { - out = append(out, modeStrings[i]) - m = m ^ x + } + // unnamed residue + if mode != 0 { + if out == nil { + return fmt.Sprintf("LoadMode(%#x)", int(mode)) } + out = append(out, fmt.Sprintf("%#x", int(mode))) } - if m != 0 { - out = append(out, "Unknown") + if len(out) == 1 { + return out[0] } - return fmt.Sprintf("LoadMode(%s)", strings.Join(out, "|")) + return "(" + strings.Join(out, "|") + ")" } diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go index 0b6bfaff80..c3a59b8ebf 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -16,13 +16,13 @@ import ( "go/scanner" "go/token" "go/types" - "io" "log" "os" "path/filepath" "runtime" "strings" "sync" + "sync/atomic" "time" "golang.org/x/sync/errgroup" @@ -31,7 +31,6 @@ import ( "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" "golang.org/x/tools/internal/typesinternal" - "golang.org/x/tools/internal/versions" ) // A LoadMode controls the amount of detail to return when loading. @@ -44,19 +43,33 @@ import ( // ID and Errors (if present) will always be filled. // [Load] may return more information than requested. // +// The Mode flag is a union of several bits named NeedName, +// NeedFiles, and so on, each of which determines whether +// a given field of Package (Name, Files, etc) should be +// populated. +// +// For convenience, we provide named constants for the most +// common combinations of Need flags: +// +// [LoadFiles] lists of files in each package +// [LoadImports] ... plus imports +// [LoadTypes] ... plus type information +// [LoadSyntax] ... plus type-annotated syntax +// [LoadAllSyntax] ... for all dependencies +// // Unfortunately there are a number of open bugs related to // interactions among the LoadMode bits: -// - https://github.com/golang/go/issues/56633 -// - https://github.com/golang/go/issues/56677 -// - https://github.com/golang/go/issues/58726 -// - https://github.com/golang/go/issues/63517 +// - https://go.dev/issue/56633 +// - https://go.dev/issue/56677 +// - https://go.dev/issue/58726 +// - https://go.dev/issue/63517 type LoadMode int const ( // NeedName adds Name and PkgPath. NeedName LoadMode = 1 << iota - // NeedFiles adds GoFiles and OtherFiles. + // NeedFiles adds Dir, GoFiles, OtherFiles, and IgnoredFiles NeedFiles // NeedCompiledGoFiles adds CompiledGoFiles. @@ -78,7 +91,7 @@ const ( // NeedSyntax adds Syntax and Fset. NeedSyntax - // NeedTypesInfo adds TypesInfo. + // NeedTypesInfo adds TypesInfo and Fset. NeedTypesInfo // NeedTypesSizes adds TypesSizes. @@ -87,9 +100,10 @@ const ( // needInternalDepsErrors adds the internal deps errors field for use by gopls. needInternalDepsErrors - // needInternalForTest adds the internal forTest field. + // NeedForTest adds ForTest. + // // Tests must also be set on the context for this field to be populated. - needInternalForTest + NeedForTest // typecheckCgo enables full support for type checking cgo. Requires Go 1.15+. // Modifies CompiledGoFiles and Types, and has no effect on its own. @@ -103,27 +117,27 @@ const ( // NeedEmbedPatterns adds EmbedPatterns. NeedEmbedPatterns + + // NeedTarget adds Target. + NeedTarget + + // Be sure to update loadmode_string.go when adding new items! ) const ( - // Deprecated: LoadFiles exists for historical compatibility - // and should not be used. Please directly specify the needed fields using the Need values. + // LoadFiles loads the name and file names for the initial packages. LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles - // Deprecated: LoadImports exists for historical compatibility - // and should not be used. Please directly specify the needed fields using the Need values. + // LoadImports loads the name, file names, and import mapping for the initial packages. LoadImports = LoadFiles | NeedImports - // Deprecated: LoadTypes exists for historical compatibility - // and should not be used. Please directly specify the needed fields using the Need values. + // LoadTypes loads exported type information for the initial packages. LoadTypes = LoadImports | NeedTypes | NeedTypesSizes - // Deprecated: LoadSyntax exists for historical compatibility - // and should not be used. Please directly specify the needed fields using the Need values. + // LoadSyntax loads typed syntax for the initial packages. LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo - // Deprecated: LoadAllSyntax exists for historical compatibility - // and should not be used. Please directly specify the needed fields using the Need values. + // LoadAllSyntax loads typed syntax for the initial packages and all dependencies. LoadAllSyntax = LoadSyntax | NeedDeps // Deprecated: NeedExportsFile is a historical misspelling of NeedExportFile. @@ -133,13 +147,7 @@ const ( // A Config specifies details about how packages should be loaded. // The zero value is a valid configuration. // -// Calls to Load do not modify this struct. -// -// TODO(adonovan): #67702: this is currently false: in fact, -// calls to [Load] do not modify the public fields of this struct, but -// may modify hidden fields, so concurrent calls to [Load] must not -// use the same Config. But perhaps we should reestablish the -// documented invariant. +// Calls to [Load] do not modify this struct. type Config struct { // Mode controls the level of information returned for each package. Mode LoadMode @@ -170,19 +178,10 @@ type Config struct { // Env []string - // gocmdRunner guards go command calls from concurrency errors. - gocmdRunner *gocommand.Runner - // BuildFlags is a list of command-line flags to be passed through to // the build system's query tool. BuildFlags []string - // modFile will be used for -modfile in go command invocations. - modFile string - - // modFlag will be used for -modfile in go command invocations. - modFlag string - // Fset provides source position information for syntax trees and types. // If Fset is nil, Load will use a new fileset, but preserve Fset's value. Fset *token.FileSet @@ -229,21 +228,24 @@ type Config struct { // drivers may vary in their level of support for overlays. Overlay map[string][]byte - // goListOverlayFile is the JSON file that encodes the Overlay - // mapping, used by 'go list -overlay=...' - goListOverlayFile string + // -- Hidden configuration fields only for use in x/tools -- + + // modFile will be used for -modfile in go command invocations. + modFile string + + // modFlag will be used for -modfile in go command invocations. + modFlag string } // Load loads and returns the Go packages named by the given patterns. // -// Config specifies loading options; -// nil behaves the same as an empty Config. +// The cfg parameter specifies loading options; nil behaves the same as an empty [Config]. // // The [Config.Mode] field is a set of bits that determine what kinds // of information should be computed and returned. Modes that require // more information tend to be slower. See [LoadMode] for details // and important caveats. Its zero value is equivalent to -// NeedName | NeedFiles | NeedCompiledGoFiles. +// [NeedName] | [NeedFiles] | [NeedCompiledGoFiles]. // // Each call to Load returns a new set of [Package] instances. // The Packages and their Imports form a directed acyclic graph. @@ -260,7 +262,7 @@ type Config struct { // Errors associated with a particular package are recorded in the // corresponding Package's Errors list, and do not cause Load to // return an error. Clients may need to handle such errors before -// proceeding with further analysis. The PrintErrors function is +// proceeding with further analysis. The [PrintErrors] function is // provided for convenient display of all errors. func Load(cfg *Config, patterns ...string) ([]*Package, error) { ld := newLoader(cfg) @@ -323,21 +325,24 @@ func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, erro } else if !response.NotHandled { return response, true, nil } - // (fall through) + // not handled: fall through } // go list fallback - // + // Write overlays once, as there are many calls // to 'go list' (one per chunk plus others too). - overlay, cleanupOverlay, err := gocommand.WriteOverlays(cfg.Overlay) + overlayFile, cleanupOverlay, err := gocommand.WriteOverlays(cfg.Overlay) if err != nil { return nil, false, err } defer cleanupOverlay() - cfg.goListOverlayFile = overlay - response, err := callDriverOnChunks(goListDriver, cfg, chunks) + var runner gocommand.Runner // (shared across many 'go list' calls) + driver := func(cfg *Config, patterns []string) (*DriverResponse, error) { + return goListDriver(cfg, &runner, overlayFile, patterns) + } + response, err := callDriverOnChunks(driver, cfg, chunks) if err != nil { return nil, false, err } @@ -375,16 +380,14 @@ func splitIntoChunks(patterns []string, argMax int) ([][]string, error) { func callDriverOnChunks(driver driver, cfg *Config, chunks [][]string) (*DriverResponse, error) { if len(chunks) == 0 { - return driver(cfg) + return driver(cfg, nil) } responses := make([]*DriverResponse, len(chunks)) errNotHandled := errors.New("driver returned NotHandled") var g errgroup.Group for i, chunk := range chunks { - i := i - chunk := chunk g.Go(func() (err error) { - responses[i], err = driver(cfg, chunk...) + responses[i], err = driver(cfg, chunk) if responses[i] != nil && responses[i].NotHandled { err = errNotHandled } @@ -434,6 +437,12 @@ type Package struct { // PkgPath is the package path as used by the go/types package. PkgPath string + // Dir is the directory associated with the package, if it exists. + // + // For packages listed by the go command, this is the directory containing + // the package files. + Dir string + // Errors contains any errors encountered querying the metadata // of the package, or while parsing or type-checking its files. Errors []Error @@ -473,6 +482,10 @@ type Package struct { // information for the package as provided by the build system. ExportFile string + // Target is the absolute install path of the .a file, for libraries, + // and of the executable file, for binaries. + Target string + // Imports maps import paths appearing in the package's Go source files // to corresponding loaded Packages. Imports map[string]*Package @@ -521,8 +534,8 @@ type Package struct { // -- internal -- - // forTest is the package under test, if any. - forTest string + // ForTest is the package under test, if any. + ForTest string // depsErrors is the DepsErrors field from the go list response, if any. depsErrors []*packagesinternal.PackageError @@ -551,9 +564,6 @@ type ModuleError struct { } func init() { - packagesinternal.GetForTest = func(p interface{}) string { - return p.(*Package).forTest - } packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError { return p.(*Package).depsErrors } @@ -565,7 +575,6 @@ func init() { } packagesinternal.TypecheckCgo = int(typecheckCgo) packagesinternal.DepsErrors = int(needInternalDepsErrors) - packagesinternal.ForTest = int(needInternalForTest) } // An Error describes a problem with a package's metadata, syntax, or types. @@ -681,18 +690,19 @@ func (p *Package) String() string { return p.ID } // loaderPackage augments Package with state used during the loading phase type loaderPackage struct { *Package - importErrors map[string]error // maps each bad import to its error - loadOnce sync.Once - color uint8 // for cycle detection - needsrc bool // load from source (Mode >= LoadTypes) - needtypes bool // type information is either requested or depended on - initial bool // package was matched by a pattern - goVersion int // minor version number of go command on PATH + importErrors map[string]error // maps each bad import to its error + preds []*loaderPackage // packages that import this one + unfinishedSuccs atomic.Int32 // number of direct imports not yet loaded + color uint8 // for cycle detection + needsrc bool // load from source (Mode >= LoadTypes) + needtypes bool // type information is either requested or depended on + initial bool // package was matched by a pattern + goVersion int // minor version number of go command on PATH } // loader holds the working state of a single call to load. type loader struct { - pkgs map[string]*loaderPackage + pkgs map[string]*loaderPackage // keyed by Package.ID Config sizes types.Sizes // non-nil if needed by mode parseCache map[string]*parseValue @@ -738,9 +748,6 @@ func newLoader(cfg *Config) *loader { if ld.Config.Env == nil { ld.Config.Env = os.Environ() } - if ld.Config.gocmdRunner == nil { - ld.Config.gocmdRunner = &gocommand.Runner{} - } if ld.Context == nil { ld.Context = context.Background() } @@ -754,7 +761,7 @@ func newLoader(cfg *Config) *loader { ld.requestedMode = ld.Mode ld.Mode = impliedLoadMode(ld.Mode) - if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { + if ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0 { if ld.Fset == nil { ld.Fset = token.NewFileSet() } @@ -763,6 +770,7 @@ func newLoader(cfg *Config) *loader { // because we load source if export data is missing. if ld.ParseFile == nil { ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) { + // We implicitly promise to keep doing ast.Object resolution. :( const mode = parser.AllErrors | parser.ParseComments return parser.ParseFile(fset, filename, src, mode) } @@ -794,7 +802,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) { exportDataInvalid := len(ld.Overlay) > 0 || pkg.ExportFile == "" && pkg.PkgPath != "unsafe" // This package needs type information if the caller requested types and the package is // either a root, or it's a non-root and the user requested dependencies ... - needtypes := (ld.Mode&NeedTypes|NeedTypesInfo != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) + needtypes := (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) // This package needs source if the call requested source (or types info, which implies source) // and the package is either a root, or itas a non- root and the user requested dependencies... needsrc := ((ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) || @@ -819,9 +827,10 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) { } } - if ld.Mode&NeedImports != 0 { - // Materialize the import graph. - + // Materialize the import graph if it is needed (NeedImports), + // or if we'll be using loadPackages (Need{Syntax|Types|TypesInfo}). + var leaves []*loaderPackage // packages with no unfinished successors + if ld.Mode&(NeedImports|NeedSyntax|NeedTypes|NeedTypesInfo) != 0 { const ( white = 0 // new grey = 1 // in progress @@ -840,63 +849,76 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) { // dependency on a package that does. These are the only packages // for which we load source code. var stack []*loaderPackage - var visit func(lpkg *loaderPackage) bool - visit = func(lpkg *loaderPackage) bool { - switch lpkg.color { - case black: - return lpkg.needsrc - case grey: + var visit func(from, lpkg *loaderPackage) bool + visit = func(from, lpkg *loaderPackage) bool { + if lpkg.color == grey { panic("internal error: grey node") } - lpkg.color = grey - stack = append(stack, lpkg) // push - stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports - lpkg.Imports = make(map[string]*Package, len(stubs)) - for importPath, ipkg := range stubs { - var importErr error - imp := ld.pkgs[ipkg.ID] - if imp == nil { - // (includes package "C" when DisableCgo) - importErr = fmt.Errorf("missing package: %q", ipkg.ID) - } else if imp.color == grey { - importErr = fmt.Errorf("import cycle: %s", stack) + if lpkg.color == white { + lpkg.color = grey + stack = append(stack, lpkg) // push + stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports + lpkg.Imports = make(map[string]*Package, len(stubs)) + for importPath, ipkg := range stubs { + var importErr error + imp := ld.pkgs[ipkg.ID] + if imp == nil { + // (includes package "C" when DisableCgo) + importErr = fmt.Errorf("missing package: %q", ipkg.ID) + } else if imp.color == grey { + importErr = fmt.Errorf("import cycle: %s", stack) + } + if importErr != nil { + if lpkg.importErrors == nil { + lpkg.importErrors = make(map[string]error) + } + lpkg.importErrors[importPath] = importErr + continue + } + + if visit(lpkg, imp) { + lpkg.needsrc = true + } + lpkg.Imports[importPath] = imp.Package } - if importErr != nil { - if lpkg.importErrors == nil { - lpkg.importErrors = make(map[string]error) + + // -- postorder -- + + // Complete type information is required for the + // immediate dependencies of each source package. + if lpkg.needsrc && ld.Mode&NeedTypes != 0 { + for _, ipkg := range lpkg.Imports { + ld.pkgs[ipkg.ID].needtypes = true } - lpkg.importErrors[importPath] = importErr - continue } - if visit(imp) { - lpkg.needsrc = true + // NeedTypeSizes causes TypeSizes to be set even + // on packages for which types aren't needed. + if ld.Mode&NeedTypesSizes != 0 { + lpkg.TypesSizes = ld.sizes } - lpkg.Imports[importPath] = imp.Package - } - // Complete type information is required for the - // immediate dependencies of each source package. - if lpkg.needsrc && ld.Mode&NeedTypes != 0 { - for _, ipkg := range lpkg.Imports { - ld.pkgs[ipkg.ID].needtypes = true + // Add packages with no imports directly to the queue of leaves. + if len(lpkg.Imports) == 0 { + leaves = append(leaves, lpkg) } + + stack = stack[:len(stack)-1] // pop + lpkg.color = black } - // NeedTypeSizes causes TypeSizes to be set even - // on packages for which types aren't needed. - if ld.Mode&NeedTypesSizes != 0 { - lpkg.TypesSizes = ld.sizes + // Add edge from predecessor. + if from != nil { + from.unfinishedSuccs.Add(+1) // incref + lpkg.preds = append(lpkg.preds, from) } - stack = stack[:len(stack)-1] // pop - lpkg.color = black return lpkg.needsrc } // For each initial package, create its import DAG. for _, lpkg := range initial { - visit(lpkg) + visit(nil, lpkg) } } else { @@ -909,16 +931,45 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) { // Load type data and syntax if needed, starting at // the initial packages (roots of the import DAG). - if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { - var wg sync.WaitGroup - for _, lpkg := range initial { - wg.Add(1) - go func(lpkg *loaderPackage) { - ld.loadRecursive(lpkg) - wg.Done() - }(lpkg) + if ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0 { + + // We avoid using g.SetLimit to limit concurrency as + // it makes g.Go stop accepting work, which prevents + // workers from enqeuing, and thus finishing, and thus + // allowing the group to make progress: deadlock. + // + // Instead we use the ioLimit and cpuLimit semaphores. + g, _ := errgroup.WithContext(ld.Context) + + // enqueues adds a package to the type-checking queue. + // It must have no unfinished successors. + var enqueue func(*loaderPackage) + enqueue = func(lpkg *loaderPackage) { + g.Go(func() error { + // Parse and type-check. + ld.loadPackage(lpkg) + + // Notify each waiting predecessor, + // and enqueue it when it becomes a leaf. + for _, pred := range lpkg.preds { + if pred.unfinishedSuccs.Add(-1) == 0 { // decref + enqueue(pred) + } + } + + return nil + }) + } + + // Load leaves first, adding new packages + // to the queue as they become leaves. + for _, leaf := range leaves { + enqueue(leaf) + } + + if err := g.Wait(); err != nil { + return nil, err // cancelled } - wg.Wait() } // If the context is done, return its error and @@ -965,7 +1016,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) { if ld.requestedMode&NeedSyntax == 0 { ld.pkgs[i].Syntax = nil } - if ld.requestedMode&NeedTypes == 0 && ld.requestedMode&NeedSyntax == 0 { + if ld.requestedMode&(NeedSyntax|NeedTypes|NeedTypesInfo) == 0 { ld.pkgs[i].Fset = nil } if ld.requestedMode&NeedTypesInfo == 0 { @@ -982,31 +1033,10 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) { return result, nil } -// loadRecursive loads the specified package and its dependencies, -// recursively, in parallel, in topological order. -// It is atomic and idempotent. -// Precondition: ld.Mode&NeedTypes. -func (ld *loader) loadRecursive(lpkg *loaderPackage) { - lpkg.loadOnce.Do(func() { - // Load the direct dependencies, in parallel. - var wg sync.WaitGroup - for _, ipkg := range lpkg.Imports { - imp := ld.pkgs[ipkg.ID] - wg.Add(1) - go func(imp *loaderPackage) { - ld.loadRecursive(imp) - wg.Done() - }(imp) - } - wg.Wait() - ld.loadPackage(lpkg) - }) -} - -// loadPackage loads the specified package. +// loadPackage loads/parses/typechecks the specified package. // It must be called only once per Package, // after immediate dependencies are loaded. -// Precondition: ld.Mode & NeedTypes. +// Precondition: ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0. func (ld *loader) loadPackage(lpkg *loaderPackage) { if lpkg.PkgPath == "unsafe" { // Fill in the blanks to avoid surprises. @@ -1042,6 +1072,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { if !lpkg.needtypes && !lpkg.needsrc { return } + + // TODO(adonovan): this condition looks wrong: + // I think it should be lpkg.needtypes && !lpg.needsrc, + // so that NeedSyntax without NeedTypes can be satisfied by export data. if !lpkg.needsrc { if err := ld.loadFromExportData(lpkg); err != nil { lpkg.Errors = append(lpkg.Errors, Error{ @@ -1147,7 +1181,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { } lpkg.Syntax = files - if ld.Config.Mode&NeedTypes == 0 { + if ld.Config.Mode&(NeedTypes|NeedTypesInfo) == 0 { return } @@ -1158,16 +1192,20 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { return } - lpkg.TypesInfo = &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Implicits: make(map[ast.Node]types.Object), - Instances: make(map[*ast.Ident]types.Instance), - Scopes: make(map[ast.Node]*types.Scope), - Selections: make(map[*ast.SelectorExpr]*types.Selection), + // Populate TypesInfo only if needed, as it + // causes the type checker to work much harder. + if ld.Config.Mode&NeedTypesInfo != 0 { + lpkg.TypesInfo = &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), + Scopes: make(map[ast.Node]*types.Scope), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + FileVersions: make(map[*ast.File]string), + } } - versions.InitFileVersions(lpkg.TypesInfo) lpkg.TypesSizes = ld.sizes importer := importerFunc(func(path string) (*types.Package, error) { @@ -1220,6 +1258,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { } } + // Type-checking is CPU intensive. + cpuLimit <- unit{} // acquire a token + defer func() { <-cpuLimit }() // release a token + typErr := types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) lpkg.importErrors = nil // no longer needed @@ -1284,8 +1326,11 @@ type importerFunc func(path string) (*types.Package, error) func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } // We use a counting semaphore to limit -// the number of parallel I/O calls per process. -var ioLimit = make(chan bool, 20) +// the number of parallel I/O calls or CPU threads per process. +var ( + ioLimit = make(chan unit, 20) + cpuLimit = make(chan unit, runtime.GOMAXPROCS(0)) +) func (ld *loader) parseFile(filename string) (*ast.File, error) { ld.parseCacheMu.Lock() @@ -1302,20 +1347,28 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) { var src []byte for f, contents := range ld.Config.Overlay { + // TODO(adonovan): Inefficient for large overlays. + // Do an exact name-based map lookup + // (for nonexistent files) followed by a + // FileID-based map lookup (for existing ones). if sameFile(f, filename) { src = contents + break } } var err error if src == nil { - ioLimit <- true // wait + ioLimit <- unit{} // acquire a token src, err = os.ReadFile(filename) - <-ioLimit // signal + <-ioLimit // release a token } if err != nil { v.err = err } else { + // Parsing is CPU intensive. + cpuLimit <- unit{} // acquire a token v.f, v.err = ld.ParseFile(ld.Fset, filename, src) + <-cpuLimit // release a token } close(v.ready) @@ -1330,18 +1383,21 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) { // Because files are scanned in parallel, the token.Pos // positions of the resulting ast.Files are not ordered. func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) { - var wg sync.WaitGroup - n := len(filenames) - parsed := make([]*ast.File, n) - errors := make([]error, n) - for i, file := range filenames { - wg.Add(1) - go func(i int, filename string) { + var ( + n = len(filenames) + parsed = make([]*ast.File, n) + errors = make([]error, n) + ) + var g errgroup.Group + for i, filename := range filenames { + // This creates goroutines unnecessarily in the + // cache-hit case, but that case is uncommon. + g.Go(func() error { parsed[i], errors[i] = ld.parseFile(filename) - wg.Done() - }(i, file) + return nil + }) } - wg.Wait() + g.Wait() // Eliminate nils, preserving order. var o int @@ -1512,4 +1568,4 @@ func usesExportData(cfg *Config) bool { return cfg.Mode&NeedExportFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedDeps == 0 } -var _ interface{} = io.Discard // assert build toolchain is go1.16 or later +type unit struct{} diff --git a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index 9ada177758..16ed3c1780 100644 --- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -228,7 +228,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { // Reject obviously non-viable cases. switch obj := obj.(type) { case *types.TypeName: - if _, ok := aliases.Unalias(obj.Type()).(*types.TypeParam); !ok { + if _, ok := types.Unalias(obj.Type()).(*types.TypeParam); !ok { // With the exception of type parameters, only package-level type names // have a path. return "", fmt.Errorf("no path for %v", obj) @@ -280,26 +280,26 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { path = append(path, opType) T := o.Type() - if alias, ok := T.(*aliases.Alias); ok { - if r := findTypeParam(obj, aliases.TypeParams(alias), path, opTypeParam, nil); r != nil { + if alias, ok := T.(*types.Alias); ok { + if r := findTypeParam(obj, aliases.TypeParams(alias), path, opTypeParam); r != nil { return Path(r), nil } - if r := find(obj, aliases.Rhs(alias), append(path, opRhs), nil); r != nil { + if r := find(obj, aliases.Rhs(alias), append(path, opRhs)); r != nil { return Path(r), nil } } else if tname.IsAlias() { // legacy alias - if r := find(obj, T, path, nil); r != nil { + if r := find(obj, T, path); r != nil { return Path(r), nil } } else if named, ok := T.(*types.Named); ok { // defined (named) type - if r := findTypeParam(obj, named.TypeParams(), path, opTypeParam, nil); r != nil { + if r := findTypeParam(obj, named.TypeParams(), path, opTypeParam); r != nil { return Path(r), nil } - if r := find(obj, named.Underlying(), append(path, opUnderlying), nil); r != nil { + if r := find(obj, named.Underlying(), append(path, opUnderlying)); r != nil { return Path(r), nil } } @@ -312,7 +312,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { if _, ok := o.(*types.TypeName); !ok { if o.Exported() { // exported non-type (const, var, func) - if r := find(obj, o.Type(), append(path, opType), nil); r != nil { + if r := find(obj, o.Type(), append(path, opType)); r != nil { return Path(r), nil } } @@ -320,7 +320,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { } // Inspect declared methods of defined types. - if T, ok := aliases.Unalias(o.Type()).(*types.Named); ok { + if T, ok := types.Unalias(o.Type()).(*types.Named); ok { path = append(path, opType) // The method index here is always with respect // to the underlying go/types data structures, @@ -332,7 +332,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { if m == obj { return Path(path2), nil // found declared method } - if r := find(obj, m.Type(), append(path2, opType), nil); r != nil { + if r := find(obj, m.Type(), append(path2, opType)); r != nil { return Path(r), nil } } @@ -447,46 +447,64 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) { // // The seen map is used to short circuit cycles through type parameters. If // nil, it will be allocated as necessary. -func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]bool) []byte { +// +// The seenMethods map is used internally to short circuit cycles through +// interface methods, such as occur in the following example: +// +// type I interface { f() interface{I} } +// +// See golang/go#68046 for details. +func find(obj types.Object, T types.Type, path []byte) []byte { + return (&finder{obj: obj}).find(T, path) +} + +// finder closes over search state for a call to find. +type finder struct { + obj types.Object // the sought object + seenTParamNames map[*types.TypeName]bool // for cycle breaking through type parameters + seenMethods map[*types.Func]bool // for cycle breaking through recursive interfaces +} + +func (f *finder) find(T types.Type, path []byte) []byte { switch T := T.(type) { - case *aliases.Alias: - return find(obj, aliases.Unalias(T), path, seen) + case *types.Alias: + return f.find(types.Unalias(T), path) case *types.Basic, *types.Named: // Named types belonging to pkg were handled already, // so T must belong to another package. No path. return nil case *types.Pointer: - return find(obj, T.Elem(), append(path, opElem), seen) + return f.find(T.Elem(), append(path, opElem)) case *types.Slice: - return find(obj, T.Elem(), append(path, opElem), seen) + return f.find(T.Elem(), append(path, opElem)) case *types.Array: - return find(obj, T.Elem(), append(path, opElem), seen) + return f.find(T.Elem(), append(path, opElem)) case *types.Chan: - return find(obj, T.Elem(), append(path, opElem), seen) + return f.find(T.Elem(), append(path, opElem)) case *types.Map: - if r := find(obj, T.Key(), append(path, opKey), seen); r != nil { + if r := f.find(T.Key(), append(path, opKey)); r != nil { return r } - return find(obj, T.Elem(), append(path, opElem), seen) + return f.find(T.Elem(), append(path, opElem)) case *types.Signature: - if r := findTypeParam(obj, T.RecvTypeParams(), path, opRecvTypeParam, nil); r != nil { + if r := f.findTypeParam(T.RecvTypeParams(), path, opRecvTypeParam); r != nil { return r } - if r := findTypeParam(obj, T.TypeParams(), path, opTypeParam, seen); r != nil { + if r := f.findTypeParam(T.TypeParams(), path, opTypeParam); r != nil { return r } - if r := find(obj, T.Params(), append(path, opParams), seen); r != nil { + if r := f.find(T.Params(), append(path, opParams)); r != nil { return r } - return find(obj, T.Results(), append(path, opResults), seen) + return f.find(T.Results(), append(path, opResults)) case *types.Struct: for i := 0; i < T.NumFields(); i++ { fld := T.Field(i) path2 := appendOpArg(path, opField, i) - if fld == obj { + if fld == f.obj { return path2 // found field var } - if r := find(obj, fld.Type(), append(path2, opType), seen); r != nil { + if r := f.find(fld.Type(), append(path2, opType)); r != nil { return r } } @@ -495,10 +513,10 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] for i := 0; i < T.Len(); i++ { v := T.At(i) path2 := appendOpArg(path, opAt, i) - if v == obj { + if v == f.obj { return path2 // found param/result var } - if r := find(obj, v.Type(), append(path2, opType), seen); r != nil { + if r := f.find(v.Type(), append(path2, opType)); r != nil { return r } } @@ -506,28 +524,35 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] case *types.Interface: for i := 0; i < T.NumMethods(); i++ { m := T.Method(i) + if f.seenMethods[m] { + return nil + } path2 := appendOpArg(path, opMethod, i) - if m == obj { + if m == f.obj { return path2 // found interface method } - if r := find(obj, m.Type(), append(path2, opType), seen); r != nil { + if f.seenMethods == nil { + f.seenMethods = make(map[*types.Func]bool) + } + f.seenMethods[m] = true + if r := f.find(m.Type(), append(path2, opType)); r != nil { return r } } return nil case *types.TypeParam: name := T.Obj() - if name == obj { - return append(path, opObj) - } - if seen[name] { + if f.seenTParamNames[name] { return nil } - if seen == nil { - seen = make(map[*types.TypeName]bool) + if name == f.obj { + return append(path, opObj) } - seen[name] = true - if r := find(obj, T.Constraint(), append(path, opConstraint), seen); r != nil { + if f.seenTParamNames == nil { + f.seenTParamNames = make(map[*types.TypeName]bool) + } + f.seenTParamNames[name] = true + if r := f.find(T.Constraint(), append(path, opConstraint)); r != nil { return r } return nil @@ -535,11 +560,15 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] panic(T) } -func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, op byte, seen map[*types.TypeName]bool) []byte { +func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, op byte) []byte { + return (&finder{obj: obj}).findTypeParam(list, path, op) +} + +func (f *finder) findTypeParam(list *types.TypeParamList, path []byte, op byte) []byte { for i := 0; i < list.Len(); i++ { tparam := list.At(i) path2 := appendOpArg(path, op, i) - if r := find(obj, tparam, path2, seen); r != nil { + if r := f.find(tparam, path2); r != nil { return r } } @@ -626,7 +655,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { // Inv: t != nil, obj == nil - t = aliases.Unalias(t) + t = types.Unalias(t) switch code { case opElem: hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map @@ -664,7 +693,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { t = named.Underlying() case opRhs: - if alias, ok := t.(*aliases.Alias); ok { + if alias, ok := t.(*types.Alias); ok { t = aliases.Rhs(alias) } else if false && aliases.Enabled() { // The Enabled check is too expensive, so for now we diff --git a/vendor/golang.org/x/tools/go/types/typeutil/callee.go b/vendor/golang.org/x/tools/go/types/typeutil/callee.go new file mode 100644 index 0000000000..754380351e --- /dev/null +++ b/vendor/golang.org/x/tools/go/types/typeutil/callee.go @@ -0,0 +1,68 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typeutil + +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/internal/typeparams" +) + +// Callee returns the named target of a function call, if any: +// a function, method, builtin, or variable. +// +// Functions and methods may potentially have type parameters. +func Callee(info *types.Info, call *ast.CallExpr) types.Object { + fun := ast.Unparen(call.Fun) + + // Look through type instantiation if necessary. + isInstance := false + switch fun.(type) { + case *ast.IndexExpr, *ast.IndexListExpr: + // When extracting the callee from an *IndexExpr, we need to check that + // it is a *types.Func and not a *types.Var. + // Example: Don't match a slice m within the expression `m[0]()`. + isInstance = true + fun, _, _, _ = typeparams.UnpackIndexExpr(fun) + } + + var obj types.Object + switch fun := fun.(type) { + case *ast.Ident: + obj = info.Uses[fun] // type, var, builtin, or declared func + case *ast.SelectorExpr: + if sel, ok := info.Selections[fun]; ok { + obj = sel.Obj() // method or field + } else { + obj = info.Uses[fun.Sel] // qualified identifier? + } + } + if _, ok := obj.(*types.TypeName); ok { + return nil // T(x) is a conversion, not a call + } + // A Func is required to match instantiations. + if _, ok := obj.(*types.Func); isInstance && !ok { + return nil // Was not a Func. + } + return obj +} + +// StaticCallee returns the target (function or method) of a static function +// call, if any. It returns nil for calls to builtins. +// +// Note: for calls of instantiated functions and methods, StaticCallee returns +// the corresponding generic function or method on the generic type. +func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { + if f, ok := Callee(info, call).(*types.Func); ok && !interfaceMethod(f) { + return f + } + return nil +} + +func interfaceMethod(f *types.Func) bool { + recv := f.Type().(*types.Signature).Recv() + return recv != nil && types.IsInterface(recv.Type()) +} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/imports.go b/vendor/golang.org/x/tools/go/types/typeutil/imports.go new file mode 100644 index 0000000000..b81ce0c330 --- /dev/null +++ b/vendor/golang.org/x/tools/go/types/typeutil/imports.go @@ -0,0 +1,30 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typeutil + +import "go/types" + +// Dependencies returns all dependencies of the specified packages. +// +// Dependent packages appear in topological order: if package P imports +// package Q, Q appears earlier than P in the result. +// The algorithm follows import statements in the order they +// appear in the source code, so the result is a total order. +func Dependencies(pkgs ...*types.Package) []*types.Package { + var result []*types.Package + seen := make(map[*types.Package]bool) + var visit func(pkgs []*types.Package) + visit = func(pkgs []*types.Package) { + for _, p := range pkgs { + if !seen[p] { + seen[p] = true + visit(p.Imports()) + result = append(result, p) + } + } + } + visit(pkgs) + return result +} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/map.go b/vendor/golang.org/x/tools/go/types/typeutil/map.go new file mode 100644 index 0000000000..43261147c0 --- /dev/null +++ b/vendor/golang.org/x/tools/go/types/typeutil/map.go @@ -0,0 +1,470 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package typeutil defines various utilities for types, such as [Map], +// a hash table that maps [types.Type] to any value. +package typeutil + +import ( + "bytes" + "fmt" + "go/types" + "hash/maphash" + "unsafe" + + "golang.org/x/tools/internal/typeparams" +) + +// Map is a hash-table-based mapping from types (types.Type) to +// arbitrary values. The concrete types that implement +// the Type interface are pointers. Since they are not canonicalized, +// == cannot be used to check for equivalence, and thus we cannot +// simply use a Go map. +// +// Just as with map[K]V, a nil *Map is a valid empty map. +// +// Read-only map operations ([Map.At], [Map.Len], and so on) may +// safely be called concurrently. +// +// TODO(adonovan): deprecate in favor of https://go.dev/issues/69420 +// and 69559, if the latter proposals for a generic hash-map type and +// a types.Hash function are accepted. +type Map struct { + table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused + length int // number of map entries +} + +// entry is an entry (key/value association) in a hash bucket. +type entry struct { + key types.Type + value any +} + +// SetHasher has no effect. +// +// It is a relic of an optimization that is no longer profitable. Do +// not use [Hasher], [MakeHasher], or [SetHasher] in new code. +func (m *Map) SetHasher(Hasher) {} + +// Delete removes the entry with the given key, if any. +// It returns true if the entry was found. +func (m *Map) Delete(key types.Type) bool { + if m != nil && m.table != nil { + hash := hash(key) + bucket := m.table[hash] + for i, e := range bucket { + if e.key != nil && types.Identical(key, e.key) { + // We can't compact the bucket as it + // would disturb iterators. + bucket[i] = entry{} + m.length-- + return true + } + } + } + return false +} + +// At returns the map entry for the given key. +// The result is nil if the entry is not present. +func (m *Map) At(key types.Type) any { + if m != nil && m.table != nil { + for _, e := range m.table[hash(key)] { + if e.key != nil && types.Identical(key, e.key) { + return e.value + } + } + } + return nil +} + +// Set sets the map entry for key to val, +// and returns the previous entry, if any. +func (m *Map) Set(key types.Type, value any) (prev any) { + if m.table != nil { + hash := hash(key) + bucket := m.table[hash] + var hole *entry + for i, e := range bucket { + if e.key == nil { + hole = &bucket[i] + } else if types.Identical(key, e.key) { + prev = e.value + bucket[i].value = value + return + } + } + + if hole != nil { + *hole = entry{key, value} // overwrite deleted entry + } else { + m.table[hash] = append(bucket, entry{key, value}) + } + } else { + hash := hash(key) + m.table = map[uint32][]entry{hash: {entry{key, value}}} + } + + m.length++ + return +} + +// Len returns the number of map entries. +func (m *Map) Len() int { + if m != nil { + return m.length + } + return 0 +} + +// Iterate calls function f on each entry in the map in unspecified order. +// +// If f should mutate the map, Iterate provides the same guarantees as +// Go maps: if f deletes a map entry that Iterate has not yet reached, +// f will not be invoked for it, but if f inserts a map entry that +// Iterate has not yet reached, whether or not f will be invoked for +// it is unspecified. +func (m *Map) Iterate(f func(key types.Type, value any)) { + if m != nil { + for _, bucket := range m.table { + for _, e := range bucket { + if e.key != nil { + f(e.key, e.value) + } + } + } + } +} + +// Keys returns a new slice containing the set of map keys. +// The order is unspecified. +func (m *Map) Keys() []types.Type { + keys := make([]types.Type, 0, m.Len()) + m.Iterate(func(key types.Type, _ any) { + keys = append(keys, key) + }) + return keys +} + +func (m *Map) toString(values bool) string { + if m == nil { + return "{}" + } + var buf bytes.Buffer + fmt.Fprint(&buf, "{") + sep := "" + m.Iterate(func(key types.Type, value any) { + fmt.Fprint(&buf, sep) + sep = ", " + fmt.Fprint(&buf, key) + if values { + fmt.Fprintf(&buf, ": %q", value) + } + }) + fmt.Fprint(&buf, "}") + return buf.String() +} + +// String returns a string representation of the map's entries. +// Values are printed using fmt.Sprintf("%v", v). +// Order is unspecified. +func (m *Map) String() string { + return m.toString(true) +} + +// KeysString returns a string representation of the map's key set. +// Order is unspecified. +func (m *Map) KeysString() string { + return m.toString(false) +} + +// -- Hasher -- + +// hash returns the hash of type t. +// TODO(adonovan): replace by types.Hash when Go proposal #69420 is accepted. +func hash(t types.Type) uint32 { + return theHasher.Hash(t) +} + +// A Hasher provides a [Hasher.Hash] method to map a type to its hash value. +// Hashers are stateless, and all are equivalent. +type Hasher struct{} + +var theHasher Hasher + +// MakeHasher returns Hasher{}. +// Hashers are stateless; all are equivalent. +func MakeHasher() Hasher { return theHasher } + +// Hash computes a hash value for the given type t such that +// Identical(t, t') => Hash(t) == Hash(t'). +func (h Hasher) Hash(t types.Type) uint32 { + return hasher{inGenericSig: false}.hash(t) +} + +// hasher holds the state of a single Hash traversal: whether we are +// inside the signature of a generic function; this is used to +// optimize [hasher.hashTypeParam]. +type hasher struct{ inGenericSig bool } + +// hashString computes the Fowler–Noll–Vo hash of s. +func hashString(s string) uint32 { + var h uint32 + for i := 0; i < len(s); i++ { + h ^= uint32(s[i]) + h *= 16777619 + } + return h +} + +// hash computes the hash of t. +func (h hasher) hash(t types.Type) uint32 { + // See Identical for rationale. + switch t := t.(type) { + case *types.Basic: + return uint32(t.Kind()) + + case *types.Alias: + return h.hash(types.Unalias(t)) + + case *types.Array: + return 9043 + 2*uint32(t.Len()) + 3*h.hash(t.Elem()) + + case *types.Slice: + return 9049 + 2*h.hash(t.Elem()) + + case *types.Struct: + var hash uint32 = 9059 + for i, n := 0, t.NumFields(); i < n; i++ { + f := t.Field(i) + if f.Anonymous() { + hash += 8861 + } + hash += hashString(t.Tag(i)) + hash += hashString(f.Name()) // (ignore f.Pkg) + hash += h.hash(f.Type()) + } + return hash + + case *types.Pointer: + return 9067 + 2*h.hash(t.Elem()) + + case *types.Signature: + var hash uint32 = 9091 + if t.Variadic() { + hash *= 8863 + } + + tparams := t.TypeParams() + if n := tparams.Len(); n > 0 { + h.inGenericSig = true // affects constraints, params, and results + + for i := range n { + tparam := tparams.At(i) + hash += 7 * h.hash(tparam.Constraint()) + } + } + + return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) + + case *types.Union: + return h.hashUnion(t) + + case *types.Interface: + // Interfaces are identical if they have the same set of methods, with + // identical names and types, and they have the same set of type + // restrictions. See go/types.identical for more details. + var hash uint32 = 9103 + + // Hash methods. + for i, n := 0, t.NumMethods(); i < n; i++ { + // Method order is not significant. + // Ignore m.Pkg(). + m := t.Method(i) + // Use shallow hash on method signature to + // avoid anonymous interface cycles. + hash += 3*hashString(m.Name()) + 5*h.shallowHash(m.Type()) + } + + // Hash type restrictions. + terms, err := typeparams.InterfaceTermSet(t) + // if err != nil t has invalid type restrictions. + if err == nil { + hash += h.hashTermSet(terms) + } + + return hash + + case *types.Map: + return 9109 + 2*h.hash(t.Key()) + 3*h.hash(t.Elem()) + + case *types.Chan: + return 9127 + 2*uint32(t.Dir()) + 3*h.hash(t.Elem()) + + case *types.Named: + hash := h.hashTypeName(t.Obj()) + targs := t.TypeArgs() + for i := 0; i < targs.Len(); i++ { + targ := targs.At(i) + hash += 2 * h.hash(targ) + } + return hash + + case *types.TypeParam: + return h.hashTypeParam(t) + + case *types.Tuple: + return h.hashTuple(t) + } + + panic(fmt.Sprintf("%T: %v", t, t)) +} + +func (h hasher) hashTuple(tuple *types.Tuple) uint32 { + // See go/types.identicalTypes for rationale. + n := tuple.Len() + hash := 9137 + 2*uint32(n) + for i := range n { + hash += 3 * h.hash(tuple.At(i).Type()) + } + return hash +} + +func (h hasher) hashUnion(t *types.Union) uint32 { + // Hash type restrictions. + terms, err := typeparams.UnionTermSet(t) + // if err != nil t has invalid type restrictions. Fall back on a non-zero + // hash. + if err != nil { + return 9151 + } + return h.hashTermSet(terms) +} + +func (h hasher) hashTermSet(terms []*types.Term) uint32 { + hash := 9157 + 2*uint32(len(terms)) + for _, term := range terms { + // term order is not significant. + termHash := h.hash(term.Type()) + if term.Tilde() { + termHash *= 9161 + } + hash += 3 * termHash + } + return hash +} + +// hashTypeParam returns the hash of a type parameter. +func (h hasher) hashTypeParam(t *types.TypeParam) uint32 { + // Within the signature of a generic function, TypeParams are + // identical if they have the same index and constraint, so we + // hash them based on index. + // + // When we are outside a generic function, free TypeParams are + // identical iff they are the same object, so we can use a + // more discriminating hash consistent with object identity. + // This optimization saves [Map] about 4% when hashing all the + // types.Info.Types in the forward closure of net/http. + if !h.inGenericSig { + // Optimization: outside a generic function signature, + // use a more discrimating hash consistent with object identity. + return h.hashTypeName(t.Obj()) + } + return 9173 + 3*uint32(t.Index()) +} + +var theSeed = maphash.MakeSeed() + +// hashTypeName hashes the pointer of tname. +func (hasher) hashTypeName(tname *types.TypeName) uint32 { + // Since types.Identical uses == to compare TypeNames, + // the Hash function uses maphash.Comparable. + // TODO(adonovan): or will, when it becomes available in go1.24. + // In the meantime we use the pointer's numeric value. + // + // hash := maphash.Comparable(theSeed, tname) + // + // (Another approach would be to hash the name and package + // path, and whether or not it is a package-level typename. It + // is rare for a package to define multiple local types with + // the same name.) + hash := uintptr(unsafe.Pointer(tname)) + return uint32(hash ^ (hash >> 32)) +} + +// shallowHash computes a hash of t without looking at any of its +// element Types, to avoid potential anonymous cycles in the types of +// interface methods. +// +// When an unnamed non-empty interface type appears anywhere among the +// arguments or results of an interface method, there is a potential +// for endless recursion. Consider: +// +// type X interface { m() []*interface { X } } +// +// The problem is that the Methods of the interface in m's result type +// include m itself; there is no mention of the named type X that +// might help us break the cycle. +// (See comment in go/types.identical, case *Interface, for more.) +func (h hasher) shallowHash(t types.Type) uint32 { + // t is the type of an interface method (Signature), + // its params or results (Tuples), or their immediate + // elements (mostly Slice, Pointer, Basic, Named), + // so there's no need to optimize anything else. + switch t := t.(type) { + case *types.Alias: + return h.shallowHash(types.Unalias(t)) + + case *types.Signature: + var hash uint32 = 604171 + if t.Variadic() { + hash *= 971767 + } + // The Signature/Tuple recursion is always finite + // and invariably shallow. + return hash + 1062599*h.shallowHash(t.Params()) + 1282529*h.shallowHash(t.Results()) + + case *types.Tuple: + n := t.Len() + hash := 9137 + 2*uint32(n) + for i := range n { + hash += 53471161 * h.shallowHash(t.At(i).Type()) + } + return hash + + case *types.Basic: + return 45212177 * uint32(t.Kind()) + + case *types.Array: + return 1524181 + 2*uint32(t.Len()) + + case *types.Slice: + return 2690201 + + case *types.Struct: + return 3326489 + + case *types.Pointer: + return 4393139 + + case *types.Union: + return 562448657 + + case *types.Interface: + return 2124679 // no recursion here + + case *types.Map: + return 9109 + + case *types.Chan: + return 9127 + + case *types.Named: + return h.hashTypeName(t.Obj()) + + case *types.TypeParam: + return h.hashTypeParam(t) + } + panic(fmt.Sprintf("shallowHash: %T: %v", t, t)) +} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go b/vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go new file mode 100644 index 0000000000..f7666028fe --- /dev/null +++ b/vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go @@ -0,0 +1,71 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements a cache of method sets. + +package typeutil + +import ( + "go/types" + "sync" +) + +// A MethodSetCache records the method set of each type T for which +// MethodSet(T) is called so that repeat queries are fast. +// The zero value is a ready-to-use cache instance. +type MethodSetCache struct { + mu sync.Mutex + named map[*types.Named]struct{ value, pointer *types.MethodSet } // method sets for named N and *N + others map[types.Type]*types.MethodSet // all other types +} + +// MethodSet returns the method set of type T. It is thread-safe. +// +// If cache is nil, this function is equivalent to types.NewMethodSet(T). +// Utility functions can thus expose an optional *MethodSetCache +// parameter to clients that care about performance. +func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { + if cache == nil { + return types.NewMethodSet(T) + } + cache.mu.Lock() + defer cache.mu.Unlock() + + switch T := types.Unalias(T).(type) { + case *types.Named: + return cache.lookupNamed(T).value + + case *types.Pointer: + if N, ok := types.Unalias(T.Elem()).(*types.Named); ok { + return cache.lookupNamed(N).pointer + } + } + + // all other types + // (The map uses pointer equivalence, not type identity.) + mset := cache.others[T] + if mset == nil { + mset = types.NewMethodSet(T) + if cache.others == nil { + cache.others = make(map[types.Type]*types.MethodSet) + } + cache.others[T] = mset + } + return mset +} + +func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } { + if cache.named == nil { + cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet }) + } + // Avoid recomputing mset(*T) for each distinct Pointer + // instance whose underlying type is a named type. + msets, ok := cache.named[named] + if !ok { + msets.value = types.NewMethodSet(named) + msets.pointer = types.NewMethodSet(types.NewPointer(named)) + cache.named[named] = msets + } + return msets +} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/ui.go b/vendor/golang.org/x/tools/go/types/typeutil/ui.go new file mode 100644 index 0000000000..9dda6a25df --- /dev/null +++ b/vendor/golang.org/x/tools/go/types/typeutil/ui.go @@ -0,0 +1,53 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typeutil + +// This file defines utilities for user interfaces that display types. + +import ( + "go/types" +) + +// IntuitiveMethodSet returns the intuitive method set of a type T, +// which is the set of methods you can call on an addressable value of +// that type. +// +// The result always contains MethodSet(T), and is exactly MethodSet(T) +// for interface types and for pointer-to-concrete types. +// For all other concrete types T, the result additionally +// contains each method belonging to *T if there is no identically +// named method on T itself. +// +// This corresponds to user intuition about method sets; +// this function is intended only for user interfaces. +// +// The order of the result is as for types.MethodSet(T). +func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection { + isPointerToConcrete := func(T types.Type) bool { + ptr, ok := types.Unalias(T).(*types.Pointer) + return ok && !types.IsInterface(ptr.Elem()) + } + + var result []*types.Selection + mset := msets.MethodSet(T) + if types.IsInterface(T) || isPointerToConcrete(T) { + for i, n := 0, mset.Len(); i < n; i++ { + result = append(result, mset.At(i)) + } + } else { + // T is some other concrete type. + // Report methods of T and *T, preferring those of T. + pmset := msets.MethodSet(types.NewPointer(T)) + for i, n := 0, pmset.Len(); i < n; i++ { + meth := pmset.At(i) + if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil { + meth = m + } + result = append(result, meth) + } + + } + return result +} diff --git a/vendor/golang.org/x/tools/internal/aliases/aliases.go b/vendor/golang.org/x/tools/internal/aliases/aliases.go index c24c2eee45..b9425f5a20 100644 --- a/vendor/golang.org/x/tools/internal/aliases/aliases.go +++ b/vendor/golang.org/x/tools/internal/aliases/aliases.go @@ -22,11 +22,17 @@ import ( // GODEBUG=gotypesalias=... by invoking the type checker. The Enabled // function is expensive and should be called once per task (e.g. // package import), not once per call to NewAlias. -func NewAlias(enabled bool, pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName { +// +// Precondition: enabled || len(tparams)==0. +// If materialized aliases are disabled, there must not be any type parameters. +func NewAlias(enabled bool, pos token.Pos, pkg *types.Package, name string, rhs types.Type, tparams []*types.TypeParam) *types.TypeName { if enabled { tname := types.NewTypeName(pos, pkg, name, nil) - newAlias(tname, rhs) + SetTypeParams(types.NewAlias(tname, rhs), tparams) return tname } + if len(tparams) > 0 { + panic("cannot create an alias with type parameters when gotypesalias is not enabled") + } return types.NewTypeName(pos, pkg, name, rhs) } diff --git a/vendor/golang.org/x/tools/internal/aliases/aliases_go121.go b/vendor/golang.org/x/tools/internal/aliases/aliases_go121.go deleted file mode 100644 index 6652f7db0f..0000000000 --- a/vendor/golang.org/x/tools/internal/aliases/aliases_go121.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2024 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.22 -// +build !go1.22 - -package aliases - -import ( - "go/types" -) - -// Alias is a placeholder for a go/types.Alias for <=1.21. -// It will never be created by go/types. -type Alias struct{} - -func (*Alias) String() string { panic("unreachable") } -func (*Alias) Underlying() types.Type { panic("unreachable") } -func (*Alias) Obj() *types.TypeName { panic("unreachable") } -func Rhs(alias *Alias) types.Type { panic("unreachable") } -func TypeParams(alias *Alias) *types.TypeParamList { panic("unreachable") } -func SetTypeParams(alias *Alias, tparams []*types.TypeParam) { panic("unreachable") } -func TypeArgs(alias *Alias) *types.TypeList { panic("unreachable") } -func Origin(alias *Alias) *Alias { panic("unreachable") } - -// Unalias returns the type t for go <=1.21. -func Unalias(t types.Type) types.Type { return t } - -func newAlias(name *types.TypeName, rhs types.Type) *Alias { panic("unreachable") } - -// Enabled reports whether [NewAlias] should create [types.Alias] types. -// -// Before go1.22, this function always returns false. -func Enabled() bool { return false } diff --git a/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go b/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go index 3ef1afeb40..7716a3331d 100644 --- a/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go +++ b/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.22 -// +build go1.22 - package aliases import ( @@ -14,22 +11,19 @@ import ( "go/types" ) -// Alias is an alias of types.Alias. -type Alias = types.Alias - // Rhs returns the type on the right-hand side of the alias declaration. -func Rhs(alias *Alias) types.Type { +func Rhs(alias *types.Alias) types.Type { if alias, ok := any(alias).(interface{ Rhs() types.Type }); ok { return alias.Rhs() // go1.23+ } // go1.22's Alias didn't have the Rhs method, // so Unalias is the best we can do. - return Unalias(alias) + return types.Unalias(alias) } // TypeParams returns the type parameter list of the alias. -func TypeParams(alias *Alias) *types.TypeParamList { +func TypeParams(alias *types.Alias) *types.TypeParamList { if alias, ok := any(alias).(interface{ TypeParams() *types.TypeParamList }); ok { return alias.TypeParams() // go1.23+ } @@ -37,7 +31,7 @@ func TypeParams(alias *Alias) *types.TypeParamList { } // SetTypeParams sets the type parameters of the alias type. -func SetTypeParams(alias *Alias, tparams []*types.TypeParam) { +func SetTypeParams(alias *types.Alias, tparams []*types.TypeParam) { if alias, ok := any(alias).(interface { SetTypeParams(tparams []*types.TypeParam) }); ok { @@ -48,7 +42,7 @@ func SetTypeParams(alias *Alias, tparams []*types.TypeParam) { } // TypeArgs returns the type arguments used to instantiate the Alias type. -func TypeArgs(alias *Alias) *types.TypeList { +func TypeArgs(alias *types.Alias) *types.TypeList { if alias, ok := any(alias).(interface{ TypeArgs() *types.TypeList }); ok { return alias.TypeArgs() // go1.23+ } @@ -57,26 +51,13 @@ func TypeArgs(alias *Alias) *types.TypeList { // Origin returns the generic Alias type of which alias is an instance. // If alias is not an instance of a generic alias, Origin returns alias. -func Origin(alias *Alias) *Alias { +func Origin(alias *types.Alias) *types.Alias { if alias, ok := any(alias).(interface{ Origin() *types.Alias }); ok { return alias.Origin() // go1.23+ } return alias // not an instance of a generic alias (go1.22) } -// Unalias is a wrapper of types.Unalias. -func Unalias(t types.Type) types.Type { return types.Unalias(t) } - -// newAlias is an internal alias around types.NewAlias. -// Direct usage is discouraged as the moment. -// Try to use NewAlias instead. -func newAlias(tname *types.TypeName, rhs types.Type) *Alias { - a := types.NewAlias(tname, rhs) - // TODO(go.dev/issue/65455): Remove kludgy workaround to set a.actual as a side-effect. - Unalias(a) - return a -} - // Enabled reports whether [NewAlias] should create [types.Alias] types. // // This function is expensive! Call it sparingly. @@ -92,7 +73,7 @@ func Enabled() bool { // many tests. Therefore any attempt to cache the result // is just incorrect. fset := token.NewFileSet() - f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", 0) + f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", parser.SkipObjectResolution) pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil) _, enabled := pkg.Scope().Lookup("A").Type().(*types.Alias) return enabled diff --git a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go index e0b13e70a0..abf708111b 100644 --- a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go +++ b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go @@ -8,286 +8,65 @@ package analysisinternal import ( "bytes" + "cmp" "fmt" "go/ast" + "go/printer" + "go/scanner" "go/token" "go/types" - "os" pathpkg "path" - "strconv" + "slices" + "strings" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/internal/aliases" + "golang.org/x/tools/internal/typesinternal" ) func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos { // Get the end position for the type error. - offset, end := fset.PositionFor(start, false).Offset, start - if offset >= len(src) { - return end + file := fset.File(start) + if file == nil { + return start } - if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 { - end = start + token.Pos(width) - } - return end -} - -func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { - // TODO(adonovan): think about generics, and also generic aliases. - under := aliases.Unalias(typ) - // Don't call Underlying unconditionally: although it removes - // Named and Alias, it also removes TypeParam. - if n, ok := under.(*types.Named); ok { - under = n.Underlying() - } - switch under := under.(type) { - case *types.Basic: - switch { - case under.Info()&types.IsNumeric != 0: - return &ast.BasicLit{Kind: token.INT, Value: "0"} - case under.Info()&types.IsBoolean != 0: - return &ast.Ident{Name: "false"} - case under.Info()&types.IsString != 0: - return &ast.BasicLit{Kind: token.STRING, Value: `""`} - default: - panic(fmt.Sprintf("unknown basic type %v", under)) - } - case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array: - return ast.NewIdent("nil") - case *types.Struct: - texpr := TypeExpr(f, pkg, typ) // typ because we want the name here. - if texpr == nil { - return nil - } - return &ast.CompositeLit{ - Type: texpr, - } - } - return nil -} - -// IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of -// analysisinternal.ZeroValue) -func IsZeroValue(expr ast.Expr) bool { - switch e := expr.(type) { - case *ast.BasicLit: - return e.Value == "0" || e.Value == `""` - case *ast.Ident: - return e.Name == "nil" || e.Name == "false" - default: - return false - } -} - -// TypeExpr returns syntax for the specified type. References to -// named types from packages other than pkg are qualified by an appropriate -// package name, as defined by the import environment of file. -func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { - switch t := typ.(type) { - case *types.Basic: - switch t.Kind() { - case types.UnsafePointer: - return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")} - default: - return ast.NewIdent(t.Name()) - } - case *types.Pointer: - x := TypeExpr(f, pkg, t.Elem()) - if x == nil { - return nil - } - return &ast.UnaryExpr{ - Op: token.MUL, - X: x, - } - case *types.Array: - elt := TypeExpr(f, pkg, t.Elem()) - if elt == nil { - return nil - } - return &ast.ArrayType{ - Len: &ast.BasicLit{ - Kind: token.INT, - Value: fmt.Sprintf("%d", t.Len()), - }, - Elt: elt, - } - case *types.Slice: - elt := TypeExpr(f, pkg, t.Elem()) - if elt == nil { - return nil - } - return &ast.ArrayType{ - Elt: elt, - } - case *types.Map: - key := TypeExpr(f, pkg, t.Key()) - value := TypeExpr(f, pkg, t.Elem()) - if key == nil || value == nil { - return nil - } - return &ast.MapType{ - Key: key, - Value: value, - } - case *types.Chan: - dir := ast.ChanDir(t.Dir()) - if t.Dir() == types.SendRecv { - dir = ast.SEND | ast.RECV - } - value := TypeExpr(f, pkg, t.Elem()) - if value == nil { - return nil - } - return &ast.ChanType{ - Dir: dir, - Value: value, - } - case *types.Signature: - var params []*ast.Field - for i := 0; i < t.Params().Len(); i++ { - p := TypeExpr(f, pkg, t.Params().At(i).Type()) - if p == nil { - return nil - } - params = append(params, &ast.Field{ - Type: p, - Names: []*ast.Ident{ - { - Name: t.Params().At(i).Name(), - }, - }, - }) - } - if t.Variadic() { - last := params[len(params)-1] - last.Type = &ast.Ellipsis{Elt: last.Type.(*ast.ArrayType).Elt} - } - var returns []*ast.Field - for i := 0; i < t.Results().Len(); i++ { - r := TypeExpr(f, pkg, t.Results().At(i).Type()) - if r == nil { - return nil - } - returns = append(returns, &ast.Field{ - Type: r, - }) - } - return &ast.FuncType{ - Params: &ast.FieldList{ - List: params, - }, - Results: &ast.FieldList{ - List: returns, - }, - } - case interface{ Obj() *types.TypeName }: // *types.{Alias,Named,TypeParam} - if t.Obj().Pkg() == nil { - return ast.NewIdent(t.Obj().Name()) - } - if t.Obj().Pkg() == pkg { - return ast.NewIdent(t.Obj().Name()) - } - pkgName := t.Obj().Pkg().Name() - - // If the file already imports the package under another name, use that. - for _, cand := range f.Imports { - if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() { - if cand.Name != nil && cand.Name.Name != "" { - pkgName = cand.Name.Name - } - } - } - if pkgName == "." { - return ast.NewIdent(t.Obj().Name()) - } - return &ast.SelectorExpr{ - X: ast.NewIdent(pkgName), - Sel: ast.NewIdent(t.Obj().Name()), - } - case *types.Struct: - return ast.NewIdent(t.String()) - case *types.Interface: - return ast.NewIdent(t.String()) - default: - return nil + if offset := file.PositionFor(start, false).Offset; offset > len(src) { + return start + } else { + src = src[offset:] } -} -// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable. -// Some examples: -// -// Basic Example: -// z := 1 -// y := z + x -// If x is undeclared, then this function would return `y := z + x`, so that we -// can insert `x := ` on the line before `y := z + x`. -// -// If stmt example: -// if z == 1 { -// } else if z == y {} -// If y is undeclared, then this function would return `if z == 1 {`, because we cannot -// insert a statement between an if and an else if statement. As a result, we need to find -// the top of the if chain to insert `y := ` before. -func StmtToInsertVarBefore(path []ast.Node) ast.Stmt { - enclosingIndex := -1 - for i, p := range path { - if _, ok := p.(ast.Stmt); ok { - enclosingIndex = i - break - } - } - if enclosingIndex == -1 { - return nil - } - enclosingStmt := path[enclosingIndex] - switch enclosingStmt.(type) { - case *ast.IfStmt: - // The enclosingStmt is inside of the if declaration, - // We need to check if we are in an else-if stmt and - // get the base if statement. - return baseIfStmt(path, enclosingIndex) - case *ast.CaseClause: - // Get the enclosing switch stmt if the enclosingStmt is - // inside of the case statement. - for i := enclosingIndex + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.SwitchStmt); ok { - return node - } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok { - return node - } - } - } - if len(path) <= enclosingIndex+1 { - return enclosingStmt.(ast.Stmt) - } - // Check if the enclosing statement is inside another node. - switch expr := path[enclosingIndex+1].(type) { - case *ast.IfStmt: - // Get the base if statement. - return baseIfStmt(path, enclosingIndex+1) - case *ast.ForStmt: - if expr.Init == enclosingStmt || expr.Post == enclosingStmt { - return expr + // Attempt to find a reasonable end position for the type error. + // + // TODO(rfindley): the heuristic implemented here is unclear. It looks like + // it seeks the end of the primary operand starting at start, but that is not + // quite implemented (for example, given a func literal this heuristic will + // return the range of the func keyword). + // + // We should formalize this heuristic, or deprecate it by finally proposing + // to add end position to all type checker errors. + // + // Nevertheless, ensure that the end position at least spans the current + // token at the cursor (this was golang/go#69505). + end := start + { + var s scanner.Scanner + fset := token.NewFileSet() + f := fset.AddFile("", fset.Base(), len(src)) + s.Init(f, src, nil /* no error handler */, scanner.ScanComments) + pos, tok, lit := s.Scan() + if tok != token.SEMICOLON && token.Pos(f.Base()) <= pos && pos <= token.Pos(f.Base()+f.Size()) { + off := file.Offset(pos) + len(lit) + src = src[off:] + end += token.Pos(off) } - case *ast.SwitchStmt, *ast.TypeSwitchStmt: - return expr.(ast.Stmt) } - return enclosingStmt.(ast.Stmt) -} -// baseIfStmt walks up the if/else-if chain until we get to -// the top of the current if chain. -func baseIfStmt(path []ast.Node, index int) ast.Stmt { - stmt := path[index] - for i := index + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt { - stmt = node - continue - } - break + // Look for bytes that might terminate the current operand. See note above: + // this is imprecise. + if width := bytes.IndexAny(src, " \n,():;[]+-*/"); width > 0 { + end += token.Pos(width) } - return stmt.(ast.Stmt) + return end } // WalkASTWithParent walks the AST rooted at n. The semantics are @@ -399,49 +178,50 @@ func equivalentTypes(want, got types.Type) bool { return types.AssignableTo(want, got) } -// MakeReadFile returns a simple implementation of the Pass.ReadFile function. -func MakeReadFile(pass *analysis.Pass) func(filename string) ([]byte, error) { +// A ReadFileFunc is a function that returns the +// contents of a file, such as [os.ReadFile]. +type ReadFileFunc = func(filename string) ([]byte, error) + +// CheckedReadFile returns a wrapper around a Pass.ReadFile +// function that performs the appropriate checks. +func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc { return func(filename string) ([]byte, error) { if err := CheckReadable(pass, filename); err != nil { return nil, err } - return os.ReadFile(filename) + return readFile(filename) } } // CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass]. func CheckReadable(pass *analysis.Pass, filename string) error { - if slicesContains(pass.OtherFiles, filename) || - slicesContains(pass.IgnoredFiles, filename) { + if slices.Contains(pass.OtherFiles, filename) || + slices.Contains(pass.IgnoredFiles, filename) { return nil } for _, f := range pass.Files { - // TODO(adonovan): use go1.20 f.FileStart - if pass.Fset.File(f.Pos()).Name() == filename { + if pass.Fset.File(f.FileStart).Name() == filename { return nil } } return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename) } -// TODO(adonovan): use go1.21 slices.Contains. -func slicesContains[S ~[]E, E comparable](slice S, x E) bool { - for _, elem := range slice { - if elem == x { - return true - } - } - return false -} - // AddImport checks whether this file already imports pkgpath and // that import is in scope at pos. If so, it returns the name under // which it was imported and a zero edit. Otherwise, it adds a new // import of pkgpath, using a name derived from the preferred name, -// and returns the chosen name along with the edit for the new import. +// and returns the chosen name, a prefix to be concatenated with member +// to form a qualified name, and the edit for the new import. +// +// In the special case that pkgpath is dot-imported then member, the +// identifer for which the import is being added, is consulted. If +// member is not shadowed at pos, AddImport returns (".", "", nil). +// (AddImport accepts the caller's implicit claim that the imported +// package declares member.) // // It does not mutate its arguments. -func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferredName string) (name string, newImport []analysis.TextEdit) { +func AddImport(info *types.Info, file *ast.File, preferredName, pkgpath, member string, pos token.Pos) (name, prefix string, newImport []analysis.TextEdit) { // Find innermost enclosing lexical block. scope := info.Scopes[file].Innermost(pos) if scope == nil { @@ -451,10 +231,16 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr // Is there an existing import of this package? // If so, are we in its scope? (not shadowed) for _, spec := range file.Imports { - pkgname, ok := importedPkgName(info, spec) - if ok && pkgname.Imported().Path() == pkgpath { - if _, obj := scope.LookupParent(pkgname.Name(), pos); obj == pkgname { - return pkgname.Name(), nil + pkgname := info.PkgNameOf(spec) + if pkgname != nil && pkgname.Imported().Path() == pkgpath { + name = pkgname.Name() + if name == "." { + // The scope of ident must be the file scope. + if s, _ := scope.LookupParent(member, pos); s == info.Scopes[file] { + return name, "", nil + } + } else if _, obj := scope.LookupParent(name, pos); obj == pkgname { + return name, name + ".", nil } } } @@ -492,22 +278,174 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr before = decl0.Doc } } - return newName, []analysis.TextEdit{{ + return newName, newName + ".", []analysis.TextEdit{{ Pos: before.Pos(), End: before.Pos(), NewText: []byte(newText), }} } -// importedPkgName returns the PkgName object declared by an ImportSpec. -// TODO(adonovan): use go1.22's Info.PkgNameOf. -func importedPkgName(info *types.Info, imp *ast.ImportSpec) (*types.PkgName, bool) { - var obj types.Object - if imp.Name != nil { - obj = info.Defs[imp.Name] - } else { - obj = info.Implicits[imp] +// Format returns a string representation of the expression e. +func Format(fset *token.FileSet, e ast.Expr) string { + var buf strings.Builder + printer.Fprint(&buf, fset, e) // ignore errors + return buf.String() +} + +// Imports returns true if path is imported by pkg. +func Imports(pkg *types.Package, path string) bool { + for _, imp := range pkg.Imports() { + if imp.Path() == path { + return true + } + } + return false +} + +// IsTypeNamed reports whether t is (or is an alias for) a +// package-level defined type with the given package path and one of +// the given names. It returns false if t is nil. +// +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsTypeNamed(t types.Type, pkgPath string, names ...string) bool { + if named, ok := types.Unalias(t).(*types.Named); ok { + tname := named.Obj() + return tname != nil && + typesinternal.IsPackageLevel(tname) && + tname.Pkg().Path() == pkgPath && + slices.Contains(names, tname.Name()) + } + return false +} + +// IsPointerToNamed reports whether t is (or is an alias for) a pointer to a +// package-level defined type with the given package path and one of the given +// names. It returns false if t is not a pointer type. +func IsPointerToNamed(t types.Type, pkgPath string, names ...string) bool { + r := typesinternal.Unpointer(t) + if r == t { + return false + } + return IsTypeNamed(r, pkgPath, names...) +} + +// IsFunctionNamed reports whether obj is a package-level function +// defined in the given package and has one of the given names. +// It returns false if obj is nil. +// +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool { + f, ok := obj.(*types.Func) + return ok && + typesinternal.IsPackageLevel(obj) && + f.Pkg().Path() == pkgPath && + f.Type().(*types.Signature).Recv() == nil && + slices.Contains(names, f.Name()) +} + +// IsMethodNamed reports whether obj is a method defined on a +// package-level type with the given package and type name, and has +// one of the given names. It returns false if obj is nil. +// +// This function avoids allocating the concatenation of "pkg.TypeName.Name", +// which is important for the performance of syntax matching. +func IsMethodNamed(obj types.Object, pkgPath string, typeName string, names ...string) bool { + if fn, ok := obj.(*types.Func); ok { + if recv := fn.Type().(*types.Signature).Recv(); recv != nil { + _, T := typesinternal.ReceiverNamed(recv) + return T != nil && + IsTypeNamed(T, pkgPath, typeName) && + slices.Contains(names, fn.Name()) + } + } + return false +} + +// ValidateFixes validates the set of fixes for a single diagnostic. +// Any error indicates a bug in the originating analyzer. +// +// It updates fixes so that fixes[*].End.IsValid(). +// +// It may be used as part of an analysis driver implementation. +func ValidateFixes(fset *token.FileSet, a *analysis.Analyzer, fixes []analysis.SuggestedFix) error { + fixMessages := make(map[string]bool) + for i := range fixes { + fix := &fixes[i] + if fixMessages[fix.Message] { + return fmt.Errorf("analyzer %q suggests two fixes with same Message (%s)", a.Name, fix.Message) + } + fixMessages[fix.Message] = true + if err := validateFix(fset, fix); err != nil { + return fmt.Errorf("analyzer %q suggests invalid fix (%s): %v", a.Name, fix.Message, err) + } } - pkgname, ok := obj.(*types.PkgName) - return pkgname, ok + return nil +} + +// validateFix validates a single fix. +// Any error indicates a bug in the originating analyzer. +// +// It updates fix so that fix.End.IsValid(). +func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error { + + // Stably sort edits by Pos. This ordering puts insertions + // (end = start) before deletions (end > start) at the same + // point, but uses a stable sort to preserve the order of + // multiple insertions at the same point. + slices.SortStableFunc(fix.TextEdits, func(x, y analysis.TextEdit) int { + if sign := cmp.Compare(x.Pos, y.Pos); sign != 0 { + return sign + } + return cmp.Compare(x.End, y.End) + }) + + var prev *analysis.TextEdit + for i := range fix.TextEdits { + edit := &fix.TextEdits[i] + + // Validate edit individually. + start := edit.Pos + file := fset.File(start) + if file == nil { + return fmt.Errorf("missing file info for pos (%v)", edit.Pos) + } + if end := edit.End; end.IsValid() { + if end < start { + return fmt.Errorf("pos (%v) > end (%v)", edit.Pos, edit.End) + } + endFile := fset.File(end) + if endFile == nil { + return fmt.Errorf("malformed end position %v", end) + } + if endFile != file { + return fmt.Errorf("edit spans files %v and %v", file.Name(), endFile.Name()) + } + } else { + edit.End = start // update the SuggestedFix + } + if eof := token.Pos(file.Base() + file.Size()); edit.End > eof { + return fmt.Errorf("end is (%v) beyond end of file (%v)", edit.End, eof) + } + + // Validate the sequence of edits: + // properly ordered, no overlapping deletions + if prev != nil && edit.Pos < prev.End { + xpos := fset.Position(prev.Pos) + xend := fset.Position(prev.End) + ypos := fset.Position(edit.Pos) + yend := fset.Position(edit.End) + return fmt.Errorf("overlapping edits to %s (%d:%d-%d:%d and %d:%d-%d:%d)", + xpos.Filename, + xpos.Line, xpos.Column, + xend.Line, xend.Column, + ypos.Line, ypos.Column, + yend.Line, yend.Column, + ) + } + prev = edit + } + + return nil } diff --git a/vendor/golang.org/x/tools/internal/astutil/edge/edge.go b/vendor/golang.org/x/tools/internal/astutil/edge/edge.go new file mode 100644 index 0000000000..4f6ccfd6e5 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/astutil/edge/edge.go @@ -0,0 +1,295 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package edge defines identifiers for each field of an ast.Node +// struct type that refers to another Node. +package edge + +import ( + "fmt" + "go/ast" + "reflect" +) + +// A Kind describes a field of an ast.Node struct. +type Kind uint8 + +// String returns a description of the edge kind. +func (k Kind) String() string { + if k == Invalid { + return "" + } + info := fieldInfos[k] + return fmt.Sprintf("%v.%s", info.nodeType.Elem().Name(), info.name) +} + +// NodeType returns the pointer-to-struct type of the ast.Node implementation. +func (k Kind) NodeType() reflect.Type { return fieldInfos[k].nodeType } + +// FieldName returns the name of the field. +func (k Kind) FieldName() string { return fieldInfos[k].name } + +// FieldType returns the declared type of the field. +func (k Kind) FieldType() reflect.Type { return fieldInfos[k].fieldType } + +// Get returns the direct child of n identified by (k, idx). +// n's type must match k.NodeType(). +// idx must be a valid slice index, or -1 for a non-slice. +func (k Kind) Get(n ast.Node, idx int) ast.Node { + if k.NodeType() != reflect.TypeOf(n) { + panic(fmt.Sprintf("%v.Get(%T): invalid node type", k, n)) + } + v := reflect.ValueOf(n).Elem().Field(fieldInfos[k].index) + if idx != -1 { + v = v.Index(idx) // asserts valid index + } else { + // (The type assertion below asserts that v is not a slice.) + } + return v.Interface().(ast.Node) // may be nil +} + +const ( + Invalid Kind = iota // for nodes at the root of the traversal + + // Kinds are sorted alphabetically. + // Numbering is not stable. + // Each is named Type_Field, where Type is the + // ast.Node struct type and Field is the name of the field + + ArrayType_Elt + ArrayType_Len + AssignStmt_Lhs + AssignStmt_Rhs + BinaryExpr_X + BinaryExpr_Y + BlockStmt_List + BranchStmt_Label + CallExpr_Args + CallExpr_Fun + CaseClause_Body + CaseClause_List + ChanType_Value + CommClause_Body + CommClause_Comm + CommentGroup_List + CompositeLit_Elts + CompositeLit_Type + DeclStmt_Decl + DeferStmt_Call + Ellipsis_Elt + ExprStmt_X + FieldList_List + Field_Comment + Field_Doc + Field_Names + Field_Tag + Field_Type + File_Decls + File_Doc + File_Name + ForStmt_Body + ForStmt_Cond + ForStmt_Init + ForStmt_Post + FuncDecl_Body + FuncDecl_Doc + FuncDecl_Name + FuncDecl_Recv + FuncDecl_Type + FuncLit_Body + FuncLit_Type + FuncType_Params + FuncType_Results + FuncType_TypeParams + GenDecl_Doc + GenDecl_Specs + GoStmt_Call + IfStmt_Body + IfStmt_Cond + IfStmt_Else + IfStmt_Init + ImportSpec_Comment + ImportSpec_Doc + ImportSpec_Name + ImportSpec_Path + IncDecStmt_X + IndexExpr_Index + IndexExpr_X + IndexListExpr_Indices + IndexListExpr_X + InterfaceType_Methods + KeyValueExpr_Key + KeyValueExpr_Value + LabeledStmt_Label + LabeledStmt_Stmt + MapType_Key + MapType_Value + ParenExpr_X + RangeStmt_Body + RangeStmt_Key + RangeStmt_Value + RangeStmt_X + ReturnStmt_Results + SelectStmt_Body + SelectorExpr_Sel + SelectorExpr_X + SendStmt_Chan + SendStmt_Value + SliceExpr_High + SliceExpr_Low + SliceExpr_Max + SliceExpr_X + StarExpr_X + StructType_Fields + SwitchStmt_Body + SwitchStmt_Init + SwitchStmt_Tag + TypeAssertExpr_Type + TypeAssertExpr_X + TypeSpec_Comment + TypeSpec_Doc + TypeSpec_Name + TypeSpec_Type + TypeSpec_TypeParams + TypeSwitchStmt_Assign + TypeSwitchStmt_Body + TypeSwitchStmt_Init + UnaryExpr_X + ValueSpec_Comment + ValueSpec_Doc + ValueSpec_Names + ValueSpec_Type + ValueSpec_Values + + maxKind +) + +// Assert that the encoding fits in 7 bits, +// as the inspector relies on this. +// (We are currently at 104.) +var _ = [1 << 7]struct{}{}[maxKind] + +type fieldInfo struct { + nodeType reflect.Type // pointer-to-struct type of ast.Node implementation + name string + index int + fieldType reflect.Type +} + +func info[N ast.Node](fieldName string) fieldInfo { + nodePtrType := reflect.TypeFor[N]() + f, ok := nodePtrType.Elem().FieldByName(fieldName) + if !ok { + panic(fieldName) + } + return fieldInfo{nodePtrType, fieldName, f.Index[0], f.Type} +} + +var fieldInfos = [...]fieldInfo{ + Invalid: {}, + ArrayType_Elt: info[*ast.ArrayType]("Elt"), + ArrayType_Len: info[*ast.ArrayType]("Len"), + AssignStmt_Lhs: info[*ast.AssignStmt]("Lhs"), + AssignStmt_Rhs: info[*ast.AssignStmt]("Rhs"), + BinaryExpr_X: info[*ast.BinaryExpr]("X"), + BinaryExpr_Y: info[*ast.BinaryExpr]("Y"), + BlockStmt_List: info[*ast.BlockStmt]("List"), + BranchStmt_Label: info[*ast.BranchStmt]("Label"), + CallExpr_Args: info[*ast.CallExpr]("Args"), + CallExpr_Fun: info[*ast.CallExpr]("Fun"), + CaseClause_Body: info[*ast.CaseClause]("Body"), + CaseClause_List: info[*ast.CaseClause]("List"), + ChanType_Value: info[*ast.ChanType]("Value"), + CommClause_Body: info[*ast.CommClause]("Body"), + CommClause_Comm: info[*ast.CommClause]("Comm"), + CommentGroup_List: info[*ast.CommentGroup]("List"), + CompositeLit_Elts: info[*ast.CompositeLit]("Elts"), + CompositeLit_Type: info[*ast.CompositeLit]("Type"), + DeclStmt_Decl: info[*ast.DeclStmt]("Decl"), + DeferStmt_Call: info[*ast.DeferStmt]("Call"), + Ellipsis_Elt: info[*ast.Ellipsis]("Elt"), + ExprStmt_X: info[*ast.ExprStmt]("X"), + FieldList_List: info[*ast.FieldList]("List"), + Field_Comment: info[*ast.Field]("Comment"), + Field_Doc: info[*ast.Field]("Doc"), + Field_Names: info[*ast.Field]("Names"), + Field_Tag: info[*ast.Field]("Tag"), + Field_Type: info[*ast.Field]("Type"), + File_Decls: info[*ast.File]("Decls"), + File_Doc: info[*ast.File]("Doc"), + File_Name: info[*ast.File]("Name"), + ForStmt_Body: info[*ast.ForStmt]("Body"), + ForStmt_Cond: info[*ast.ForStmt]("Cond"), + ForStmt_Init: info[*ast.ForStmt]("Init"), + ForStmt_Post: info[*ast.ForStmt]("Post"), + FuncDecl_Body: info[*ast.FuncDecl]("Body"), + FuncDecl_Doc: info[*ast.FuncDecl]("Doc"), + FuncDecl_Name: info[*ast.FuncDecl]("Name"), + FuncDecl_Recv: info[*ast.FuncDecl]("Recv"), + FuncDecl_Type: info[*ast.FuncDecl]("Type"), + FuncLit_Body: info[*ast.FuncLit]("Body"), + FuncLit_Type: info[*ast.FuncLit]("Type"), + FuncType_Params: info[*ast.FuncType]("Params"), + FuncType_Results: info[*ast.FuncType]("Results"), + FuncType_TypeParams: info[*ast.FuncType]("TypeParams"), + GenDecl_Doc: info[*ast.GenDecl]("Doc"), + GenDecl_Specs: info[*ast.GenDecl]("Specs"), + GoStmt_Call: info[*ast.GoStmt]("Call"), + IfStmt_Body: info[*ast.IfStmt]("Body"), + IfStmt_Cond: info[*ast.IfStmt]("Cond"), + IfStmt_Else: info[*ast.IfStmt]("Else"), + IfStmt_Init: info[*ast.IfStmt]("Init"), + ImportSpec_Comment: info[*ast.ImportSpec]("Comment"), + ImportSpec_Doc: info[*ast.ImportSpec]("Doc"), + ImportSpec_Name: info[*ast.ImportSpec]("Name"), + ImportSpec_Path: info[*ast.ImportSpec]("Path"), + IncDecStmt_X: info[*ast.IncDecStmt]("X"), + IndexExpr_Index: info[*ast.IndexExpr]("Index"), + IndexExpr_X: info[*ast.IndexExpr]("X"), + IndexListExpr_Indices: info[*ast.IndexListExpr]("Indices"), + IndexListExpr_X: info[*ast.IndexListExpr]("X"), + InterfaceType_Methods: info[*ast.InterfaceType]("Methods"), + KeyValueExpr_Key: info[*ast.KeyValueExpr]("Key"), + KeyValueExpr_Value: info[*ast.KeyValueExpr]("Value"), + LabeledStmt_Label: info[*ast.LabeledStmt]("Label"), + LabeledStmt_Stmt: info[*ast.LabeledStmt]("Stmt"), + MapType_Key: info[*ast.MapType]("Key"), + MapType_Value: info[*ast.MapType]("Value"), + ParenExpr_X: info[*ast.ParenExpr]("X"), + RangeStmt_Body: info[*ast.RangeStmt]("Body"), + RangeStmt_Key: info[*ast.RangeStmt]("Key"), + RangeStmt_Value: info[*ast.RangeStmt]("Value"), + RangeStmt_X: info[*ast.RangeStmt]("X"), + ReturnStmt_Results: info[*ast.ReturnStmt]("Results"), + SelectStmt_Body: info[*ast.SelectStmt]("Body"), + SelectorExpr_Sel: info[*ast.SelectorExpr]("Sel"), + SelectorExpr_X: info[*ast.SelectorExpr]("X"), + SendStmt_Chan: info[*ast.SendStmt]("Chan"), + SendStmt_Value: info[*ast.SendStmt]("Value"), + SliceExpr_High: info[*ast.SliceExpr]("High"), + SliceExpr_Low: info[*ast.SliceExpr]("Low"), + SliceExpr_Max: info[*ast.SliceExpr]("Max"), + SliceExpr_X: info[*ast.SliceExpr]("X"), + StarExpr_X: info[*ast.StarExpr]("X"), + StructType_Fields: info[*ast.StructType]("Fields"), + SwitchStmt_Body: info[*ast.SwitchStmt]("Body"), + SwitchStmt_Init: info[*ast.SwitchStmt]("Init"), + SwitchStmt_Tag: info[*ast.SwitchStmt]("Tag"), + TypeAssertExpr_Type: info[*ast.TypeAssertExpr]("Type"), + TypeAssertExpr_X: info[*ast.TypeAssertExpr]("X"), + TypeSpec_Comment: info[*ast.TypeSpec]("Comment"), + TypeSpec_Doc: info[*ast.TypeSpec]("Doc"), + TypeSpec_Name: info[*ast.TypeSpec]("Name"), + TypeSpec_Type: info[*ast.TypeSpec]("Type"), + TypeSpec_TypeParams: info[*ast.TypeSpec]("TypeParams"), + TypeSwitchStmt_Assign: info[*ast.TypeSwitchStmt]("Assign"), + TypeSwitchStmt_Body: info[*ast.TypeSwitchStmt]("Body"), + TypeSwitchStmt_Init: info[*ast.TypeSwitchStmt]("Init"), + UnaryExpr_X: info[*ast.UnaryExpr]("X"), + ValueSpec_Comment: info[*ast.ValueSpec]("Comment"), + ValueSpec_Doc: info[*ast.ValueSpec]("Doc"), + ValueSpec_Names: info[*ast.ValueSpec]("Names"), + ValueSpec_Type: info[*ast.ValueSpec]("Type"), + ValueSpec_Values: info[*ast.ValueSpec]("Values"), +} diff --git a/vendor/golang.org/x/tools/internal/diff/lcs/old.go b/vendor/golang.org/x/tools/internal/diff/lcs/old.go index 4353da15ba..7c74b47bb1 100644 --- a/vendor/golang.org/x/tools/internal/diff/lcs/old.go +++ b/vendor/golang.org/x/tools/internal/diff/lcs/old.go @@ -199,6 +199,7 @@ func (e *editGraph) bdone(D, k int) (bool, lcs) { } // run the backward algorithm, until success or up to the limit on D. +// (used only by tests) func backward(e *editGraph) lcs { e.setBackward(0, 0, e.ux) if ok, ans := e.bdone(0, 0); ok { diff --git a/vendor/golang.org/x/tools/internal/diff/merge.go b/vendor/golang.org/x/tools/internal/diff/merge.go new file mode 100644 index 0000000000..eeae98adf7 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/diff/merge.go @@ -0,0 +1,81 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package diff + +import ( + "slices" +) + +// Merge merges two valid, ordered lists of edits. +// It returns zero if there was a conflict. +// +// If corresponding edits in x and y are identical, +// they are coalesced in the result. +// +// If x and y both provide different insertions at the same point, +// the insertions from x will be first in the result. +// +// TODO(adonovan): this algorithm could be improved, for example by +// working harder to coalesce non-identical edits that share a common +// deletion or common prefix of insertion (see the tests). +// Survey the academic literature for insights. +func Merge(x, y []Edit) ([]Edit, bool) { + // Make a defensive (premature) copy of the arrays. + x = slices.Clone(x) + y = slices.Clone(y) + + var merged []Edit + add := func(edit Edit) { + merged = append(merged, edit) + } + var xi, yi int + for xi < len(x) && yi < len(y) { + px := &x[xi] + py := &y[yi] + + if *px == *py { + // x and y are identical: coalesce. + add(*px) + xi++ + yi++ + + } else if px.End <= py.Start { + // x is entirely before y, + // or an insertion at start of y. + add(*px) + xi++ + + } else if py.End <= px.Start { + // y is entirely before x, + // or an insertion at start of x. + add(*py) + yi++ + + } else if px.Start < py.Start { + // x is partly before y: + // split it into a deletion and an edit. + add(Edit{px.Start, py.Start, ""}) + px.Start = py.Start + + } else if py.Start < px.Start { + // y is partly before x: + // split it into a deletion and an edit. + add(Edit{py.Start, px.Start, ""}) + py.Start = px.Start + + } else { + // x and y are unequal non-insertions + // at the same point: conflict. + return nil, false + } + } + for ; xi < len(x); xi++ { + add(x[xi]) + } + for ; yi < len(y); yi++ { + add(y[yi]) + } + return merged, true +} diff --git a/vendor/golang.org/x/tools/internal/facts/imports.go b/vendor/golang.org/x/tools/internal/facts/imports.go index 9f706cd954..ed5ec5fa13 100644 --- a/vendor/golang.org/x/tools/internal/facts/imports.go +++ b/vendor/golang.org/x/tools/internal/facts/imports.go @@ -8,6 +8,7 @@ import ( "go/types" "golang.org/x/tools/internal/aliases" + "golang.org/x/tools/internal/typesinternal" ) // importMap computes the import map for a package by traversing the @@ -47,32 +48,41 @@ func importMap(imports []*types.Package) map[string]*types.Package { addType = func(T types.Type) { switch T := T.(type) { - case *aliases.Alias: - addType(aliases.Unalias(T)) case *types.Basic: // nop - case *types.Named: + case typesinternal.NamedOrAlias: // *types.{Named,Alias} + // Add the type arguments if this is an instance. + if targs := typesinternal.TypeArgs(T); targs.Len() > 0 { + for i := 0; i < targs.Len(); i++ { + addType(targs.At(i)) + } + } + // Remove infinite expansions of *types.Named by always looking at the origin. // Some named types with type parameters [that will not type check] have // infinite expansions: // type N[T any] struct { F *N[N[T]] } // importMap() is called on such types when Analyzer.RunDespiteErrors is true. - T = T.Origin() + T = typesinternal.Origin(T) if !typs[T] { typs[T] = true + + // common aspects addObj(T.Obj()) - addType(T.Underlying()) - for i := 0; i < T.NumMethods(); i++ { - addObj(T.Method(i)) - } - if tparams := T.TypeParams(); tparams != nil { + if tparams := typesinternal.TypeParams(T); tparams.Len() > 0 { for i := 0; i < tparams.Len(); i++ { addType(tparams.At(i)) } } - if targs := T.TypeArgs(); targs != nil { - for i := 0; i < targs.Len(); i++ { - addType(targs.At(i)) + + // variant aspects + switch T := T.(type) { + case *types.Alias: + addType(aliases.Rhs(T)) + case *types.Named: + addType(T.Underlying()) + for i := 0; i < T.NumMethods(); i++ { + addObj(T.Method(i)) } } } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/bimport.go b/vendor/golang.org/x/tools/internal/gcimporter/bimport.go index d98b0db2a9..d79a605ed1 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/bimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/bimport.go @@ -87,64 +87,3 @@ func chanDir(d int) types.ChanDir { return 0 } } - -var predeclOnce sync.Once -var predecl []types.Type // initialized lazily - -func predeclared() []types.Type { - predeclOnce.Do(func() { - // initialize lazily to be sure that all - // elements have been initialized before - predecl = []types.Type{ // basic types - types.Typ[types.Bool], - types.Typ[types.Int], - types.Typ[types.Int8], - types.Typ[types.Int16], - types.Typ[types.Int32], - types.Typ[types.Int64], - types.Typ[types.Uint], - types.Typ[types.Uint8], - types.Typ[types.Uint16], - types.Typ[types.Uint32], - types.Typ[types.Uint64], - types.Typ[types.Uintptr], - types.Typ[types.Float32], - types.Typ[types.Float64], - types.Typ[types.Complex64], - types.Typ[types.Complex128], - types.Typ[types.String], - - // basic type aliases - types.Universe.Lookup("byte").Type(), - types.Universe.Lookup("rune").Type(), - - // error - types.Universe.Lookup("error").Type(), - - // untyped types - types.Typ[types.UntypedBool], - types.Typ[types.UntypedInt], - types.Typ[types.UntypedRune], - types.Typ[types.UntypedFloat], - types.Typ[types.UntypedComplex], - types.Typ[types.UntypedString], - types.Typ[types.UntypedNil], - - // package unsafe - types.Typ[types.UnsafePointer], - - // invalid type - types.Typ[types.Invalid], // only appears in packages with errors - - // used internally by gc; never used by this package or in .a files - anyType{}, - } - predecl = append(predecl, additionalPredeclared()...) - }) - return predecl -} - -type anyType struct{} - -func (t anyType) Underlying() types.Type { return t } -func (t anyType) String() string { return "any" } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go b/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go index f6437feb1c..5662a311da 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go @@ -2,49 +2,183 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go. - -// This file implements FindExportData. +// This file should be kept in sync with $GOROOT/src/internal/exportdata/exportdata.go. +// This file also additionally implements FindExportData for gcexportdata.NewReader. package gcimporter import ( "bufio" + "bytes" + "errors" "fmt" + "go/build" "io" - "strconv" + "os" + "os/exec" + "path/filepath" "strings" + "sync" ) -func readGopackHeader(r *bufio.Reader) (name string, size int64, err error) { - // See $GOROOT/include/ar.h. - hdr := make([]byte, 16+12+6+6+8+10+2) - _, err = io.ReadFull(r, hdr) +// FindExportData positions the reader r at the beginning of the +// export data section of an underlying cmd/compile created archive +// file by reading from it. The reader must be positioned at the +// start of the file before calling this function. +// This returns the length of the export data in bytes. +// +// This function is needed by [gcexportdata.Read], which must +// accept inputs produced by the last two releases of cmd/compile, +// plus tip. +func FindExportData(r *bufio.Reader) (size int64, err error) { + arsize, err := FindPackageDefinition(r) + if err != nil { + return + } + size = int64(arsize) + + objapi, headers, err := ReadObjectHeaders(r) if err != nil { return } - // leave for debugging - if false { - fmt.Printf("header: %s", hdr) + size -= int64(len(objapi)) + for _, h := range headers { + size -= int64(len(h)) + } + + // Check for the binary export data section header "$$B\n". + // TODO(taking): Unify with ReadExportDataHeader so that it stops at the 'u' instead of reading + line, err := r.ReadSlice('\n') + if err != nil { + return + } + hdr := string(line) + if hdr != "$$B\n" { + err = fmt.Errorf("unknown export data header: %q", hdr) + return } - s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) - length, err := strconv.Atoi(s) - size = int64(length) - if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { - err = fmt.Errorf("invalid archive header") + size -= int64(len(hdr)) + + // For files with a binary export data header "$$B\n", + // these are always terminated by an end-of-section marker "\n$$\n". + // So the last bytes must always be this constant. + // + // The end-of-section marker is not a part of the export data itself. + // Do not include these in size. + // + // It would be nice to have sanity check that the final bytes after + // the export data are indeed the end-of-section marker. The split + // of gcexportdata.NewReader and gcexportdata.Read make checking this + // ugly so gcimporter gives up enforcing this. The compiler and go/types + // importer do enforce this, which seems good enough. + const endofsection = "\n$$\n" + size -= int64(len(endofsection)) + + if size < 0 { + err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", arsize, size) return } - name = strings.TrimSpace(string(hdr[:16])) + return } -// FindExportData positions the reader r at the beginning of the -// export data section of an underlying GC-created object/archive -// file by reading from it. The reader must be positioned at the -// start of the file before calling this function. The hdr result -// is the string before the export data, either "$$" or "$$B". -// The size result is the length of the export data in bytes, or -1 if not known. -func FindExportData(r *bufio.Reader) (hdr string, size int64, err error) { +// ReadUnified reads the contents of the unified export data from a reader r +// that contains the contents of a GC-created archive file. +// +// On success, the reader will be positioned after the end-of-section marker "\n$$\n". +// +// Supported GC-created archive files have 4 layers of nesting: +// - An archive file containing a package definition file. +// - The package definition file contains headers followed by a data section. +// Headers are lines (≤ 4kb) that do not start with "$$". +// - The data section starts with "$$B\n" followed by export data followed +// by an end of section marker "\n$$\n". (The section start "$$\n" is no +// longer supported.) +// - The export data starts with a format byte ('u') followed by the in +// the given format. (See ReadExportDataHeader for older formats.) +// +// Putting this together, the bytes in a GC-created archive files are expected +// to look like the following. +// See cmd/internal/archive for more details on ar file headers. +// +// | \n | ar file signature +// | __.PKGDEF...size...\n | ar header for __.PKGDEF including size. +// | go object <...>\n | objabi header +// | \n | other headers such as build id +// | $$B\n | binary format marker +// | u\n | unified export +// | $$\n | end-of-section marker +// | [optional padding] | padding byte (0x0A) if size is odd +// | [ar file header] | other ar files +// | [ar file data] | +func ReadUnified(r *bufio.Reader) (data []byte, err error) { + // We historically guaranteed headers at the default buffer size (4096) work. + // This ensures we can use ReadSlice throughout. + const minBufferSize = 4096 + r = bufio.NewReaderSize(r, minBufferSize) + + size, err := FindPackageDefinition(r) + if err != nil { + return + } + n := size + + objapi, headers, err := ReadObjectHeaders(r) + if err != nil { + return + } + n -= len(objapi) + for _, h := range headers { + n -= len(h) + } + + hdrlen, err := ReadExportDataHeader(r) + if err != nil { + return + } + n -= hdrlen + + // size also includes the end of section marker. Remove that many bytes from the end. + const marker = "\n$$\n" + n -= len(marker) + + if n < 0 { + err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", size, n) + return + } + + // Read n bytes from buf. + data = make([]byte, n) + _, err = io.ReadFull(r, data) + if err != nil { + return + } + + // Check for marker at the end. + var suffix [len(marker)]byte + _, err = io.ReadFull(r, suffix[:]) + if err != nil { + return + } + if s := string(suffix[:]); s != marker { + err = fmt.Errorf("read %q instead of end-of-section marker (%q)", s, marker) + return + } + + return +} + +// FindPackageDefinition positions the reader r at the beginning of a package +// definition file ("__.PKGDEF") within a GC-created archive by reading +// from it, and returns the size of the package definition file in the archive. +// +// The reader must be positioned at the start of the archive file before calling +// this function, and "__.PKGDEF" is assumed to be the first file in the archive. +// +// See cmd/internal/archive for details on the archive format. +func FindPackageDefinition(r *bufio.Reader) (size int, err error) { + // Uses ReadSlice to limit risk of malformed inputs. + // Read first line to make sure this is an object file. line, err := r.ReadSlice('\n') if err != nil { @@ -52,48 +186,236 @@ func FindExportData(r *bufio.Reader) (hdr string, size int64, err error) { return } - if string(line) == "!\n" { - // Archive file. Scan to __.PKGDEF. - var name string - if name, size, err = readGopackHeader(r); err != nil { - return - } + // Is the first line an archive file signature? + if string(line) != "!\n" { + err = fmt.Errorf("not the start of an archive file (%q)", line) + return + } + + // package export block should be first + size = readArchiveHeader(r, "__.PKGDEF") + if size <= 0 { + err = fmt.Errorf("not a package file") + return + } + + return +} - // First entry should be __.PKGDEF. - if name != "__.PKGDEF" { - err = fmt.Errorf("go archive is missing __.PKGDEF") +// ReadObjectHeaders reads object headers from the reader. Object headers are +// lines that do not start with an end-of-section marker "$$". The first header +// is the objabi header. On success, the reader will be positioned at the beginning +// of the end-of-section marker. +// +// It returns an error if any header does not fit in r.Size() bytes. +func ReadObjectHeaders(r *bufio.Reader) (objapi string, headers []string, err error) { + // line is a temporary buffer for headers. + // Use bounded reads (ReadSlice, Peek) to limit risk of malformed inputs. + var line []byte + + // objapi header should be the first line + if line, err = r.ReadSlice('\n'); err != nil { + err = fmt.Errorf("can't find export data (%v)", err) + return + } + objapi = string(line) + + // objapi header begins with "go object ". + if !strings.HasPrefix(objapi, "go object ") { + err = fmt.Errorf("not a go object file: %s", objapi) + return + } + + // process remaining object header lines + for { + // check for an end of section marker "$$" + line, err = r.Peek(2) + if err != nil { return } + if string(line) == "$$" { + return // stop + } - // Read first line of __.PKGDEF data, so that line - // is once again the first line of the input. - if line, err = r.ReadSlice('\n'); err != nil { - err = fmt.Errorf("can't find export data (%v)", err) + // read next header + line, err = r.ReadSlice('\n') + if err != nil { return } - size -= int64(len(line)) + headers = append(headers, string(line)) } +} - // Now at __.PKGDEF in archive or still at beginning of file. - // Either way, line should begin with "go object ". - if !strings.HasPrefix(string(line), "go object ") { - err = fmt.Errorf("not a Go object file") +// ReadExportDataHeader reads the export data header and format from r. +// It returns the number of bytes read, or an error if the format is no longer +// supported or it failed to read. +// +// The only currently supported format is binary export data in the +// unified export format. +func ReadExportDataHeader(r *bufio.Reader) (n int, err error) { + // Read export data header. + line, err := r.ReadSlice('\n') + if err != nil { return } - // Skip over object header to export data. - // Begins after first line starting with $$. - for line[0] != '$' { - if line, err = r.ReadSlice('\n'); err != nil { - err = fmt.Errorf("can't find export data (%v)", err) + hdr := string(line) + switch hdr { + case "$$\n": + err = fmt.Errorf("old textual export format no longer supported (recompile package)") + return + + case "$$B\n": + var format byte + format, err = r.ReadByte() + if err != nil { return } - size -= int64(len(line)) - } - hdr = string(line) - if size < 0 { - size = -1 + // The unified export format starts with a 'u'. + switch format { + case 'u': + default: + // Older no longer supported export formats include: + // indexed export format which started with an 'i'; and + // the older binary export format which started with a 'c', + // 'd', or 'v' (from "version"). + err = fmt.Errorf("binary export format %q is no longer supported (recompile package)", format) + return + } + + default: + err = fmt.Errorf("unknown export data header: %q", hdr) + return } + n = len(hdr) + 1 // + 1 is for 'u' return } + +// FindPkg returns the filename and unique package id for an import +// path based on package information provided by build.Import (using +// the build.Default build.Context). A relative srcDir is interpreted +// relative to the current working directory. +// +// FindPkg is only used in tests within x/tools. +func FindPkg(path, srcDir string) (filename, id string, err error) { + // TODO(taking): Move internal/exportdata.FindPkg into its own file, + // and then this copy into a _test package. + if path == "" { + return "", "", errors.New("path is empty") + } + + var noext string + switch { + default: + // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" + // Don't require the source files to be present. + if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 + srcDir = abs + } + var bp *build.Package + bp, err = build.Import(path, srcDir, build.FindOnly|build.AllowBinary) + if bp.PkgObj == "" { + if bp.Goroot && bp.Dir != "" { + filename, err = lookupGorootExport(bp.Dir) + if err == nil { + _, err = os.Stat(filename) + } + if err == nil { + return filename, bp.ImportPath, nil + } + } + goto notfound + } else { + noext = strings.TrimSuffix(bp.PkgObj, ".a") + } + id = bp.ImportPath + + case build.IsLocalImport(path): + // "./x" -> "/this/directory/x.ext", "/this/directory/x" + noext = filepath.Join(srcDir, path) + id = noext + + case filepath.IsAbs(path): + // for completeness only - go/build.Import + // does not support absolute imports + // "/x" -> "/x.ext", "/x" + noext = path + id = path + } + + if false { // for debugging + if path != id { + fmt.Printf("%s -> %s\n", path, id) + } + } + + // try extensions + for _, ext := range pkgExts { + filename = noext + ext + f, statErr := os.Stat(filename) + if statErr == nil && !f.IsDir() { + return filename, id, nil + } + if err == nil { + err = statErr + } + } + +notfound: + if err == nil { + return "", path, fmt.Errorf("can't find import: %q", path) + } + return "", path, fmt.Errorf("can't find import: %q: %w", path, err) +} + +var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension + +var exportMap sync.Map // package dir → func() (string, error) + +// lookupGorootExport returns the location of the export data +// (normally found in the build cache, but located in GOROOT/pkg +// in prior Go releases) for the package located in pkgDir. +// +// (We use the package's directory instead of its import path +// mainly to simplify handling of the packages in src/vendor +// and cmd/vendor.) +// +// lookupGorootExport is only used in tests within x/tools. +func lookupGorootExport(pkgDir string) (string, error) { + f, ok := exportMap.Load(pkgDir) + if !ok { + var ( + listOnce sync.Once + exportPath string + err error + ) + f, _ = exportMap.LoadOrStore(pkgDir, func() (string, error) { + listOnce.Do(func() { + cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir) + cmd.Dir = build.Default.GOROOT + cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT) + var output []byte + output, err = cmd.Output() + if err != nil { + if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { + err = errors.New(string(ee.Stderr)) + } + return + } + + exports := strings.Split(string(bytes.TrimSpace(output)), "\n") + if len(exports) != 1 { + err = fmt.Errorf("go list reported %d exports; expected 1", len(exports)) + return + } + + exportPath = exports[0] + }) + + return exportPath, err + }) + } + + return f.(func() (string, error))() +} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go index 39df91124a..3dbd21d1b9 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go @@ -23,17 +23,11 @@ package gcimporter // import "golang.org/x/tools/internal/gcimporter" import ( "bufio" - "bytes" "fmt" - "go/build" "go/token" "go/types" "io" "os" - "os/exec" - "path/filepath" - "strings" - "sync" ) const ( @@ -45,125 +39,14 @@ const ( trace = false ) -var exportMap sync.Map // package dir → func() (string, bool) - -// lookupGorootExport returns the location of the export data -// (normally found in the build cache, but located in GOROOT/pkg -// in prior Go releases) for the package located in pkgDir. -// -// (We use the package's directory instead of its import path -// mainly to simplify handling of the packages in src/vendor -// and cmd/vendor.) -func lookupGorootExport(pkgDir string) (string, bool) { - f, ok := exportMap.Load(pkgDir) - if !ok { - var ( - listOnce sync.Once - exportPath string - ) - f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) { - listOnce.Do(func() { - cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir) - cmd.Dir = build.Default.GOROOT - var output []byte - output, err := cmd.Output() - if err != nil { - return - } - - exports := strings.Split(string(bytes.TrimSpace(output)), "\n") - if len(exports) != 1 { - return - } - - exportPath = exports[0] - }) - - return exportPath, exportPath != "" - }) - } - - return f.(func() (string, bool))() -} - -var pkgExts = [...]string{".a", ".o"} - -// FindPkg returns the filename and unique package id for an import -// path based on package information provided by build.Import (using -// the build.Default build.Context). A relative srcDir is interpreted -// relative to the current working directory. -// If no file was found, an empty filename is returned. -func FindPkg(path, srcDir string) (filename, id string) { - if path == "" { - return - } - - var noext string - switch { - default: - // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" - // Don't require the source files to be present. - if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 - srcDir = abs - } - bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) - if bp.PkgObj == "" { - var ok bool - if bp.Goroot && bp.Dir != "" { - filename, ok = lookupGorootExport(bp.Dir) - } - if !ok { - id = path // make sure we have an id to print in error message - return - } - } else { - noext = strings.TrimSuffix(bp.PkgObj, ".a") - id = bp.ImportPath - } - - case build.IsLocalImport(path): - // "./x" -> "/this/directory/x.ext", "/this/directory/x" - noext = filepath.Join(srcDir, path) - id = noext - - case filepath.IsAbs(path): - // for completeness only - go/build.Import - // does not support absolute imports - // "/x" -> "/x.ext", "/x" - noext = path - id = path - } - - if false { // for debugging - if path != id { - fmt.Printf("%s -> %s\n", path, id) - } - } - - if filename != "" { - if f, err := os.Stat(filename); err == nil && !f.IsDir() { - return - } - } - - // try extensions - for _, ext := range pkgExts { - filename = noext + ext - if f, err := os.Stat(filename); err == nil && !f.IsDir() { - return - } - } - - filename = "" // not found - return -} - // Import imports a gc-generated package given its import path and srcDir, adds // the corresponding package object to the packages map, and returns the object. // The packages map must contain all packages already imported. -func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { +// +// Import is only used in tests. +func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { var rc io.ReadCloser - var filename, id string + var id string if lookup != nil { // With custom lookup specified, assume that caller has // converted path to a canonical import path for use in the map. @@ -182,12 +65,13 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func } rc = f } else { - filename, id = FindPkg(path, srcDir) + var filename string + filename, id, err = FindPkg(path, srcDir) if filename == "" { if path == "unsafe" { return types.Unsafe, nil } - return nil, fmt.Errorf("can't find import: %q", id) + return nil, err } // no need to re-import if the package was imported completely before @@ -210,57 +94,15 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func } defer rc.Close() - var hdr string - var size int64 buf := bufio.NewReader(rc) - if hdr, size, err = FindExportData(buf); err != nil { + data, err := ReadUnified(buf) + if err != nil { + err = fmt.Errorf("import %q: %v", path, err) return } - switch hdr { - case "$$B\n": - var data []byte - data, err = io.ReadAll(buf) - if err != nil { - break - } - - // TODO(gri): allow clients of go/importer to provide a FileSet. - // Or, define a new standard go/types/gcexportdata package. - fset := token.NewFileSet() - - // Select appropriate importer. - if len(data) > 0 { - switch data[0] { - case 'v', 'c', 'd': // binary, till go1.10 - return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0]) - - case 'i': // indexed, till go1.19 - _, pkg, err := IImportData(fset, packages, data[1:], id) - return pkg, err - - case 'u': // unified, from go1.20 - _, pkg, err := UImportData(fset, packages, data[1:size], id) - return pkg, err - - default: - l := len(data) - if l > 10 { - l = 10 - } - return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), id) - } - } - - default: - err = fmt.Errorf("unknown export data header: %q", hdr) - } + // unified: emitted by cmd/compile since go1.20. + _, pkg, err = UImportData(fset, packages, data, id) return } - -type byPath []*types.Package - -func (a byPath) Len() int { return len(a) } -func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index deeb67f315..7dfc31a37d 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -2,9 +2,227 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Indexed binary package export. -// This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go; -// see that file for specification of the format. +// Indexed package export. +// +// The indexed export data format is an evolution of the previous +// binary export data format. Its chief contribution is introducing an +// index table, which allows efficient random access of individual +// declarations and inline function bodies. In turn, this allows +// avoiding unnecessary work for compilation units that import large +// packages. +// +// +// The top-level data format is structured as: +// +// Header struct { +// Tag byte // 'i' +// Version uvarint +// StringSize uvarint +// DataSize uvarint +// } +// +// Strings [StringSize]byte +// Data [DataSize]byte +// +// MainIndex []struct{ +// PkgPath stringOff +// PkgName stringOff +// PkgHeight uvarint +// +// Decls []struct{ +// Name stringOff +// Offset declOff +// } +// } +// +// Fingerprint [8]byte +// +// uvarint means a uint64 written out using uvarint encoding. +// +// []T means a uvarint followed by that many T objects. In other +// words: +// +// Len uvarint +// Elems [Len]T +// +// stringOff means a uvarint that indicates an offset within the +// Strings section. At that offset is another uvarint, followed by +// that many bytes, which form the string value. +// +// declOff means a uvarint that indicates an offset within the Data +// section where the associated declaration can be found. +// +// +// There are five kinds of declarations, distinguished by their first +// byte: +// +// type Var struct { +// Tag byte // 'V' +// Pos Pos +// Type typeOff +// } +// +// type Func struct { +// Tag byte // 'F' or 'G' +// Pos Pos +// TypeParams []typeOff // only present if Tag == 'G' +// Signature Signature +// } +// +// type Const struct { +// Tag byte // 'C' +// Pos Pos +// Value Value +// } +// +// type Type struct { +// Tag byte // 'T' or 'U' +// Pos Pos +// TypeParams []typeOff // only present if Tag == 'U' +// Underlying typeOff +// +// Methods []struct{ // omitted if Underlying is an interface type +// Pos Pos +// Name stringOff +// Recv Param +// Signature Signature +// } +// } +// +// type Alias struct { +// Tag byte // 'A' or 'B' +// Pos Pos +// TypeParams []typeOff // only present if Tag == 'B' +// Type typeOff +// } +// +// // "Automatic" declaration of each typeparam +// type TypeParam struct { +// Tag byte // 'P' +// Pos Pos +// Implicit bool +// Constraint typeOff +// } +// +// typeOff means a uvarint that either indicates a predeclared type, +// or an offset into the Data section. If the uvarint is less than +// predeclReserved, then it indicates the index into the predeclared +// types list (see predeclared in bexport.go for order). Otherwise, +// subtracting predeclReserved yields the offset of a type descriptor. +// +// Value means a type, kind, and type-specific value. See +// (*exportWriter).value for details. +// +// +// There are twelve kinds of type descriptors, distinguished by an itag: +// +// type DefinedType struct { +// Tag itag // definedType +// Name stringOff +// PkgPath stringOff +// } +// +// type PointerType struct { +// Tag itag // pointerType +// Elem typeOff +// } +// +// type SliceType struct { +// Tag itag // sliceType +// Elem typeOff +// } +// +// type ArrayType struct { +// Tag itag // arrayType +// Len uint64 +// Elem typeOff +// } +// +// type ChanType struct { +// Tag itag // chanType +// Dir uint64 // 1 RecvOnly; 2 SendOnly; 3 SendRecv +// Elem typeOff +// } +// +// type MapType struct { +// Tag itag // mapType +// Key typeOff +// Elem typeOff +// } +// +// type FuncType struct { +// Tag itag // signatureType +// PkgPath stringOff +// Signature Signature +// } +// +// type StructType struct { +// Tag itag // structType +// PkgPath stringOff +// Fields []struct { +// Pos Pos +// Name stringOff +// Type typeOff +// Embedded bool +// Note stringOff +// } +// } +// +// type InterfaceType struct { +// Tag itag // interfaceType +// PkgPath stringOff +// Embeddeds []struct { +// Pos Pos +// Type typeOff +// } +// Methods []struct { +// Pos Pos +// Name stringOff +// Signature Signature +// } +// } +// +// // Reference to a type param declaration +// type TypeParamType struct { +// Tag itag // typeParamType +// Name stringOff +// PkgPath stringOff +// } +// +// // Instantiation of a generic type (like List[T2] or List[int]) +// type InstanceType struct { +// Tag itag // instanceType +// Pos pos +// TypeArgs []typeOff +// BaseType typeOff +// } +// +// type UnionType struct { +// Tag itag // interfaceType +// Terms []struct { +// tilde bool +// Type typeOff +// } +// } +// +// +// +// type Signature struct { +// Params []Param +// Results []Param +// Variadic bool // omitted if Results is empty +// } +// +// type Param struct { +// Pos Pos +// Name stringOff +// Type typOff +// } +// +// +// Pos encodes a file:line:column triple, incorporating a simple delta +// encoding scheme within a data object. See exportWriter.pos for +// details. package gcimporter @@ -24,11 +242,30 @@ import ( "golang.org/x/tools/go/types/objectpath" "golang.org/x/tools/internal/aliases" - "golang.org/x/tools/internal/tokeninternal" ) // IExportShallow encodes "shallow" export data for the specified package. // +// For types, we use "shallow" export data. Historically, the Go +// compiler always produced a summary of the types for a given package +// that included types from other packages that it indirectly +// referenced: "deep" export data. This had the advantage that the +// compiler (and analogous tools such as gopls) need only load one +// file per direct import. However, it meant that the files tended to +// get larger based on the level of the package in the import +// graph. For example, higher-level packages in the kubernetes module +// have over 1MB of "deep" export data, even when they have almost no +// content of their own, merely because they mention a major type that +// references many others. In pathological cases the export data was +// 300x larger than the source for a package due to this quadratic +// growth. +// +// "Shallow" export data means that the serialized types describe only +// a single package. If those types mention types from other packages, +// the type checker may need to request additional packages beyond +// just the direct imports. Type information for the entire transitive +// closure of imports is provided (lazily) by the DAG. +// // No promises are made about the encoding other than that it can be decoded by // the same version of IIExportShallow. If you plan to save export data in the // file system, be sure to include a cryptographic digest of the executable in @@ -51,8 +288,8 @@ func IExportShallow(fset *token.FileSet, pkg *types.Package, reportf ReportFunc) } // IImportShallow decodes "shallow" types.Package data encoded by -// IExportShallow in the same executable. This function cannot import data from -// cmd/compile or gcexportdata.Write. +// [IExportShallow] in the same executable. This function cannot import data +// from cmd/compile or gcexportdata.Write. // // The importer calls getPackages to obtain package symbols for all // packages mentioned in the export data, including the one being @@ -223,7 +460,7 @@ func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) // Sort the set of needed offsets. Duplicates are harmless. sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] }) - lines := tokeninternal.GetLines(file) // byte offset of each line start + lines := file.Lines() // byte offset of each line start w.uint64(uint64(len(lines))) // Rather than record the entire array of line start offsets, @@ -507,13 +744,13 @@ func (p *iexporter) doDecl(obj types.Object) { case *types.TypeName: t := obj.Type() - if tparam, ok := aliases.Unalias(t).(*types.TypeParam); ok { + if tparam, ok := types.Unalias(t).(*types.TypeParam); ok { w.tag(typeParamTag) w.pos(obj.Pos()) constraint := tparam.Constraint() if p.version >= iexportVersionGo1_18 { implicit := false - if iface, _ := aliases.Unalias(constraint).(*types.Interface); iface != nil { + if iface, _ := types.Unalias(constraint).(*types.Interface); iface != nil { implicit = iface.IsImplicit() } w.bool(implicit) @@ -523,9 +760,22 @@ func (p *iexporter) doDecl(obj types.Object) { } if obj.IsAlias() { - w.tag(aliasTag) + alias, materialized := t.(*types.Alias) // may fail when aliases are not enabled + + var tparams *types.TypeParamList + if materialized { + tparams = aliases.TypeParams(alias) + } + if tparams.Len() == 0 { + w.tag(aliasTag) + } else { + w.tag(genericAliasTag) + } w.pos(obj.Pos()) - if alias, ok := t.(*aliases.Alias); ok { + if tparams.Len() > 0 { + w.tparamList(obj.Name(), tparams, obj.Pkg()) + } + if materialized { // Preserve materialized aliases, // even of non-exported types. t = aliases.Rhs(alias) @@ -744,8 +994,14 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { }() } switch t := t.(type) { - case *aliases.Alias: - // TODO(adonovan): support parameterized aliases, following *types.Named. + case *types.Alias: + if targs := aliases.TypeArgs(t); targs.Len() > 0 { + w.startType(instanceType) + w.pos(t.Obj().Pos()) + w.typeList(targs, pkg) + w.typ(aliases.Origin(t), pkg) + return + } w.startType(aliasType) w.qualifiedType(t.Obj()) @@ -854,7 +1110,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { for i := 0; i < n; i++ { ft := t.EmbeddedType(i) tPkg := pkg - if named, _ := aliases.Unalias(ft).(*types.Named); named != nil { + if named, _ := types.Unalias(ft).(*types.Named); named != nil { w.pos(named.Obj().Pos()) } else { w.pos(token.NoPos) diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index 136aa03653..1294392715 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -3,9 +3,7 @@ // license that can be found in the LICENSE file. // Indexed package import. -// See cmd/compile/internal/gc/iexport.go for the export data format. - -// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go. +// See iexport.go for the export data format. package gcimporter @@ -53,6 +51,7 @@ const ( iexportVersionPosCol = 1 iexportVersionGo1_18 = 2 iexportVersionGenerics = 2 + iexportVersion = iexportVersionGenerics iexportVersionCurrent = 2 ) @@ -540,7 +539,7 @@ func canReuse(def *types.Named, rhs types.Type) bool { if def == nil { return true } - iface, _ := aliases.Unalias(rhs).(*types.Interface) + iface, _ := types.Unalias(rhs).(*types.Interface) if iface == nil { return true } @@ -557,19 +556,28 @@ type importReader struct { prevColumn int64 } +// markBlack is redefined in iimport_go123.go, to work around golang/go#69912. +// +// If TypeNames are not marked black (in the sense of go/types cycle +// detection), they may be mutated when dot-imported. Fix this by punching a +// hole through the type, when compiling with Go 1.23. (The bug has been fixed +// for 1.24, but the fix was not worth back-porting). +var markBlack = func(name *types.TypeName) {} + func (r *importReader) obj(name string) { tag := r.byte() pos := r.pos() switch tag { - case aliasTag: + case aliasTag, genericAliasTag: + var tparams []*types.TypeParam + if tag == genericAliasTag { + tparams = r.tparamList() + } typ := r.typ() - // TODO(adonovan): support generic aliases: - // if tag == genericAliasTag { - // tparams := r.tparamList() - // alias.SetTypeParams(tparams) - // } - r.declare(aliases.NewAlias(r.p.aliases, pos, r.currPkg, name, typ)) + obj := aliases.NewAlias(r.p.aliases, pos, r.currPkg, name, typ, tparams) + markBlack(obj) // workaround for golang/go#69912 + r.declare(obj) case constTag: typ, val := r.value() @@ -589,6 +597,9 @@ func (r *importReader) obj(name string) { // declaration before recursing. obj := types.NewTypeName(pos, r.currPkg, name, nil) named := types.NewNamed(obj, nil, nil) + + markBlack(obj) // workaround for golang/go#69912 + // Declare obj before calling r.tparamList, so the new type name is recognized // if used in the constraint of one of its own typeparams (see #48280). r.declare(obj) @@ -615,7 +626,7 @@ func (r *importReader) obj(name string) { if targs.Len() > 0 { rparams = make([]*types.TypeParam, targs.Len()) for i := range rparams { - rparams[i] = aliases.Unalias(targs.At(i)).(*types.TypeParam) + rparams[i] = types.Unalias(targs.At(i)).(*types.TypeParam) } } msig := r.signature(recv, rparams, nil) @@ -645,7 +656,7 @@ func (r *importReader) obj(name string) { } constraint := r.typ() if implicit { - iface, _ := aliases.Unalias(constraint).(*types.Interface) + iface, _ := types.Unalias(constraint).(*types.Interface) if iface == nil { errorf("non-interface constraint marked implicit") } @@ -660,7 +671,9 @@ func (r *importReader) obj(name string) { case varTag: typ := r.typ() - r.declare(types.NewVar(pos, r.currPkg, name, typ)) + v := types.NewVar(pos, r.currPkg, name, typ) + typesinternal.SetVarKind(v, typesinternal.PackageVar) + r.declare(v) default: errorf("unexpected tag: %v", tag) @@ -852,7 +865,7 @@ func (r *importReader) typ() types.Type { } func isInterface(t types.Type) bool { - _, ok := aliases.Unalias(t).(*types.Interface) + _, ok := types.Unalias(t).(*types.Interface) return ok } @@ -862,7 +875,7 @@ func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } func (r *importReader) doType(base *types.Named) (res types.Type) { k := r.kind() if debug { - r.p.trace("importing type %d (base: %s)", k, base) + r.p.trace("importing type %d (base: %v)", k, base) r.p.indent++ defer func() { r.p.indent-- @@ -959,7 +972,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { methods[i] = method } - typ := newInterface(methods, embeddeds) + typ := types.NewInterfaceType(methods, embeddeds) r.p.interfaceList = append(r.p.interfaceList, typ) return typ @@ -1051,7 +1064,7 @@ func (r *importReader) tparamList() []*types.TypeParam { for i := range xs { // Note: the standard library importer is tolerant of nil types here, // though would panic in SetTypeParams. - xs[i] = aliases.Unalias(r.typ()).(*types.TypeParam) + xs[i] = types.Unalias(r.typ()).(*types.TypeParam) } return xs } @@ -1098,3 +1111,9 @@ func (r *importReader) byte() byte { } return x } + +type byPath []*types.Package + +func (a byPath) Len() int { return len(a) } +func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go new file mode 100644 index 0000000000..7586bfaca6 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go @@ -0,0 +1,53 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.22 && !go1.24 + +package gcimporter + +import ( + "go/token" + "go/types" + "unsafe" +) + +// TODO(rfindley): delete this workaround once go1.24 is assured. + +func init() { + // Update markBlack so that it correctly sets the color + // of imported TypeNames. + // + // See the doc comment for markBlack for details. + + type color uint32 + const ( + white color = iota + black + grey + ) + type object struct { + _ *types.Scope + _ token.Pos + _ *types.Package + _ string + _ types.Type + _ uint32 + color_ color + _ token.Pos + } + type typeName struct { + object + } + + // If the size of types.TypeName changes, this will fail to compile. + const delta = int64(unsafe.Sizeof(typeName{})) - int64(unsafe.Sizeof(types.TypeName{})) + var _ [-delta * delta]int + + markBlack = func(obj *types.TypeName) { + type uP = unsafe.Pointer + var ptr *typeName + *(*uP)(uP(&ptr)) = uP(obj) + ptr.color_ = black + } +} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go b/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go deleted file mode 100644 index 8b163e3d05..0000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.11 -// +build !go1.11 - -package gcimporter - -import "go/types" - -func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { - named := make([]*types.Named, len(embeddeds)) - for i, e := range embeddeds { - var ok bool - named[i], ok = e.(*types.Named) - if !ok { - panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11") - } - } - return types.NewInterface(methods, named) -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go b/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go deleted file mode 100644 index 49984f40fd..0000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.11 -// +build go1.11 - -package gcimporter - -import "go/types" - -func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { - return types.NewInterfaceType(methods, embeddeds) -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/predeclared.go b/vendor/golang.org/x/tools/internal/gcimporter/predeclared.go new file mode 100644 index 0000000000..907c8557a5 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gcimporter/predeclared.go @@ -0,0 +1,91 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gcimporter + +import ( + "go/types" + "sync" +) + +// predecl is a cache for the predeclared types in types.Universe. +// +// Cache a distinct result based on the runtime value of any. +// The pointer value of the any type varies based on GODEBUG settings. +var predeclMu sync.Mutex +var predecl map[types.Type][]types.Type + +func predeclared() []types.Type { + anyt := types.Universe.Lookup("any").Type() + + predeclMu.Lock() + defer predeclMu.Unlock() + + if pre, ok := predecl[anyt]; ok { + return pre + } + + if predecl == nil { + predecl = make(map[types.Type][]types.Type) + } + + decls := []types.Type{ // basic types + types.Typ[types.Bool], + types.Typ[types.Int], + types.Typ[types.Int8], + types.Typ[types.Int16], + types.Typ[types.Int32], + types.Typ[types.Int64], + types.Typ[types.Uint], + types.Typ[types.Uint8], + types.Typ[types.Uint16], + types.Typ[types.Uint32], + types.Typ[types.Uint64], + types.Typ[types.Uintptr], + types.Typ[types.Float32], + types.Typ[types.Float64], + types.Typ[types.Complex64], + types.Typ[types.Complex128], + types.Typ[types.String], + + // basic type aliases + types.Universe.Lookup("byte").Type(), + types.Universe.Lookup("rune").Type(), + + // error + types.Universe.Lookup("error").Type(), + + // untyped types + types.Typ[types.UntypedBool], + types.Typ[types.UntypedInt], + types.Typ[types.UntypedRune], + types.Typ[types.UntypedFloat], + types.Typ[types.UntypedComplex], + types.Typ[types.UntypedString], + types.Typ[types.UntypedNil], + + // package unsafe + types.Typ[types.UnsafePointer], + + // invalid type + types.Typ[types.Invalid], // only appears in packages with errors + + // used internally by gc; never used by this package or in .a files + anyType{}, + + // comparable + types.Universe.Lookup("comparable").Type(), + + // any + anyt, + } + + predecl[anyt] = decls + return decls +} + +type anyType struct{} + +func (t anyType) Underlying() types.Type { return t } +func (t anyType) String() string { return "any" } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/support.go b/vendor/golang.org/x/tools/internal/gcimporter/support.go new file mode 100644 index 0000000000..4af810dc41 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gcimporter/support.go @@ -0,0 +1,30 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gcimporter + +import ( + "bufio" + "io" + "strconv" + "strings" +) + +// Copy of $GOROOT/src/cmd/internal/archive.ReadHeader. +func readArchiveHeader(b *bufio.Reader, name string) int { + // architecture-independent object file output + const HeaderSize = 60 + + var buf [HeaderSize]byte + if _, err := io.ReadFull(b, buf[:]); err != nil { + return -1 + } + aname := strings.Trim(string(buf[0:16]), " ") + if !strings.HasPrefix(aname, name) { + return -1 + } + asize := strings.Trim(string(buf[48:58]), " ") + i, _ := strconv.Atoi(asize) + return i +} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go b/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go deleted file mode 100644 index 0cd3b91b65..0000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gcimporter - -import "go/types" - -const iexportVersion = iexportVersionGenerics - -// additionalPredeclared returns additional predeclared types in go.1.18. -func additionalPredeclared() []types.Type { - return []types.Type{ - // comparable - types.Universe.Lookup("comparable").Type(), - - // any - types.Universe.Lookup("any").Type(), - } -} - -// See cmd/compile/internal/types.SplitVargenSuffix. -func splitVargenSuffix(name string) (base, suffix string) { - i := len(name) - for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' { - i-- - } - const dot = "·" - if i >= len(dot) && name[i-len(dot):i] == dot { - i -= len(dot) - return name[:i], name[i:] - } - return name, "" -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go b/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go deleted file mode 100644 index 38b624cada..0000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.unified -// +build !goexperiment.unified - -package gcimporter - -const unifiedIR = false diff --git a/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go deleted file mode 100644 index b5118d0b3a..0000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.unified -// +build goexperiment.unified - -package gcimporter - -const unifiedIR = true diff --git a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go index 2c07706887..522287d18d 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go @@ -11,10 +11,10 @@ import ( "go/token" "go/types" "sort" - "strings" "golang.org/x/tools/internal/aliases" "golang.org/x/tools/internal/pkgbits" + "golang.org/x/tools/internal/typesinternal" ) // A pkgReader holds the shared state for reading a unified IR package @@ -52,8 +52,7 @@ func (pr *pkgReader) later(fn func()) { // See cmd/compile/internal/noder.derivedInfo. type derivedInfo struct { - idx pkgbits.Index - needed bool + idx pkgbits.Index } // See cmd/compile/internal/noder.typeInfo. @@ -72,7 +71,6 @@ func UImportData(fset *token.FileSet, imports map[string]*types.Package, data [] } s := string(data) - s = s[:strings.LastIndex(s, "\n$$\n")] input := pkgbits.NewPkgDecoder(path, s) pkg = readUnifiedPackage(fset, nil, imports, input) return @@ -110,13 +108,17 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic) pkg := r.pkg() - r.Bool() // has init + if r.Version().Has(pkgbits.HasInit) { + r.Bool() + } for i, n := 0, r.Len(); i < n; i++ { // As if r.obj(), but avoiding the Scope.Lookup call, // to avoid eager loading of imports. r.Sync(pkgbits.SyncObject) - assert(!r.Bool()) + if r.Version().Has(pkgbits.DerivedFuncInstance) { + assert(!r.Bool()) + } r.p.objIdx(r.Reloc(pkgbits.RelocObj)) assert(r.Len() == 0) } @@ -165,7 +167,7 @@ type readerDict struct { // tparams is a slice of the constructed TypeParams for the element. tparams []*types.TypeParam - // devived is a slice of types derived from tparams, which may be + // derived is a slice of types derived from tparams, which may be // instantiated while reading the current element. derived []derivedInfo derivedTypes []types.Type // lazily instantiated from derived @@ -263,7 +265,12 @@ func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Package { func (r *reader) doPkg() *types.Package { path := r.String() switch path { - case "": + // cmd/compile emits path="main" for main packages because + // that's the linker symbol prefix it used; but we need + // the package's path as it would be reported by go list, + // hence "main" below. + // See test at go/packages.TestMainPackagePathInModeTypes. + case "", "main": path = r.p.PkgPath() case "builtin": return nil // universe @@ -471,7 +478,9 @@ func (r *reader) param() *types.Var { func (r *reader) obj() (types.Object, []types.Type) { r.Sync(pkgbits.SyncObject) - assert(!r.Bool()) + if r.Version().Has(pkgbits.DerivedFuncInstance) { + assert(!r.Bool()) + } pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj)) obj := pkgScope(pkg).Lookup(name) @@ -525,8 +534,12 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { case pkgbits.ObjAlias: pos := r.pos() + var tparams []*types.TypeParam + if r.Version().Has(pkgbits.AliasTypeParamNames) { + tparams = r.typeParamNames() + } typ := r.typ() - declare(aliases.NewAlias(r.p.aliases, pos, objPkg, objName, typ)) + declare(aliases.NewAlias(r.p.aliases, pos, objPkg, objName, typ, tparams)) case pkgbits.ObjConst: pos := r.pos() @@ -553,13 +566,14 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { // If the underlying type is an interface, we need to // duplicate its methods so we can replace the receiver // parameter's type (#49906). - if iface, ok := aliases.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 { + if iface, ok := types.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 { methods := make([]*types.Func, iface.NumExplicitMethods()) for i := range methods { fn := iface.ExplicitMethod(i) sig := fn.Type().(*types.Signature) recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named) + typesinternal.SetVarKind(recv, typesinternal.RecvVar) methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic())) } @@ -607,7 +621,9 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { case pkgbits.ObjVar: pos := r.pos() typ := r.typ() - declare(types.NewVar(pos, objPkg, objName, typ)) + v := types.NewVar(pos, objPkg, objName, typ) + typesinternal.SetVarKind(v, typesinternal.PackageVar) + declare(v) } } @@ -632,7 +648,10 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict { dict.derived = make([]derivedInfo, r.Len()) dict.derivedTypes = make([]types.Type, len(dict.derived)) for i := range dict.derived { - dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} + dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.RelocType)} + if r.Version().Has(pkgbits.DerivedInfoNeeded) { + assert(!r.Bool()) + } } pr.retireReader(r) @@ -726,3 +745,17 @@ func pkgScope(pkg *types.Package) *types.Scope { } return types.Universe } + +// See cmd/compile/internal/types.SplitVargenSuffix. +func splitVargenSuffix(name string) (base, suffix string) { + i := len(name) + for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' { + i-- + } + const dot = "·" + if i >= len(dot) && name[i-len(dot):i] == dot { + i -= len(dot) + return name[:i], name[i:] + } + return name, "" +} diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go index 2e59ff8558..7ea9013447 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -16,7 +16,6 @@ import ( "os" "os/exec" "path/filepath" - "reflect" "regexp" "runtime" "strconv" @@ -29,7 +28,7 @@ import ( "golang.org/x/tools/internal/event/label" ) -// An Runner will run go command invocations and serialize +// A Runner will run go command invocations and serialize // them if it sees a concurrency error. type Runner struct { // once guards the runner initialization. @@ -180,7 +179,7 @@ type Invocation struct { CleanEnv bool Env []string WorkingDir string - Logf func(format string, args ...interface{}) + Logf func(format string, args ...any) } // Postcondition: both error results have same nilness. @@ -250,16 +249,13 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { cmd.Stdout = stdout cmd.Stderr = stderr - // cmd.WaitDelay was added only in go1.20 (see #50436). - if waitDelay := reflect.ValueOf(cmd).Elem().FieldByName("WaitDelay"); waitDelay.IsValid() { - // https://go.dev/issue/59541: don't wait forever copying stderr - // after the command has exited. - // After CL 484741 we copy stdout manually, so we we'll stop reading that as - // soon as ctx is done. However, we also don't want to wait around forever - // for stderr. Give a much-longer-than-reasonable delay and then assume that - // something has wedged in the kernel or runtime. - waitDelay.Set(reflect.ValueOf(30 * time.Second)) - } + // https://go.dev/issue/59541: don't wait forever copying stderr + // after the command has exited. + // After CL 484741 we copy stdout manually, so we we'll stop reading that as + // soon as ctx is done. However, we also don't want to wait around forever + // for stderr. Give a much-longer-than-reasonable delay and then assume that + // something has wedged in the kernel or runtime. + cmd.WaitDelay = 30 * time.Second // The cwd gets resolved to the real path. On Darwin, where // /tmp is a symlink, this breaks anything that expects the @@ -392,7 +388,9 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) { case err := <-resChan: return err case <-timer.C: - HandleHangingGoCommand(startTime, cmd) + // HandleHangingGoCommand terminates this process. + // Pass off resChan in case we can collect the command error. + handleHangingGoCommand(startTime, cmd, resChan) case <-ctx.Done(): } } else { @@ -417,8 +415,6 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) { } // Didn't shut down in response to interrupt. Kill it hard. - // TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT - // on certain platforms, such as unix. if err := cmd.Process.Kill(); err != nil && !errors.Is(err, os.ErrProcessDone) && debug { log.Printf("error killing the Go command: %v", err) } @@ -426,15 +422,17 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) { return <-resChan } -func HandleHangingGoCommand(start time.Time, cmd *exec.Cmd) { +// handleHangingGoCommand outputs debugging information to help diagnose the +// cause of a hanging Go command, and then exits with log.Fatalf. +func handleHangingGoCommand(start time.Time, cmd *exec.Cmd, resChan chan error) { switch runtime.GOOS { - case "linux", "darwin", "freebsd", "netbsd": + case "linux", "darwin", "freebsd", "netbsd", "openbsd": fmt.Fprintln(os.Stderr, `DETECTED A HANGING GO COMMAND -The gopls test runner has detected a hanging go command. In order to debug -this, the output of ps and lsof/fstat is printed below. + The gopls test runner has detected a hanging go command. In order to debug + this, the output of ps and lsof/fstat is printed below. -See golang/go#54461 for more details.`) + See golang/go#54461 for more details.`) fmt.Fprintln(os.Stderr, "\nps axo ppid,pid,command:") fmt.Fprintln(os.Stderr, "-------------------------") @@ -442,7 +440,7 @@ See golang/go#54461 for more details.`) psCmd.Stdout = os.Stderr psCmd.Stderr = os.Stderr if err := psCmd.Run(); err != nil { - panic(fmt.Sprintf("running ps: %v", err)) + log.Printf("Handling hanging Go command: running ps: %v", err) } listFiles := "lsof" @@ -456,10 +454,24 @@ See golang/go#54461 for more details.`) listFilesCmd.Stdout = os.Stderr listFilesCmd.Stderr = os.Stderr if err := listFilesCmd.Run(); err != nil { - panic(fmt.Sprintf("running %s: %v", listFiles, err)) + log.Printf("Handling hanging Go command: running %s: %v", listFiles, err) + } + // Try to extract information about the slow go process by issuing a SIGQUIT. + if err := cmd.Process.Signal(sigStuckProcess); err == nil { + select { + case err := <-resChan: + stderr := "not a bytes.Buffer" + if buf, _ := cmd.Stderr.(*bytes.Buffer); buf != nil { + stderr = buf.String() + } + log.Printf("Quit hanging go command:\n\terr:%v\n\tstderr:\n%v\n\n", err, stderr) + case <-time.After(5 * time.Second): + } + } else { + log.Printf("Sending signal %d to hanging go command: %v", sigStuckProcess, err) } } - panic(fmt.Sprintf("detected hanging go command (golang/go#54461); waited %s\n\tcommand:%s\n\tpid:%d", time.Since(start), cmd, cmd.Process.Pid)) + log.Fatalf("detected hanging go command (golang/go#54461); waited %s\n\tcommand:%s\n\tpid:%d", time.Since(start), cmd, cmd.Process.Pid) } func cmdDebugStr(cmd *exec.Cmd) string { diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke_notunix.go b/vendor/golang.org/x/tools/internal/gocommand/invoke_notunix.go new file mode 100644 index 0000000000..469c648e4d --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke_notunix.go @@ -0,0 +1,13 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !unix + +package gocommand + +import "os" + +// sigStuckProcess is the signal to send to kill a hanging subprocess. +// On Unix we send SIGQUIT, but on non-Unix we only have os.Kill. +var sigStuckProcess = os.Kill diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke_unix.go b/vendor/golang.org/x/tools/internal/gocommand/invoke_unix.go new file mode 100644 index 0000000000..169d37c8e9 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke_unix.go @@ -0,0 +1,13 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package gocommand + +import "syscall" + +// Sigstuckprocess is the signal to send to kill a hanging subprocess. +// Send SIGQUIT to get a stack trace. +var sigStuckProcess = syscall.SIGQUIT diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go index dc7d50a7a4..bf6b0aaddd 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -27,7 +27,6 @@ import ( "unicode" "unicode/utf8" - "golang.org/x/sync/errgroup" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/gocommand" @@ -91,18 +90,6 @@ type ImportFix struct { Relevance float64 // see pkg } -// An ImportInfo represents a single import statement. -type ImportInfo struct { - ImportPath string // import path, e.g. "crypto/rand". - Name string // import name, e.g. "crand", or "" if none. -} - -// A packageInfo represents what's known about a package. -type packageInfo struct { - name string // real package name, if known. - exports map[string]bool // known exports. -} - // parseOtherFiles parses all the Go files in srcDir except filename, including // test files if filename looks like a test. // @@ -131,7 +118,7 @@ func parseOtherFiles(ctx context.Context, fset *token.FileSet, srcDir, filename continue } - f, err := parser.ParseFile(fset, filepath.Join(srcDir, fi.Name()), nil, 0) + f, err := parser.ParseFile(fset, filepath.Join(srcDir, fi.Name()), nil, parser.SkipObjectResolution) if err != nil { continue } @@ -162,8 +149,8 @@ func addGlobals(f *ast.File, globals map[string]bool) { // collectReferences builds a map of selector expressions, from // left hand side (X) to a set of right hand sides (Sel). -func collectReferences(f *ast.File) references { - refs := references{} +func collectReferences(f *ast.File) References { + refs := References{} var visitor visitFn visitor = func(node ast.Node) ast.Visitor { @@ -233,7 +220,7 @@ func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo { allFound := true for right := range syms { - if !pkgInfo.exports[right] { + if !pkgInfo.Exports[right] { allFound = false break } @@ -246,11 +233,6 @@ func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo { return nil } -// references is set of references found in a Go file. The first map key is the -// left hand side of a selector expression, the second key is the right hand -// side, and the value should always be true. -type references map[string]map[string]bool - // A pass contains all the inputs and state necessary to fix a file's imports. // It can be modified in some ways during use; see comments below. type pass struct { @@ -258,27 +240,29 @@ type pass struct { fset *token.FileSet // fset used to parse f and its siblings. f *ast.File // the file being fixed. srcDir string // the directory containing f. - env *ProcessEnv // the environment to use for go commands, etc. - loadRealPackageNames bool // if true, load package names from disk rather than guessing them. - otherFiles []*ast.File // sibling files. + logf func(string, ...any) + source Source // the environment to use for go commands, etc. + loadRealPackageNames bool // if true, load package names from disk rather than guessing them. + otherFiles []*ast.File // sibling files. + goroot string // Intermediate state, generated by load. existingImports map[string][]*ImportInfo - allRefs references - missingRefs references + allRefs References + missingRefs References // Inputs to fix. These can be augmented between successive fix calls. lastTry bool // indicates that this is the last call and fix should clean up as best it can. candidates []*ImportInfo // candidate imports in priority order. - knownPackages map[string]*packageInfo // information about all known packages. + knownPackages map[string]*PackageInfo // information about all known packages. } // loadPackageNames saves the package names for everything referenced by imports. -func (p *pass) loadPackageNames(imports []*ImportInfo) error { - if p.env.Logf != nil { - p.env.Logf("loading package names for %v packages", len(imports)) +func (p *pass) loadPackageNames(ctx context.Context, imports []*ImportInfo) error { + if p.logf != nil { + p.logf("loading package names for %v packages", len(imports)) defer func() { - p.env.Logf("done loading package names for %v packages", len(imports)) + p.logf("done loading package names for %v packages", len(imports)) }() } var unknown []string @@ -289,20 +273,17 @@ func (p *pass) loadPackageNames(imports []*ImportInfo) error { unknown = append(unknown, imp.ImportPath) } - resolver, err := p.env.GetResolver() - if err != nil { - return err - } - - names, err := resolver.loadPackageNames(unknown, p.srcDir) + names, err := p.source.LoadPackageNames(ctx, p.srcDir, unknown) if err != nil { return err } + // TODO(rfindley): revisit this. Why do we need to store known packages with + // no exports? The inconsistent data is confusing. for path, name := range names { - p.knownPackages[path] = &packageInfo{ - name: name, - exports: map[string]bool{}, + p.knownPackages[path] = &PackageInfo{ + Name: name, + Exports: map[string]bool{}, } } return nil @@ -330,8 +311,8 @@ func (p *pass) importIdentifier(imp *ImportInfo) string { return imp.Name } known := p.knownPackages[imp.ImportPath] - if known != nil && known.name != "" { - return withoutVersion(known.name) + if known != nil && known.Name != "" { + return withoutVersion(known.Name) } return ImportPathToAssumedName(imp.ImportPath) } @@ -339,9 +320,9 @@ func (p *pass) importIdentifier(imp *ImportInfo) string { // load reads in everything necessary to run a pass, and reports whether the // file already has all the imports it needs. It fills in p.missingRefs with the // file's missing symbols, if any, or removes unused imports if not. -func (p *pass) load() ([]*ImportFix, bool) { - p.knownPackages = map[string]*packageInfo{} - p.missingRefs = references{} +func (p *pass) load(ctx context.Context) ([]*ImportFix, bool) { + p.knownPackages = map[string]*PackageInfo{} + p.missingRefs = References{} p.existingImports = map[string][]*ImportInfo{} // Load basic information about the file in question. @@ -364,9 +345,11 @@ func (p *pass) load() ([]*ImportFix, bool) { // f's imports by the identifier they introduce. imports := collectImports(p.f) if p.loadRealPackageNames { - err := p.loadPackageNames(append(imports, p.candidates...)) + err := p.loadPackageNames(ctx, append(imports, p.candidates...)) if err != nil { - p.env.logf("loading package names: %v", err) + if p.logf != nil { + p.logf("loading package names: %v", err) + } return nil, false } } @@ -535,9 +518,10 @@ func (p *pass) assumeSiblingImportsValid() { // We have the stdlib in memory; no need to guess. rights = symbolNameSet(m) } - p.addCandidate(imp, &packageInfo{ + // TODO(rfindley): we should set package name here, for consistency. + p.addCandidate(imp, &PackageInfo{ // no name; we already know it. - exports: rights, + Exports: rights, }) } } @@ -546,14 +530,14 @@ func (p *pass) assumeSiblingImportsValid() { // addCandidate adds a candidate import to p, and merges in the information // in pkg. -func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) { +func (p *pass) addCandidate(imp *ImportInfo, pkg *PackageInfo) { p.candidates = append(p.candidates, imp) if existing, ok := p.knownPackages[imp.ImportPath]; ok { - if existing.name == "" { - existing.name = pkg.name + if existing.Name == "" { + existing.Name = pkg.Name } - for export := range pkg.exports { - existing.exports[export] = true + for export := range pkg.Exports { + existing.Exports[export] = true } } else { p.knownPackages[imp.ImportPath] = pkg @@ -581,19 +565,42 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P // getFixes gets the import fixes that need to be made to f in order to fix the imports. // It does not modify the ast. func getFixes(ctx context.Context, fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { + source, err := NewProcessEnvSource(env, filename, f.Name.Name) + if err != nil { + return nil, err + } + goEnv, err := env.goEnv() + if err != nil { + return nil, err + } + return getFixesWithSource(ctx, fset, f, filename, goEnv["GOROOT"], env.logf, source) +} + +func getFixesWithSource(ctx context.Context, fset *token.FileSet, f *ast.File, filename string, goroot string, logf func(string, ...any), source Source) ([]*ImportFix, error) { + // This logic is defensively duplicated from getFixes. abs, err := filepath.Abs(filename) if err != nil { return nil, err } srcDir := filepath.Dir(abs) - env.logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) + + if logf != nil { + logf("fixImports(filename=%q), srcDir=%q ...", filename, abs, srcDir) + } // First pass: looking only at f, and using the naive algorithm to // derive package names from import paths, see if the file is already // complete. We can't add any imports yet, because we don't know // if missing references are actually package vars. - p := &pass{fset: fset, f: f, srcDir: srcDir, env: env} - if fixes, done := p.load(); done { + p := &pass{ + fset: fset, + f: f, + srcDir: srcDir, + logf: logf, + goroot: goroot, + source: source, + } + if fixes, done := p.load(ctx); done { return fixes, nil } @@ -605,7 +612,7 @@ func getFixes(ctx context.Context, fset *token.FileSet, f *ast.File, filename st // Second pass: add information from other files in the same package, // like their package vars and imports. p.otherFiles = otherFiles - if fixes, done := p.load(); done { + if fixes, done := p.load(ctx); done { return fixes, nil } @@ -618,10 +625,17 @@ func getFixes(ctx context.Context, fset *token.FileSet, f *ast.File, filename st // Third pass: get real package names where we had previously used // the naive algorithm. - p = &pass{fset: fset, f: f, srcDir: srcDir, env: env} + p = &pass{ + fset: fset, + f: f, + srcDir: srcDir, + logf: logf, + goroot: goroot, + source: p.source, // safe to reuse, as it's just a wrapper around env + } p.loadRealPackageNames = true p.otherFiles = otherFiles - if fixes, done := p.load(); done { + if fixes, done := p.load(ctx); done { return fixes, nil } @@ -766,7 +780,7 @@ func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix return true }, dirFound: func(pkg *pkg) bool { - if !canUse(filename, pkg.dir) { + if !CanUse(filename, pkg.dir) { return false } // Try the assumed package name first, then a simpler path match @@ -801,7 +815,7 @@ func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, return true }, dirFound: func(pkg *pkg) bool { - if !canUse(filename, pkg.dir) { + if !CanUse(filename, pkg.dir) { return false } return strings.HasPrefix(pkg.importPathShort, searchPrefix) @@ -835,7 +849,7 @@ func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchP return true }, dirFound: func(pkg *pkg) bool { - return pkgIsCandidate(filename, references{searchPkg: nil}, pkg) + return pkgIsCandidate(filename, References{searchPkg: nil}, pkg) }, packageNameLoaded: func(pkg *pkg) bool { return pkg.packageName == searchPkg @@ -913,7 +927,7 @@ type ProcessEnv struct { WorkingDir string // If Logf is non-nil, debug logging is enabled through this function. - Logf func(format string, args ...interface{}) + Logf func(format string, args ...any) // If set, ModCache holds a shared cache of directory info to use across // multiple ProcessEnvs. @@ -1086,11 +1100,7 @@ func (e *ProcessEnv) invokeGo(ctx context.Context, verb string, args ...string) return e.GocmdRunner.Run(ctx, inv) } -func addStdlibCandidates(pass *pass, refs references) error { - goenv, err := pass.env.goEnv() - if err != nil { - return err - } +func addStdlibCandidates(pass *pass, refs References) error { localbase := func(nm string) string { ans := path.Base(nm) if ans[0] == 'v' { @@ -1105,13 +1115,13 @@ func addStdlibCandidates(pass *pass, refs references) error { } add := func(pkg string) { // Prevent self-imports. - if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir { + if path.Base(pkg) == pass.f.Name.Name && filepath.Join(pass.goroot, "src", pkg) == pass.srcDir { return } exports := symbolNameSet(stdlib.PackageSymbols[pkg]) pass.addCandidate( &ImportInfo{ImportPath: pkg}, - &packageInfo{name: localbase(pkg), exports: exports}) + &PackageInfo{Name: localbase(pkg), Exports: exports}) } for left := range refs { if left == "rand" { @@ -1122,6 +1132,9 @@ func addStdlibCandidates(pass *pass, refs references) error { // but we have no way of figuring out what the user is using // TODO: investigate using the toolchain version to disambiguate in the stdlib add("math/rand/v2") + // math/rand has an overlapping API + // TestIssue66407 fails without this + add("math/rand") continue } for importPath := range stdlib.PackageSymbols { @@ -1175,91 +1188,14 @@ type scanCallback struct { exportsLoaded func(pkg *pkg, exports []stdlib.Symbol) } -func addExternalCandidates(ctx context.Context, pass *pass, refs references, filename string) error { +func addExternalCandidates(ctx context.Context, pass *pass, refs References, filename string) error { ctx, done := event.Start(ctx, "imports.addExternalCandidates") defer done() - var mu sync.Mutex - found := make(map[string][]pkgDistance) - callback := &scanCallback{ - rootFound: func(gopathwalk.Root) bool { - return true // We want everything. - }, - dirFound: func(pkg *pkg) bool { - return pkgIsCandidate(filename, refs, pkg) - }, - packageNameLoaded: func(pkg *pkg) bool { - if _, want := refs[pkg.packageName]; !want { - return false - } - if pkg.dir == pass.srcDir && pass.f.Name.Name == pkg.packageName { - // The candidate is in the same directory and has the - // same package name. Don't try to import ourselves. - return false - } - if !canUse(filename, pkg.dir) { - return false - } - mu.Lock() - defer mu.Unlock() - found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkg, distance(pass.srcDir, pkg.dir)}) - return false // We'll do our own loading after we sort. - }, - } - resolver, err := pass.env.GetResolver() + results, err := pass.source.ResolveReferences(ctx, filename, refs) if err != nil { return err } - if err = resolver.scan(ctx, callback); err != nil { - return err - } - - // Search for imports matching potential package references. - type result struct { - imp *ImportInfo - pkg *packageInfo - } - results := make([]*result, len(refs)) - - g, ctx := errgroup.WithContext(ctx) - - searcher := symbolSearcher{ - logf: pass.env.logf, - srcDir: pass.srcDir, - xtest: strings.HasSuffix(pass.f.Name.Name, "_test"), - loadExports: resolver.loadExports, - } - - i := 0 - for pkgName, symbols := range refs { - index := i // claim an index in results - i++ - pkgName := pkgName - symbols := symbols - - g.Go(func() error { - found, err := searcher.search(ctx, found[pkgName], pkgName, symbols) - if err != nil { - return err - } - if found == nil { - return nil // No matching package. - } - - imp := &ImportInfo{ - ImportPath: found.importPathShort, - } - pkg := &packageInfo{ - name: pkgName, - exports: symbols, - } - results[index] = &result{imp, pkg} - return nil - }) - } - if err := g.Wait(); err != nil { - return err - } for _, result := range results { if result == nil { @@ -1267,7 +1203,7 @@ func addExternalCandidates(ctx context.Context, pass *pass, refs references, fil } // Don't offer completions that would shadow predeclared // names, such as github.com/coreos/etcd/error. - if types.Universe.Lookup(result.pkg.name) != nil { // predeclared + if types.Universe.Lookup(result.Package.Name) != nil { // predeclared // Ideally we would skip this candidate only // if the predeclared name is actually // referenced by the file, but that's a lot @@ -1276,7 +1212,7 @@ func addExternalCandidates(ctx context.Context, pass *pass, refs references, fil // user before long. continue } - pass.addCandidate(result.imp, result.pkg) + pass.addCandidate(result.Import, result.Package) } return nil } @@ -1620,6 +1556,7 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl } fullFile := filepath.Join(dir, fi.Name()) + // Legacy ast.Object resolution is needed here. f, err := parser.ParseFile(fset, fullFile, nil, 0) if err != nil { env.logf("error parsing %v: %v", fullFile, err) @@ -1800,9 +1737,9 @@ func (s *symbolSearcher) searchOne(ctx context.Context, c pkgDistance, symbols m // filename is the file being formatted. // pkgIdent is the package being searched for, like "client" (if // searching for "client.New") -func pkgIsCandidate(filename string, refs references, pkg *pkg) bool { +func pkgIsCandidate(filename string, refs References, pkg *pkg) bool { // Check "internal" and "vendor" visibility: - if !canUse(filename, pkg.dir) { + if !CanUse(filename, pkg.dir) { return false } @@ -1825,9 +1762,9 @@ func pkgIsCandidate(filename string, refs references, pkg *pkg) bool { return false } -// canUse reports whether the package in dir is usable from filename, +// CanUse reports whether the package in dir is usable from filename, // respecting the Go "internal" and "vendor" visibility rules. -func canUse(filename, dir string) bool { +func CanUse(filename, dir string) bool { // Fast path check, before any allocations. If it doesn't contain vendor // or internal, it's not tricky: // Note that this can false-negative on directories like "notinternal", diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go index f83465520a..2215a12880 100644 --- a/vendor/golang.org/x/tools/internal/imports/imports.go +++ b/vendor/golang.org/x/tools/internal/imports/imports.go @@ -47,7 +47,14 @@ type Options struct { // Process implements golang.org/x/tools/imports.Process with explicit context in opt.Env. func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) { fileSet := token.NewFileSet() - file, adjust, err := parse(fileSet, filename, src, opt) + var parserMode parser.Mode + if opt.Comments { + parserMode |= parser.ParseComments + } + if opt.AllErrors { + parserMode |= parser.AllErrors + } + file, adjust, err := parse(fileSet, filename, src, parserMode, opt.Fragment) if err != nil { return nil, err } @@ -66,17 +73,19 @@ func Process(filename string, src []byte, opt *Options) (formatted []byte, err e // // Note that filename's directory influences which imports can be chosen, // so it is important that filename be accurate. -func FixImports(ctx context.Context, filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { +func FixImports(ctx context.Context, filename string, src []byte, goroot string, logf func(string, ...any), source Source) (fixes []*ImportFix, err error) { ctx, done := event.Start(ctx, "imports.FixImports") defer done() fileSet := token.NewFileSet() - file, _, err := parse(fileSet, filename, src, opt) + // TODO(rfindley): these default values for ParseComments and AllErrors were + // extracted from gopls, but are they even needed? + file, _, err := parse(fileSet, filename, src, parser.ParseComments|parser.AllErrors, true) if err != nil { return nil, err } - return getFixes(ctx, fileSet, file, filename, opt.Env) + return getFixesWithSource(ctx, fileSet, file, filename, goroot, logf, source) } // ApplyFixes applies all of the fixes to the file and formats it. extraMode @@ -86,7 +95,7 @@ func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, e // Don't use parse() -- we don't care about fragments or statement lists // here, and we need to work with unparseable files. fileSet := token.NewFileSet() - parserMode := parser.Mode(0) + parserMode := parser.SkipObjectResolution if opt.Comments { parserMode |= parser.ParseComments } @@ -114,7 +123,7 @@ func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, e // formatted file, and returns the postpocessed result. func formatFile(fset *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) { mergeImports(file) - sortImports(opt.LocalPrefix, fset.File(file.Pos()), file) + sortImports(opt.LocalPrefix, fset.File(file.FileStart), file) var spacesBefore []string // import paths we need spaces before for _, impSection := range astutil.Imports(fset, file) { // Within each block of contiguous imports, see if any @@ -164,13 +173,9 @@ func formatFile(fset *token.FileSet, file *ast.File, src []byte, adjust func(ori // parse parses src, which was read from filename, // as a Go source file or statement list. -func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) { - parserMode := parser.Mode(0) - if opt.Comments { - parserMode |= parser.ParseComments - } - if opt.AllErrors { - parserMode |= parser.AllErrors +func parse(fset *token.FileSet, filename string, src []byte, parserMode parser.Mode, fragment bool) (*ast.File, func(orig, src []byte) []byte, error) { + if parserMode&parser.SkipObjectResolution != 0 { + panic("legacy ast.Object resolution is required") } // Try as whole source file. @@ -181,7 +186,7 @@ func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast // If the error is that the source file didn't begin with a // package line and we accept fragmented input, fall through to // try as a source fragment. Stop and return on any other error. - if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") { + if !fragment || !strings.Contains(err.Error(), "expected 'package'") { return nil, nil, err } diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go index 91221fda32..8555e3f83d 100644 --- a/vendor/golang.org/x/tools/internal/imports/mod.go +++ b/vendor/golang.org/x/tools/internal/imports/mod.go @@ -245,7 +245,10 @@ func newModuleResolver(e *ProcessEnv, moduleCacheCache *DirInfoCache) (*ModuleRe // 2. Use this to separate module cache scanning from other scanning. func gomodcacheForEnv(goenv map[string]string) string { if gmc := goenv["GOMODCACHE"]; gmc != "" { - return gmc + // golang/go#67156: ensure that the module cache is clean, since it is + // assumed as a prefix to directories scanned by gopathwalk, which are + // themselves clean. + return filepath.Clean(gmc) } gopaths := filepath.SplitList(goenv["GOPATH"]) if len(gopaths) == 0 { @@ -740,8 +743,8 @@ func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) directoryPackageInfo { subdir := "" - if dir != root.Path { - subdir = dir[len(root.Path)+len("/"):] + if prefix := root.Path + string(filepath.Separator); strings.HasPrefix(dir, prefix) { + subdir = dir[len(prefix):] } importPath := filepath.ToSlash(subdir) if strings.HasPrefix(importPath, "vendor/") { diff --git a/vendor/golang.org/x/tools/internal/imports/source.go b/vendor/golang.org/x/tools/internal/imports/source.go new file mode 100644 index 0000000000..cbe4f3c5ba --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/source.go @@ -0,0 +1,63 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package imports + +import "context" + +// These types document the APIs below. +// +// TODO(rfindley): consider making these defined types rather than aliases. +type ( + ImportPath = string + PackageName = string + Symbol = string + + // References is set of References found in a Go file. The first map key is the + // left hand side of a selector expression, the second key is the right hand + // side, and the value should always be true. + References = map[PackageName]map[Symbol]bool +) + +// A Result satisfies a missing import. +// +// The Import field describes the missing import spec, and the Package field +// summarizes the package exports. +type Result struct { + Import *ImportInfo + Package *PackageInfo +} + +// An ImportInfo represents a single import statement. +type ImportInfo struct { + ImportPath string // import path, e.g. "crypto/rand". + Name string // import name, e.g. "crand", or "" if none. +} + +// A PackageInfo represents what's known about a package. +type PackageInfo struct { + Name string // package name in the package declaration, if known + Exports map[string]bool // set of names of known package level sortSymbols +} + +// A Source provides imports to satisfy unresolved references in the file being +// fixed. +type Source interface { + // LoadPackageNames queries PackageName information for the requested import + // paths, when operating from the provided srcDir. + // + // TODO(rfindley): try to refactor to remove this operation. + LoadPackageNames(ctx context.Context, srcDir string, paths []ImportPath) (map[ImportPath]PackageName, error) + + // ResolveReferences asks the Source for the best package name to satisfy + // each of the missing references, in the context of fixing the given + // filename. + // + // Returns a map from package name to a [Result] for that package name that + // provides the required symbols. Keys may be omitted in the map if no + // candidates satisfy all missing references for that package name. It is up + // to each data source to select the best result for each entry in the + // missing map. + ResolveReferences(ctx context.Context, filename string, missing References) ([]*Result, error) +} diff --git a/vendor/golang.org/x/tools/internal/imports/source_env.go b/vendor/golang.org/x/tools/internal/imports/source_env.go new file mode 100644 index 0000000000..ec996c3ccf --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/source_env.go @@ -0,0 +1,129 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package imports + +import ( + "context" + "path/filepath" + "strings" + "sync" + + "golang.org/x/sync/errgroup" + "golang.org/x/tools/internal/gopathwalk" +) + +// ProcessEnvSource implements the [Source] interface using the legacy +// [ProcessEnv] abstraction. +type ProcessEnvSource struct { + env *ProcessEnv + srcDir string + filename string + pkgName string +} + +// NewProcessEnvSource returns a [ProcessEnvSource] wrapping the given +// env, to be used for fixing imports in the file with name filename in package +// named pkgName. +func NewProcessEnvSource(env *ProcessEnv, filename, pkgName string) (*ProcessEnvSource, error) { + abs, err := filepath.Abs(filename) + if err != nil { + return nil, err + } + srcDir := filepath.Dir(abs) + return &ProcessEnvSource{ + env: env, + srcDir: srcDir, + filename: filename, + pkgName: pkgName, + }, nil +} + +func (s *ProcessEnvSource) LoadPackageNames(ctx context.Context, srcDir string, unknown []string) (map[string]string, error) { + r, err := s.env.GetResolver() + if err != nil { + return nil, err + } + return r.loadPackageNames(unknown, srcDir) +} + +func (s *ProcessEnvSource) ResolveReferences(ctx context.Context, filename string, refs map[string]map[string]bool) ([]*Result, error) { + var mu sync.Mutex + found := make(map[string][]pkgDistance) + callback := &scanCallback{ + rootFound: func(gopathwalk.Root) bool { + return true // We want everything. + }, + dirFound: func(pkg *pkg) bool { + return pkgIsCandidate(filename, refs, pkg) + }, + packageNameLoaded: func(pkg *pkg) bool { + if _, want := refs[pkg.packageName]; !want { + return false + } + if pkg.dir == s.srcDir && s.pkgName == pkg.packageName { + // The candidate is in the same directory and has the + // same package name. Don't try to import ourselves. + return false + } + if !CanUse(filename, pkg.dir) { + return false + } + mu.Lock() + defer mu.Unlock() + found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkg, distance(s.srcDir, pkg.dir)}) + return false // We'll do our own loading after we sort. + }, + } + resolver, err := s.env.GetResolver() + if err != nil { + return nil, err + } + if err := resolver.scan(ctx, callback); err != nil { + return nil, err + } + + g, ctx := errgroup.WithContext(ctx) + + searcher := symbolSearcher{ + logf: s.env.logf, + srcDir: s.srcDir, + xtest: strings.HasSuffix(s.pkgName, "_test"), + loadExports: resolver.loadExports, + } + + var resultMu sync.Mutex + results := make(map[string]*Result, len(refs)) + for pkgName, symbols := range refs { + g.Go(func() error { + found, err := searcher.search(ctx, found[pkgName], pkgName, symbols) + if err != nil { + return err + } + if found == nil { + return nil // No matching package. + } + + imp := &ImportInfo{ + ImportPath: found.importPathShort, + } + pkg := &PackageInfo{ + Name: pkgName, + Exports: symbols, + } + resultMu.Lock() + results[pkgName] = &Result{Import: imp, Package: pkg} + resultMu.Unlock() + return nil + }) + } + if err := g.Wait(); err != nil { + return nil, err + } + var ans []*Result + for _, x := range results { + ans = append(ans, x) + } + return ans, nil +} diff --git a/vendor/golang.org/x/tools/internal/imports/source_modindex.go b/vendor/golang.org/x/tools/internal/imports/source_modindex.go new file mode 100644 index 0000000000..05229f06ce --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/source_modindex.go @@ -0,0 +1,103 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package imports + +import ( + "context" + "sync" + "time" + + "golang.org/x/tools/internal/modindex" +) + +// This code is here rather than in the modindex package +// to avoid import loops + +// implements Source using modindex, so only for module cache. +// +// this is perhaps over-engineered. A new Index is read at first use. +// And then Update is called after every 15 minutes, and a new Index +// is read if the index changed. It is not clear the Mutex is needed. +type IndexSource struct { + modcachedir string + mutex sync.Mutex + ix *modindex.Index + expires time.Time +} + +// create a new Source. Called from NewView in cache/session.go. +func NewIndexSource(cachedir string) *IndexSource { + return &IndexSource{modcachedir: cachedir} +} + +func (s *IndexSource) LoadPackageNames(ctx context.Context, srcDir string, paths []ImportPath) (map[ImportPath]PackageName, error) { + /// This is used by goimports to resolve the package names of imports of the + // current package, which is irrelevant for the module cache. + return nil, nil +} + +func (s *IndexSource) ResolveReferences(ctx context.Context, filename string, missing References) ([]*Result, error) { + if err := s.maybeReadIndex(); err != nil { + return nil, err + } + var cs []modindex.Candidate + for pkg, nms := range missing { + for nm := range nms { + x := s.ix.Lookup(pkg, nm, false) + cs = append(cs, x...) + } + } + found := make(map[string]*Result) + for _, c := range cs { + var x *Result + if x = found[c.ImportPath]; x == nil { + x = &Result{ + Import: &ImportInfo{ + ImportPath: c.ImportPath, + Name: "", + }, + Package: &PackageInfo{ + Name: c.PkgName, + Exports: make(map[string]bool), + }, + } + found[c.ImportPath] = x + } + x.Package.Exports[c.Name] = true + } + var ans []*Result + for _, x := range found { + ans = append(ans, x) + } + return ans, nil +} + +func (s *IndexSource) maybeReadIndex() error { + s.mutex.Lock() + defer s.mutex.Unlock() + + var readIndex bool + if time.Now().After(s.expires) { + ok, err := modindex.Update(s.modcachedir) + if err != nil { + return err + } + if ok { + readIndex = true + } + } + + if readIndex || s.ix == nil { + ix, err := modindex.ReadIndex(s.modcachedir) + if err != nil { + return err + } + s.ix = ix + // for now refresh every 15 minutes + s.expires = time.Now().Add(time.Minute * 15) + } + + return nil +} diff --git a/vendor/golang.org/x/tools/internal/modindex/directories.go b/vendor/golang.org/x/tools/internal/modindex/directories.go new file mode 100644 index 0000000000..1e1a02f239 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/modindex/directories.go @@ -0,0 +1,135 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modindex + +import ( + "fmt" + "log" + "os" + "path/filepath" + "regexp" + "slices" + "strings" + "sync" + "time" + + "golang.org/x/mod/semver" + "golang.org/x/tools/internal/gopathwalk" +) + +type directory struct { + path Relpath + importPath string + version string // semantic version + syms []symbol +} + +// filterDirs groups the directories by import path, +// sorting the ones with the same import path by semantic version, +// most recent first. +func byImportPath(dirs []Relpath) (map[string][]*directory, error) { + ans := make(map[string][]*directory) // key is import path + for _, d := range dirs { + ip, sv, err := DirToImportPathVersion(d) + if err != nil { + return nil, err + } + ans[ip] = append(ans[ip], &directory{ + path: d, + importPath: ip, + version: sv, + }) + } + for k, v := range ans { + semanticSort(v) + ans[k] = v + } + return ans, nil +} + +// sort the directories by semantic version, latest first +func semanticSort(v []*directory) { + slices.SortFunc(v, func(l, r *directory) int { + if n := semver.Compare(l.version, r.version); n != 0 { + return -n // latest first + } + return strings.Compare(string(l.path), string(r.path)) + }) +} + +// modCacheRegexp splits a relpathpath into module, module version, and package. +var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) + +// DirToImportPathVersion computes import path and semantic version +func DirToImportPathVersion(dir Relpath) (string, string, error) { + m := modCacheRegexp.FindStringSubmatch(string(dir)) + // m[1] is the module path + // m[2] is the version major.minor.patch(-
 1 && flds[1][1] == 'D',
+			}
+			if px.Type == Func {
+				n, err := strconv.Atoi(flds[2])
+				if err != nil {
+					continue // should never happen
+				}
+				px.Results = int16(n)
+				if len(flds) >= 4 {
+					sig := strings.Split(flds[3], " ")
+					for i := 0; i < len(sig); i++ {
+						// $ cannot otherwise occur. removing the spaces
+						// almost works, but for chan struct{}, e.g.
+						sig[i] = strings.Replace(sig[i], "$", " ", -1)
+					}
+					px.Sig = toFields(sig)
+				}
+			}
+			ans = append(ans, px)
+		}
+	}
+	return ans
+}
+
+func toFields(sig []string) []Field {
+	ans := make([]Field, len(sig)/2)
+	for i := 0; i < len(ans); i++ {
+		ans[i] = Field{Arg: sig[2*i], Type: sig[2*i+1]}
+	}
+	return ans
+}
+
+// benchmarks show this is measurably better than strings.Split
+// split into first 4 fields separated by single space
+func fastSplit(x string) []string {
+	ans := make([]string, 0, 4)
+	nxt := 0
+	start := 0
+	for i := 0; i < len(x); i++ {
+		if x[i] != ' ' {
+			continue
+		}
+		ans = append(ans, x[start:i])
+		nxt++
+		start = i + 1
+		if nxt >= 3 {
+			break
+		}
+	}
+	ans = append(ans, x[start:])
+	return ans
+}
+
+func asLexType(c byte) LexType {
+	switch c {
+	case 'C':
+		return Const
+	case 'V':
+		return Var
+	case 'T':
+		return Type
+	case 'F':
+		return Func
+	}
+	return -1
+}
diff --git a/vendor/golang.org/x/tools/internal/modindex/modindex.go b/vendor/golang.org/x/tools/internal/modindex/modindex.go
new file mode 100644
index 0000000000..355a53e71a
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/modindex/modindex.go
@@ -0,0 +1,164 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package modindex contains code for building and searching an index to
+// the Go module cache. The directory containing the index, returned by
+// IndexDir(), contains a file index-name- that contains the name
+// of the current index. We believe writing that short file is atomic.
+// ReadIndex reads that file to get the file name of the index.
+// WriteIndex writes an index with a unique name and then
+// writes that name into a new version of index-name-.
+// ( stands for the CurrentVersion of the index format.)
+package modindex
+
+import (
+	"path/filepath"
+	"slices"
+	"strings"
+	"time"
+
+	"golang.org/x/mod/semver"
+)
+
+// Create always creates a new index for the go module cache that is in cachedir.
+func Create(cachedir string) error {
+	_, err := indexModCache(cachedir, true)
+	return err
+}
+
+// Update the index for the go module cache that is in cachedir,
+// If there is no existing index it will build one.
+// If there are changed directories since the last index, it will
+// write a new one and return true. Otherwise it returns false.
+func Update(cachedir string) (bool, error) {
+	return indexModCache(cachedir, false)
+}
+
+// indexModCache writes an index current as of when it is called.
+// If clear is true the index is constructed from all of GOMODCACHE
+// otherwise the index is constructed from the last previous index
+// and the updates to the cache. It returns true if it wrote an index,
+// false otherwise.
+func indexModCache(cachedir string, clear bool) (bool, error) {
+	cachedir, err := filepath.Abs(cachedir)
+	if err != nil {
+		return false, err
+	}
+	cd := Abspath(cachedir)
+	future := time.Now().Add(24 * time.Hour) // safely in the future
+	ok, err := modindexTimed(future, cd, clear)
+	if err != nil {
+		return false, err
+	}
+	return ok, nil
+}
+
+// modindexTimed writes an index current as of onlyBefore.
+// If clear is true the index is constructed from all of GOMODCACHE
+// otherwise the index is constructed from the last previous index
+// and all the updates to the cache before onlyBefore.
+// It returns true if it wrote a new index, false if it wrote nothing.
+func modindexTimed(onlyBefore time.Time, cachedir Abspath, clear bool) (bool, error) {
+	var curIndex *Index
+	if !clear {
+		var err error
+		curIndex, err = ReadIndex(string(cachedir))
+		if clear && err != nil {
+			return false, err
+		}
+		// TODO(pjw): check that most of those directories still exist
+	}
+	cfg := &work{
+		onlyBefore: onlyBefore,
+		oldIndex:   curIndex,
+		cacheDir:   cachedir,
+	}
+	if curIndex != nil {
+		cfg.onlyAfter = curIndex.Changed
+	}
+	if err := cfg.buildIndex(); err != nil {
+		return false, err
+	}
+	if len(cfg.newIndex.Entries) == 0 && curIndex != nil {
+		// no changes from existing curIndex, don't write a new index
+		return false, nil
+	}
+	if err := cfg.writeIndex(); err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+type work struct {
+	onlyBefore time.Time // do not use directories later than this
+	onlyAfter  time.Time // only interested in directories after this
+	// directories from before onlyAfter come from oldIndex
+	oldIndex *Index
+	newIndex *Index
+	cacheDir Abspath
+}
+
+func (w *work) buildIndex() error {
+	// The effective date of the new index should be at least
+	// slightly earlier than when the directories are scanned
+	// so set it now.
+	w.newIndex = &Index{Changed: time.Now(), Cachedir: w.cacheDir}
+	dirs := findDirs(string(w.cacheDir), w.onlyAfter, w.onlyBefore)
+	if len(dirs) == 0 {
+		return nil
+	}
+	newdirs, err := byImportPath(dirs)
+	if err != nil {
+		return err
+	}
+	// for each import path it might occur only in newdirs,
+	// only in w.oldIndex, or in both.
+	// If it occurs in both, use the semantically later one
+	if w.oldIndex != nil {
+		for _, e := range w.oldIndex.Entries {
+			found, ok := newdirs[e.ImportPath]
+			if !ok {
+				w.newIndex.Entries = append(w.newIndex.Entries, e)
+				continue // use this one, there is no new one
+			}
+			if semver.Compare(found[0].version, e.Version) > 0 {
+				// use the new one
+			} else {
+				// use the old one, forget the new one
+				w.newIndex.Entries = append(w.newIndex.Entries, e)
+				delete(newdirs, e.ImportPath)
+			}
+		}
+	}
+	// get symbol information for all the new diredtories
+	getSymbols(w.cacheDir, newdirs)
+	// assemble the new index entries
+	for k, v := range newdirs {
+		d := v[0]
+		pkg, names := processSyms(d.syms)
+		if pkg == "" {
+			continue // PJW: does this ever happen?
+		}
+		entry := Entry{
+			PkgName:    pkg,
+			Dir:        d.path,
+			ImportPath: k,
+			Version:    d.version,
+			Names:      names,
+		}
+		w.newIndex.Entries = append(w.newIndex.Entries, entry)
+	}
+	// sort the entries in the new index
+	slices.SortFunc(w.newIndex.Entries, func(l, r Entry) int {
+		if n := strings.Compare(l.PkgName, r.PkgName); n != 0 {
+			return n
+		}
+		return strings.Compare(l.ImportPath, r.ImportPath)
+	})
+	return nil
+}
+
+func (w *work) writeIndex() error {
+	return writeIndex(w.cacheDir, w.newIndex)
+}
diff --git a/vendor/golang.org/x/tools/internal/modindex/symbols.go b/vendor/golang.org/x/tools/internal/modindex/symbols.go
new file mode 100644
index 0000000000..b918529d43
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/modindex/symbols.go
@@ -0,0 +1,218 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modindex
+
+import (
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"go/types"
+	"os"
+	"path/filepath"
+	"runtime"
+	"slices"
+	"strings"
+
+	"golang.org/x/sync/errgroup"
+)
+
+// The name of a symbol contains information about the symbol:
+//  T for types, TD if the type is deprecated
+//  C for consts, CD if the const is deprecated
+//  V for vars, VD if the var is deprecated
+// and for funcs:  F  ( )*
+// any spaces in  are replaced by $s so that the fields
+// of the name are space separated. F is replaced by FD if the func
+// is deprecated.
+type symbol struct {
+	pkg  string // name of the symbols's package
+	name string // declared name
+	kind string // T, C, V, or F, follwed by D if deprecated
+	sig  string // signature information, for F
+}
+
+// find the symbols for the best directories
+func getSymbols(cd Abspath, dirs map[string][]*directory) {
+	var g errgroup.Group
+	g.SetLimit(max(2, runtime.GOMAXPROCS(0)/2))
+	for _, vv := range dirs {
+		// throttling some day?
+		d := vv[0]
+		g.Go(func() error {
+			thedir := filepath.Join(string(cd), string(d.path))
+			mode := parser.SkipObjectResolution | parser.ParseComments
+
+			fi, err := os.ReadDir(thedir)
+			if err != nil {
+				return nil // log this someday?
+			}
+			for _, fx := range fi {
+				if !strings.HasSuffix(fx.Name(), ".go") || strings.HasSuffix(fx.Name(), "_test.go") {
+					continue
+				}
+				fname := filepath.Join(thedir, fx.Name())
+				tr, err := parser.ParseFile(token.NewFileSet(), fname, nil, mode)
+				if err != nil {
+					continue // ignore errors, someday log them?
+				}
+				d.syms = append(d.syms, getFileExports(tr)...)
+			}
+			return nil
+		})
+	}
+	g.Wait()
+}
+
+func getFileExports(f *ast.File) []symbol {
+	pkg := f.Name.Name
+	if pkg == "main" {
+		return nil
+	}
+	var ans []symbol
+	// should we look for //go:build ignore?
+	for _, decl := range f.Decls {
+		switch decl := decl.(type) {
+		case *ast.FuncDecl:
+			if decl.Recv != nil {
+				// ignore methods, as we are completing package selections
+				continue
+			}
+			name := decl.Name.Name
+			dtype := decl.Type
+			// not looking at dtype.TypeParams. That is, treating
+			// generic functions just like non-generic ones.
+			sig := dtype.Params
+			kind := "F"
+			if isDeprecated(decl.Doc) {
+				kind += "D"
+			}
+			result := []string{fmt.Sprintf("%d", dtype.Results.NumFields())}
+			for _, x := range sig.List {
+				// This code creates a string representing the type.
+				// TODO(pjw): it may be fragile:
+				// 1. x.Type could be nil, perhaps in ill-formed code
+				// 2. ExprString might someday change incompatibly to
+				//    include struct tags, which can be arbitrary strings
+				if x.Type == nil {
+					// Can this happen without a parse error? (Files with parse
+					// errors are ignored in getSymbols)
+					continue // maybe report this someday
+				}
+				tp := types.ExprString(x.Type)
+				if len(tp) == 0 {
+					// Can this happen?
+					continue // maybe report this someday
+				}
+				// This is only safe if ExprString never returns anything with a $
+				// The only place a $ can occur seems to be in a struct tag, which
+				// can be an arbitrary string literal, and ExprString does not presently
+				// print struct tags. So for this to happen the type of a formal parameter
+				// has to be a explict struct, e.g. foo(x struct{a int "$"}) and ExprString
+				// would have to show the struct tag. Even testing for this case seems
+				// a waste of effort, but let's remember the possibility
+				if strings.Contains(tp, "$") {
+					continue
+				}
+				tp = strings.Replace(tp, " ", "$", -1)
+				if len(x.Names) == 0 {
+					result = append(result, "_")
+					result = append(result, tp)
+				} else {
+					for _, y := range x.Names {
+						result = append(result, y.Name)
+						result = append(result, tp)
+					}
+				}
+			}
+			sigs := strings.Join(result, " ")
+			if s := newsym(pkg, name, kind, sigs); s != nil {
+				ans = append(ans, *s)
+			}
+		case *ast.GenDecl:
+			depr := isDeprecated(decl.Doc)
+			switch decl.Tok {
+			case token.CONST, token.VAR:
+				tp := "V"
+				if decl.Tok == token.CONST {
+					tp = "C"
+				}
+				if depr {
+					tp += "D"
+				}
+				for _, sp := range decl.Specs {
+					for _, x := range sp.(*ast.ValueSpec).Names {
+						if s := newsym(pkg, x.Name, tp, ""); s != nil {
+							ans = append(ans, *s)
+						}
+					}
+				}
+			case token.TYPE:
+				tp := "T"
+				if depr {
+					tp += "D"
+				}
+				for _, sp := range decl.Specs {
+					if s := newsym(pkg, sp.(*ast.TypeSpec).Name.Name, tp, ""); s != nil {
+						ans = append(ans, *s)
+					}
+				}
+			}
+		}
+	}
+	return ans
+}
+
+func newsym(pkg, name, kind, sig string) *symbol {
+	if len(name) == 0 || !ast.IsExported(name) {
+		return nil
+	}
+	sym := symbol{pkg: pkg, name: name, kind: kind, sig: sig}
+	return &sym
+}
+
+func isDeprecated(doc *ast.CommentGroup) bool {
+	if doc == nil {
+		return false
+	}
+	// go.dev/wiki/Deprecated Paragraph starting 'Deprecated:'
+	// This code fails for /* Deprecated: */, but it's the code from
+	// gopls/internal/analysis/deprecated
+	lines := strings.Split(doc.Text(), "\n\n")
+	for _, line := range lines {
+		if strings.HasPrefix(line, "Deprecated:") {
+			return true
+		}
+	}
+	return false
+}
+
+// return the package name and the value for the symbols.
+// if there are multiple packages, choose one arbitrarily
+// the returned slice is sorted lexicographically
+func processSyms(syms []symbol) (string, []string) {
+	if len(syms) == 0 {
+		return "", nil
+	}
+	slices.SortFunc(syms, func(l, r symbol) int {
+		return strings.Compare(l.name, r.name)
+	})
+	pkg := syms[0].pkg
+	var names []string
+	for _, s := range syms {
+		var nx string
+		if s.pkg == pkg {
+			if s.sig != "" {
+				nx = fmt.Sprintf("%s %s %s", s.name, s.kind, s.sig)
+			} else {
+				nx = fmt.Sprintf("%s %s", s.name, s.kind)
+			}
+			names = append(names, nx)
+		} else {
+			continue // PJW: do we want to keep track of these?
+		}
+	}
+	return pkg, names
+}
diff --git a/vendor/golang.org/x/tools/internal/modindex/types.go b/vendor/golang.org/x/tools/internal/modindex/types.go
new file mode 100644
index 0000000000..ece4488630
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/modindex/types.go
@@ -0,0 +1,25 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modindex
+
+import (
+	"strings"
+)
+
+// some special types to avoid confusions
+
+// distinguish various types of directory names. It's easy to get confused.
+type Abspath string // absolute paths
+type Relpath string // paths with GOMODCACHE prefix removed
+
+func toRelpath(cachedir Abspath, s string) Relpath {
+	if strings.HasPrefix(s, string(cachedir)) {
+		if s == string(cachedir) {
+			return Relpath("")
+		}
+		return Relpath(s[len(cachedir)+1:])
+	}
+	return Relpath(s)
+}
diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
index 44719de173..784605914e 100644
--- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
+++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
@@ -5,8 +5,7 @@
 // Package packagesinternal exposes internal-only fields from go/packages.
 package packagesinternal
 
-var GetForTest = func(p interface{}) string { return "" }
-var GetDepsErrors = func(p interface{}) []*PackageError { return nil }
+var GetDepsErrors = func(p any) []*PackageError { return nil }
 
 type PackageError struct {
 	ImportStack []string // shortest path from package named on command line to this one
@@ -16,7 +15,6 @@ type PackageError struct {
 
 var TypecheckCgo int
 var DepsErrors int // must be set as a LoadMode to call GetDepsErrors
-var ForTest int    // must be set as a LoadMode to call GetForTest
 
-var SetModFlag = func(config interface{}, value string) {}
+var SetModFlag = func(config any, value string) {}
 var SetModFile = func(config interface{}, value string) {}
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/decoder.go b/vendor/golang.org/x/tools/internal/pkgbits/decoder.go
index b92e8e6eb3..f6cb37c5c3 100644
--- a/vendor/golang.org/x/tools/internal/pkgbits/decoder.go
+++ b/vendor/golang.org/x/tools/internal/pkgbits/decoder.go
@@ -21,7 +21,7 @@ import (
 // export data.
 type PkgDecoder struct {
 	// version is the file format version.
-	version uint32
+	version Version
 
 	// sync indicates whether the file uses sync markers.
 	sync bool
@@ -68,8 +68,6 @@ func (pr *PkgDecoder) SyncMarkers() bool { return pr.sync }
 // NewPkgDecoder returns a PkgDecoder initialized to read the Unified
 // IR export data from input. pkgPath is the package path for the
 // compilation unit that produced the export data.
-//
-// TODO(mdempsky): Remove pkgPath parameter; unneeded since CL 391014.
 func NewPkgDecoder(pkgPath, input string) PkgDecoder {
 	pr := PkgDecoder{
 		pkgPath: pkgPath,
@@ -80,14 +78,15 @@ func NewPkgDecoder(pkgPath, input string) PkgDecoder {
 
 	r := strings.NewReader(input)
 
-	assert(binary.Read(r, binary.LittleEndian, &pr.version) == nil)
+	var ver uint32
+	assert(binary.Read(r, binary.LittleEndian, &ver) == nil)
+	pr.version = Version(ver)
 
-	switch pr.version {
-	default:
-		panic(fmt.Errorf("unsupported version: %v", pr.version))
-	case 0:
-		// no flags
-	case 1:
+	if pr.version >= numVersions {
+		panic(fmt.Errorf("cannot decode %q, export data version %d is greater than maximum supported version %d", pkgPath, pr.version, numVersions-1))
+	}
+
+	if pr.version.Has(Flags) {
 		var flags uint32
 		assert(binary.Read(r, binary.LittleEndian, &flags) == nil)
 		pr.sync = flags&flagSyncMarkers != 0
@@ -102,7 +101,9 @@ func NewPkgDecoder(pkgPath, input string) PkgDecoder {
 	assert(err == nil)
 
 	pr.elemData = input[pos:]
-	assert(len(pr.elemData)-8 == int(pr.elemEnds[len(pr.elemEnds)-1]))
+
+	const fingerprintSize = 8
+	assert(len(pr.elemData)-fingerprintSize == int(pr.elemEnds[len(pr.elemEnds)-1]))
 
 	return pr
 }
@@ -136,7 +137,7 @@ func (pr *PkgDecoder) AbsIdx(k RelocKind, idx Index) int {
 		absIdx += int(pr.elemEndsEnds[k-1])
 	}
 	if absIdx >= int(pr.elemEndsEnds[k]) {
-		errorf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds)
+		panicf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds)
 	}
 	return absIdx
 }
@@ -193,9 +194,7 @@ func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder {
 		Idx:    idx,
 	}
 
-	// TODO(mdempsky) r.data.Reset(...) after #44505 is resolved.
-	r.Data = *strings.NewReader(pr.DataIdx(k, idx))
-
+	r.Data.Reset(pr.DataIdx(k, idx))
 	r.Sync(SyncRelocs)
 	r.Relocs = make([]RelocEnt, r.Len())
 	for i := range r.Relocs {
@@ -244,7 +243,7 @@ type Decoder struct {
 
 func (r *Decoder) checkErr(err error) {
 	if err != nil {
-		errorf("unexpected decoding error: %w", err)
+		panicf("unexpected decoding error: %w", err)
 	}
 }
 
@@ -515,3 +514,6 @@ func (pr *PkgDecoder) PeekObj(idx Index) (string, string, CodeObj) {
 
 	return path, name, tag
 }
+
+// Version reports the version of the bitstream.
+func (w *Decoder) Version() Version { return w.common.version }
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/encoder.go b/vendor/golang.org/x/tools/internal/pkgbits/encoder.go
index 6482617a4f..c17a12399d 100644
--- a/vendor/golang.org/x/tools/internal/pkgbits/encoder.go
+++ b/vendor/golang.org/x/tools/internal/pkgbits/encoder.go
@@ -12,18 +12,15 @@ import (
 	"io"
 	"math/big"
 	"runtime"
+	"strings"
 )
 
-// currentVersion is the current version number.
-//
-//   - v0: initial prototype
-//
-//   - v1: adds the flags uint32 word
-const currentVersion uint32 = 1
-
 // A PkgEncoder provides methods for encoding a package's Unified IR
 // export data.
 type PkgEncoder struct {
+	// version of the bitstream.
+	version Version
+
 	// elems holds the bitstream for previously encoded elements.
 	elems [numRelocs][]string
 
@@ -47,8 +44,9 @@ func (pw *PkgEncoder) SyncMarkers() bool { return pw.syncFrames >= 0 }
 // export data files, but can help diagnosing desync errors in
 // higher-level Unified IR reader/writer code. If syncFrames is
 // negative, then sync markers are omitted entirely.
-func NewPkgEncoder(syncFrames int) PkgEncoder {
+func NewPkgEncoder(version Version, syncFrames int) PkgEncoder {
 	return PkgEncoder{
+		version:    version,
 		stringsIdx: make(map[string]Index),
 		syncFrames: syncFrames,
 	}
@@ -64,13 +62,15 @@ func (pw *PkgEncoder) DumpTo(out0 io.Writer) (fingerprint [8]byte) {
 		assert(binary.Write(out, binary.LittleEndian, x) == nil)
 	}
 
-	writeUint32(currentVersion)
+	writeUint32(uint32(pw.version))
 
-	var flags uint32
-	if pw.SyncMarkers() {
-		flags |= flagSyncMarkers
+	if pw.version.Has(Flags) {
+		var flags uint32
+		if pw.SyncMarkers() {
+			flags |= flagSyncMarkers
+		}
+		writeUint32(flags)
 	}
-	writeUint32(flags)
 
 	// Write elemEndsEnds.
 	var sum uint32
@@ -159,7 +159,7 @@ type Encoder struct {
 
 // Flush finalizes the element's bitstream and returns its Index.
 func (w *Encoder) Flush() Index {
-	var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved
+	var sb strings.Builder
 
 	// Backup the data so we write the relocations at the front.
 	var tmp bytes.Buffer
@@ -189,7 +189,7 @@ func (w *Encoder) Flush() Index {
 
 func (w *Encoder) checkErr(err error) {
 	if err != nil {
-		errorf("unexpected encoding error: %v", err)
+		panicf("unexpected encoding error: %v", err)
 	}
 }
 
@@ -320,8 +320,14 @@ func (w *Encoder) Code(c Code) {
 // section (if not already present), and then writing a relocation
 // into the element bitstream.
 func (w *Encoder) String(s string) {
+	w.StringRef(w.p.StringIdx(s))
+}
+
+// StringRef writes a reference to the given index, which must be a
+// previously encoded string value.
+func (w *Encoder) StringRef(idx Index) {
 	w.Sync(SyncString)
-	w.Reloc(RelocString, w.p.StringIdx(s))
+	w.Reloc(RelocString, idx)
 }
 
 // Strings encodes and writes a variable-length slice of strings into
@@ -348,7 +354,7 @@ func (w *Encoder) Value(val constant.Value) {
 func (w *Encoder) scalar(val constant.Value) {
 	switch v := constant.Val(val).(type) {
 	default:
-		errorf("unhandled %v (%v)", val, val.Kind())
+		panicf("unhandled %v (%v)", val, val.Kind())
 	case bool:
 		w.Code(ValBool)
 		w.Bool(v)
@@ -381,3 +387,6 @@ func (w *Encoder) bigFloat(v *big.Float) {
 	b := v.Append(nil, 'p', -1)
 	w.String(string(b)) // TODO: More efficient encoding.
 }
+
+// Version reports the version of the bitstream.
+func (w *Encoder) Version() Version { return w.p.version }
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go b/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go
deleted file mode 100644
index 5294f6a63e..0000000000
--- a/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.7
-// +build !go1.7
-
-// TODO(mdempsky): Remove after #44505 is resolved
-
-package pkgbits
-
-import "runtime"
-
-func walkFrames(pcs []uintptr, visit frameVisitor) {
-	for _, pc := range pcs {
-		fn := runtime.FuncForPC(pc)
-		file, line := fn.FileLine(pc)
-
-		visit(file, line, fn.Name(), pc-fn.Entry())
-	}
-}
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go b/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go
deleted file mode 100644
index 2324ae7adf..0000000000
--- a/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.7
-// +build go1.7
-
-package pkgbits
-
-import "runtime"
-
-// walkFrames calls visit for each call frame represented by pcs.
-//
-// pcs should be a slice of PCs, as returned by runtime.Callers.
-func walkFrames(pcs []uintptr, visit frameVisitor) {
-	if len(pcs) == 0 {
-		return
-	}
-
-	frames := runtime.CallersFrames(pcs)
-	for {
-		frame, more := frames.Next()
-		visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry)
-		if !more {
-			return
-		}
-	}
-}
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/support.go b/vendor/golang.org/x/tools/internal/pkgbits/support.go
index ad26d3b28c..50534a2955 100644
--- a/vendor/golang.org/x/tools/internal/pkgbits/support.go
+++ b/vendor/golang.org/x/tools/internal/pkgbits/support.go
@@ -12,6 +12,6 @@ func assert(b bool) {
 	}
 }
 
-func errorf(format string, args ...interface{}) {
+func panicf(format string, args ...any) {
 	panic(fmt.Errorf(format, args...))
 }
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/sync.go b/vendor/golang.org/x/tools/internal/pkgbits/sync.go
index 5bd51ef717..1520b73afb 100644
--- a/vendor/golang.org/x/tools/internal/pkgbits/sync.go
+++ b/vendor/golang.org/x/tools/internal/pkgbits/sync.go
@@ -6,6 +6,7 @@ package pkgbits
 
 import (
 	"fmt"
+	"runtime"
 	"strings"
 )
 
@@ -23,6 +24,24 @@ func fmtFrames(pcs ...uintptr) []string {
 
 type frameVisitor func(file string, line int, name string, offset uintptr)
 
+// walkFrames calls visit for each call frame represented by pcs.
+//
+// pcs should be a slice of PCs, as returned by runtime.Callers.
+func walkFrames(pcs []uintptr, visit frameVisitor) {
+	if len(pcs) == 0 {
+		return
+	}
+
+	frames := runtime.CallersFrames(pcs)
+	for {
+		frame, more := frames.Next()
+		visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry)
+		if !more {
+			return
+		}
+	}
+}
+
 // SyncMarker is an enum type that represents markers that may be
 // written to export data to ensure the reader and writer stay
 // synchronized.
@@ -110,4 +129,8 @@ const (
 	SyncStmtsEnd
 	SyncLabel
 	SyncOptLabel
+
+	SyncMultiExpr
+	SyncRType
+	SyncConvRTTI
 )
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go b/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go
index 4a5b0ca5f2..582ad56d3e 100644
--- a/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go
+++ b/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go
@@ -74,11 +74,14 @@ func _() {
 	_ = x[SyncStmtsEnd-64]
 	_ = x[SyncLabel-65]
 	_ = x[SyncOptLabel-66]
+	_ = x[SyncMultiExpr-67]
+	_ = x[SyncRType-68]
+	_ = x[SyncConvRTTI-69]
 }
 
-const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabel"
+const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabelMultiExprRTypeConvRTTI"
 
-var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458}
+var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458, 467, 472, 480}
 
 func (i SyncMarker) String() string {
 	i -= 1
diff --git a/vendor/golang.org/x/tools/internal/pkgbits/version.go b/vendor/golang.org/x/tools/internal/pkgbits/version.go
new file mode 100644
index 0000000000..53af9df22b
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/pkgbits/version.go
@@ -0,0 +1,85 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkgbits
+
+// Version indicates a version of a unified IR bitstream.
+// Each Version indicates the addition, removal, or change of
+// new data in the bitstream.
+//
+// These are serialized to disk and the interpretation remains fixed.
+type Version uint32
+
+const (
+	// V0: initial prototype.
+	//
+	// All data that is not assigned a Field is in version V0
+	// and has not been deprecated.
+	V0 Version = iota
+
+	// V1: adds the Flags uint32 word
+	V1
+
+	// V2: removes unused legacy fields and supports type parameters for aliases.
+	// - remove the legacy "has init" bool from the public root
+	// - remove obj's "derived func instance" bool
+	// - add a TypeParamNames field to ObjAlias
+	// - remove derived info "needed" bool
+	V2
+
+	numVersions = iota
+)
+
+// Field denotes a unit of data in the serialized unified IR bitstream.
+// It is conceptually a like field in a structure.
+//
+// We only really need Fields when the data may or may not be present
+// in a stream based on the Version of the bitstream.
+//
+// Unlike much of pkgbits, Fields are not serialized and
+// can change values as needed.
+type Field int
+
+const (
+	// Flags in a uint32 in the header of a bitstream
+	// that is used to indicate whether optional features are enabled.
+	Flags Field = iota
+
+	// Deprecated: HasInit was a bool indicating whether a package
+	// has any init functions.
+	HasInit
+
+	// Deprecated: DerivedFuncInstance was a bool indicating
+	// whether an object was a function instance.
+	DerivedFuncInstance
+
+	// ObjAlias has a list of TypeParamNames.
+	AliasTypeParamNames
+
+	// Deprecated: DerivedInfoNeeded was a bool indicating
+	// whether a type was a derived type.
+	DerivedInfoNeeded
+
+	numFields = iota
+)
+
+// introduced is the version a field was added.
+var introduced = [numFields]Version{
+	Flags:               V1,
+	AliasTypeParamNames: V2,
+}
+
+// removed is the version a field was removed in or 0 for fields
+// that have not yet been deprecated.
+// (So removed[f]-1 is the last version it is included in.)
+var removed = [numFields]Version{
+	HasInit:             V2,
+	DerivedFuncInstance: V2,
+	DerivedInfoNeeded:   V2,
+}
+
+// Has reports whether field f is present in a bitstream at version v.
+func (v Version) Has(f Field) bool {
+	return introduced[f] <= v && (v < removed[f] || removed[f] == V0)
+}
diff --git a/vendor/golang.org/x/tools/internal/robustio/gopls_windows.go b/vendor/golang.org/x/tools/internal/robustio/gopls_windows.go
deleted file mode 100644
index 949f278161..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/gopls_windows.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package robustio
-
-import "syscall"
-
-// The robustio package is copied from cmd/go/internal/robustio, a package used
-// by the go command to retry known flaky operations on certain operating systems.
-
-//go:generate go run copyfiles.go
-
-// Since the gopls module cannot access internal/syscall/windows, copy a
-// necessary constant.
-const ERROR_SHARING_VIOLATION syscall.Errno = 32
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio.go b/vendor/golang.org/x/tools/internal/robustio/robustio.go
deleted file mode 100644
index 0a559fc9b8..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package robustio wraps I/O functions that are prone to failure on Windows,
-// transparently retrying errors up to an arbitrary timeout.
-//
-// Errors are classified heuristically and retries are bounded, so the functions
-// in this package do not completely eliminate spurious errors. However, they do
-// significantly reduce the rate of failure in practice.
-//
-// If so, the error will likely wrap one of:
-// The functions in this package do not completely eliminate spurious errors,
-// but substantially reduce their rate of occurrence in practice.
-package robustio
-
-import "time"
-
-// Rename is like os.Rename, but on Windows retries errors that may occur if the
-// file is concurrently read or overwritten.
-//
-// (See golang.org/issue/31247 and golang.org/issue/32188.)
-func Rename(oldpath, newpath string) error {
-	return rename(oldpath, newpath)
-}
-
-// ReadFile is like os.ReadFile, but on Windows retries errors that may
-// occur if the file is concurrently replaced.
-//
-// (See golang.org/issue/31247 and golang.org/issue/32188.)
-func ReadFile(filename string) ([]byte, error) {
-	return readFile(filename)
-}
-
-// RemoveAll is like os.RemoveAll, but on Windows retries errors that may occur
-// if an executable file in the directory has recently been executed.
-//
-// (See golang.org/issue/19491.)
-func RemoveAll(path string) error {
-	return removeAll(path)
-}
-
-// IsEphemeralError reports whether err is one of the errors that the functions
-// in this package attempt to mitigate.
-//
-// Errors considered ephemeral include:
-//   - syscall.ERROR_ACCESS_DENIED
-//   - syscall.ERROR_FILE_NOT_FOUND
-//   - internal/syscall/windows.ERROR_SHARING_VIOLATION
-//
-// This set may be expanded in the future; programs must not rely on the
-// non-ephemerality of any given error.
-func IsEphemeralError(err error) bool {
-	return isEphemeralError(err)
-}
-
-// A FileID uniquely identifies a file in the file system.
-//
-// If GetFileID(name1) returns the same ID as GetFileID(name2), the two file
-// names denote the same file.
-// A FileID is comparable, and thus suitable for use as a map key.
-type FileID struct {
-	device, inode uint64
-}
-
-// GetFileID returns the file system's identifier for the file, and its
-// modification time.
-// Like os.Stat, it reads through symbolic links.
-func GetFileID(filename string) (FileID, time.Time, error) { return getFileID(filename) }
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio_darwin.go b/vendor/golang.org/x/tools/internal/robustio/robustio_darwin.go
deleted file mode 100644
index 99fd8ebc2f..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio_darwin.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package robustio
-
-import (
-	"errors"
-	"syscall"
-)
-
-const errFileNotFound = syscall.ENOENT
-
-// isEphemeralError returns true if err may be resolved by waiting.
-func isEphemeralError(err error) bool {
-	var errno syscall.Errno
-	if errors.As(err, &errno) {
-		return errno == errFileNotFound
-	}
-	return false
-}
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio_flaky.go b/vendor/golang.org/x/tools/internal/robustio/robustio_flaky.go
deleted file mode 100644
index d5c241857b..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio_flaky.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build windows || darwin
-// +build windows darwin
-
-package robustio
-
-import (
-	"errors"
-	"math/rand"
-	"os"
-	"syscall"
-	"time"
-)
-
-const arbitraryTimeout = 2000 * time.Millisecond
-
-// retry retries ephemeral errors from f up to an arbitrary timeout
-// to work around filesystem flakiness on Windows and Darwin.
-func retry(f func() (err error, mayRetry bool)) error {
-	var (
-		bestErr     error
-		lowestErrno syscall.Errno
-		start       time.Time
-		nextSleep   time.Duration = 1 * time.Millisecond
-	)
-	for {
-		err, mayRetry := f()
-		if err == nil || !mayRetry {
-			return err
-		}
-
-		var errno syscall.Errno
-		if errors.As(err, &errno) && (lowestErrno == 0 || errno < lowestErrno) {
-			bestErr = err
-			lowestErrno = errno
-		} else if bestErr == nil {
-			bestErr = err
-		}
-
-		if start.IsZero() {
-			start = time.Now()
-		} else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
-			break
-		}
-		time.Sleep(nextSleep)
-		nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
-	}
-
-	return bestErr
-}
-
-// rename is like os.Rename, but retries ephemeral errors.
-//
-// On Windows it wraps os.Rename, which (as of 2019-06-04) uses MoveFileEx with
-// MOVEFILE_REPLACE_EXISTING.
-//
-// Windows also provides a different system call, ReplaceFile,
-// that provides similar semantics, but perhaps preserves more metadata. (The
-// documentation on the differences between the two is very sparse.)
-//
-// Empirical error rates with MoveFileEx are lower under modest concurrency, so
-// for now we're sticking with what the os package already provides.
-func rename(oldpath, newpath string) (err error) {
-	return retry(func() (err error, mayRetry bool) {
-		err = os.Rename(oldpath, newpath)
-		return err, isEphemeralError(err)
-	})
-}
-
-// readFile is like os.ReadFile, but retries ephemeral errors.
-func readFile(filename string) ([]byte, error) {
-	var b []byte
-	err := retry(func() (err error, mayRetry bool) {
-		b, err = os.ReadFile(filename)
-
-		// Unlike in rename, we do not retry errFileNotFound here: it can occur
-		// as a spurious error, but the file may also genuinely not exist, so the
-		// increase in robustness is probably not worth the extra latency.
-		return err, isEphemeralError(err) && !errors.Is(err, errFileNotFound)
-	})
-	return b, err
-}
-
-func removeAll(path string) error {
-	return retry(func() (err error, mayRetry bool) {
-		err = os.RemoveAll(path)
-		return err, isEphemeralError(err)
-	})
-}
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio_other.go b/vendor/golang.org/x/tools/internal/robustio/robustio_other.go
deleted file mode 100644
index 3a20cac6cf..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio_other.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !windows && !darwin
-// +build !windows,!darwin
-
-package robustio
-
-import (
-	"os"
-)
-
-func rename(oldpath, newpath string) error {
-	return os.Rename(oldpath, newpath)
-}
-
-func readFile(filename string) ([]byte, error) {
-	return os.ReadFile(filename)
-}
-
-func removeAll(path string) error {
-	return os.RemoveAll(path)
-}
-
-func isEphemeralError(err error) bool {
-	return false
-}
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio_plan9.go b/vendor/golang.org/x/tools/internal/robustio/robustio_plan9.go
deleted file mode 100644
index 9fa4cacb5a..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio_plan9.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build plan9
-// +build plan9
-
-package robustio
-
-import (
-	"os"
-	"syscall"
-	"time"
-)
-
-func getFileID(filename string) (FileID, time.Time, error) {
-	fi, err := os.Stat(filename)
-	if err != nil {
-		return FileID{}, time.Time{}, err
-	}
-	dir := fi.Sys().(*syscall.Dir)
-	return FileID{
-		device: uint64(dir.Type)<<32 | uint64(dir.Dev),
-		inode:  dir.Qid.Path,
-	}, fi.ModTime(), nil
-}
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio_posix.go b/vendor/golang.org/x/tools/internal/robustio/robustio_posix.go
deleted file mode 100644
index cf74865d0b..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio_posix.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !windows && !plan9
-// +build !windows,!plan9
-
-package robustio
-
-import (
-	"os"
-	"syscall"
-	"time"
-)
-
-func getFileID(filename string) (FileID, time.Time, error) {
-	fi, err := os.Stat(filename)
-	if err != nil {
-		return FileID{}, time.Time{}, err
-	}
-	stat := fi.Sys().(*syscall.Stat_t)
-	return FileID{
-		device: uint64(stat.Dev), // (int32 on darwin, uint64 on linux)
-		inode:  stat.Ino,
-	}, fi.ModTime(), nil
-}
diff --git a/vendor/golang.org/x/tools/internal/robustio/robustio_windows.go b/vendor/golang.org/x/tools/internal/robustio/robustio_windows.go
deleted file mode 100644
index 616c32883d..0000000000
--- a/vendor/golang.org/x/tools/internal/robustio/robustio_windows.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package robustio
-
-import (
-	"errors"
-	"syscall"
-	"time"
-)
-
-const errFileNotFound = syscall.ERROR_FILE_NOT_FOUND
-
-// isEphemeralError returns true if err may be resolved by waiting.
-func isEphemeralError(err error) bool {
-	var errno syscall.Errno
-	if errors.As(err, &errno) {
-		switch errno {
-		case syscall.ERROR_ACCESS_DENIED,
-			syscall.ERROR_FILE_NOT_FOUND,
-			ERROR_SHARING_VIOLATION:
-			return true
-		}
-	}
-	return false
-}
-
-// Note: it may be convenient to have this helper return fs.FileInfo, but
-// implementing this is actually quite involved on Windows. Since we only
-// currently use mtime, keep it simple.
-func getFileID(filename string) (FileID, time.Time, error) {
-	filename16, err := syscall.UTF16PtrFromString(filename)
-	if err != nil {
-		return FileID{}, time.Time{}, err
-	}
-	h, err := syscall.CreateFile(filename16, 0, 0, nil, syscall.OPEN_EXISTING, uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS), 0)
-	if err != nil {
-		return FileID{}, time.Time{}, err
-	}
-	defer syscall.CloseHandle(h)
-	var i syscall.ByHandleFileInformation
-	if err := syscall.GetFileInformationByHandle(h, &i); err != nil {
-		return FileID{}, time.Time{}, err
-	}
-	mtime := time.Unix(0, i.LastWriteTime.Nanoseconds())
-	return FileID{
-		device: uint64(i.VolumeSerialNumber),
-		inode:  uint64(i.FileIndexHigh)<<32 | uint64(i.FileIndexLow),
-	}, mtime, nil
-}
diff --git a/vendor/golang.org/x/tools/internal/stdlib/manifest.go b/vendor/golang.org/x/tools/internal/stdlib/manifest.go
index a928acf29f..9f0b871ff6 100644
--- a/vendor/golang.org/x/tools/internal/stdlib/manifest.go
+++ b/vendor/golang.org/x/tools/internal/stdlib/manifest.go
@@ -268,6 +268,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"ErrTooLarge", Var, 0},
 		{"Fields", Func, 0},
 		{"FieldsFunc", Func, 0},
+		{"FieldsFuncSeq", Func, 24},
+		{"FieldsSeq", Func, 24},
 		{"HasPrefix", Func, 0},
 		{"HasSuffix", Func, 0},
 		{"Index", Func, 0},
@@ -280,6 +282,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"LastIndexAny", Func, 0},
 		{"LastIndexByte", Func, 5},
 		{"LastIndexFunc", Func, 0},
+		{"Lines", Func, 24},
 		{"Map", Func, 0},
 		{"MinRead", Const, 0},
 		{"NewBuffer", Func, 0},
@@ -293,7 +296,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"Split", Func, 0},
 		{"SplitAfter", Func, 0},
 		{"SplitAfterN", Func, 0},
+		{"SplitAfterSeq", Func, 24},
 		{"SplitN", Func, 0},
+		{"SplitSeq", Func, 24},
 		{"Title", Func, 0},
 		{"ToLower", Func, 0},
 		{"ToLowerSpecial", Func, 0},
@@ -535,6 +540,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"NewCTR", Func, 0},
 		{"NewGCM", Func, 2},
 		{"NewGCMWithNonceSize", Func, 5},
+		{"NewGCMWithRandomNonce", Func, 24},
 		{"NewGCMWithTagSize", Func, 11},
 		{"NewOFB", Func, 0},
 		{"Stream", Type, 0},
@@ -673,6 +679,14 @@ var PackageSymbols = map[string][]Symbol{
 		{"Unmarshal", Func, 0},
 		{"UnmarshalCompressed", Func, 15},
 	},
+	"crypto/fips140": {
+		{"Enabled", Func, 24},
+	},
+	"crypto/hkdf": {
+		{"Expand", Func, 24},
+		{"Extract", Func, 24},
+		{"Key", Func, 24},
+	},
 	"crypto/hmac": {
 		{"Equal", Func, 1},
 		{"New", Func, 0},
@@ -683,11 +697,43 @@ var PackageSymbols = map[string][]Symbol{
 		{"Size", Const, 0},
 		{"Sum", Func, 2},
 	},
+	"crypto/mlkem": {
+		{"(*DecapsulationKey1024).Bytes", Method, 24},
+		{"(*DecapsulationKey1024).Decapsulate", Method, 24},
+		{"(*DecapsulationKey1024).EncapsulationKey", Method, 24},
+		{"(*DecapsulationKey768).Bytes", Method, 24},
+		{"(*DecapsulationKey768).Decapsulate", Method, 24},
+		{"(*DecapsulationKey768).EncapsulationKey", Method, 24},
+		{"(*EncapsulationKey1024).Bytes", Method, 24},
+		{"(*EncapsulationKey1024).Encapsulate", Method, 24},
+		{"(*EncapsulationKey768).Bytes", Method, 24},
+		{"(*EncapsulationKey768).Encapsulate", Method, 24},
+		{"CiphertextSize1024", Const, 24},
+		{"CiphertextSize768", Const, 24},
+		{"DecapsulationKey1024", Type, 24},
+		{"DecapsulationKey768", Type, 24},
+		{"EncapsulationKey1024", Type, 24},
+		{"EncapsulationKey768", Type, 24},
+		{"EncapsulationKeySize1024", Const, 24},
+		{"EncapsulationKeySize768", Const, 24},
+		{"GenerateKey1024", Func, 24},
+		{"GenerateKey768", Func, 24},
+		{"NewDecapsulationKey1024", Func, 24},
+		{"NewDecapsulationKey768", Func, 24},
+		{"NewEncapsulationKey1024", Func, 24},
+		{"NewEncapsulationKey768", Func, 24},
+		{"SeedSize", Const, 24},
+		{"SharedKeySize", Const, 24},
+	},
+	"crypto/pbkdf2": {
+		{"Key", Func, 24},
+	},
 	"crypto/rand": {
 		{"Int", Func, 0},
 		{"Prime", Func, 0},
 		{"Read", Func, 0},
 		{"Reader", Var, 0},
+		{"Text", Func, 24},
 	},
 	"crypto/rc4": {
 		{"(*Cipher).Reset", Method, 0},
@@ -766,6 +812,39 @@ var PackageSymbols = map[string][]Symbol{
 		{"Sum224", Func, 2},
 		{"Sum256", Func, 2},
 	},
+	"crypto/sha3": {
+		{"(*SHA3).AppendBinary", Method, 24},
+		{"(*SHA3).BlockSize", Method, 24},
+		{"(*SHA3).MarshalBinary", Method, 24},
+		{"(*SHA3).Reset", Method, 24},
+		{"(*SHA3).Size", Method, 24},
+		{"(*SHA3).Sum", Method, 24},
+		{"(*SHA3).UnmarshalBinary", Method, 24},
+		{"(*SHA3).Write", Method, 24},
+		{"(*SHAKE).AppendBinary", Method, 24},
+		{"(*SHAKE).BlockSize", Method, 24},
+		{"(*SHAKE).MarshalBinary", Method, 24},
+		{"(*SHAKE).Read", Method, 24},
+		{"(*SHAKE).Reset", Method, 24},
+		{"(*SHAKE).UnmarshalBinary", Method, 24},
+		{"(*SHAKE).Write", Method, 24},
+		{"New224", Func, 24},
+		{"New256", Func, 24},
+		{"New384", Func, 24},
+		{"New512", Func, 24},
+		{"NewCSHAKE128", Func, 24},
+		{"NewCSHAKE256", Func, 24},
+		{"NewSHAKE128", Func, 24},
+		{"NewSHAKE256", Func, 24},
+		{"SHA3", Type, 24},
+		{"SHAKE", Type, 24},
+		{"Sum224", Func, 24},
+		{"Sum256", Func, 24},
+		{"Sum384", Func, 24},
+		{"Sum512", Func, 24},
+		{"SumSHAKE128", Func, 24},
+		{"SumSHAKE256", Func, 24},
+	},
 	"crypto/sha512": {
 		{"BlockSize", Const, 0},
 		{"New", Func, 0},
@@ -788,6 +867,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"ConstantTimeEq", Func, 0},
 		{"ConstantTimeLessOrEq", Func, 2},
 		{"ConstantTimeSelect", Func, 0},
+		{"WithDataIndependentTiming", Func, 24},
 		{"XORBytes", Func, 20},
 	},
 	"crypto/tls": {
@@ -864,6 +944,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"ClientHelloInfo", Type, 4},
 		{"ClientHelloInfo.CipherSuites", Field, 4},
 		{"ClientHelloInfo.Conn", Field, 8},
+		{"ClientHelloInfo.Extensions", Field, 24},
 		{"ClientHelloInfo.ServerName", Field, 4},
 		{"ClientHelloInfo.SignatureSchemes", Field, 8},
 		{"ClientHelloInfo.SupportedCurves", Field, 4},
@@ -881,6 +962,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"Config.CurvePreferences", Field, 3},
 		{"Config.DynamicRecordSizingDisabled", Field, 7},
 		{"Config.EncryptedClientHelloConfigList", Field, 23},
+		{"Config.EncryptedClientHelloKeys", Field, 24},
 		{"Config.EncryptedClientHelloRejectionVerify", Field, 23},
 		{"Config.GetCertificate", Field, 4},
 		{"Config.GetClientCertificate", Field, 8},
@@ -934,6 +1016,10 @@ var PackageSymbols = map[string][]Symbol{
 		{"ECHRejectionError", Type, 23},
 		{"ECHRejectionError.RetryConfigList", Field, 23},
 		{"Ed25519", Const, 13},
+		{"EncryptedClientHelloKey", Type, 24},
+		{"EncryptedClientHelloKey.Config", Field, 24},
+		{"EncryptedClientHelloKey.PrivateKey", Field, 24},
+		{"EncryptedClientHelloKey.SendAsRetry", Field, 24},
 		{"InsecureCipherSuites", Func, 14},
 		{"Listen", Func, 0},
 		{"LoadX509KeyPair", Func, 0},
@@ -951,7 +1037,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"ParseSessionState", Func, 21},
 		{"QUICClient", Func, 21},
 		{"QUICConfig", Type, 21},
-		{"QUICConfig.EnableStoreSessionEvent", Field, 23},
+		{"QUICConfig.EnableSessionEvents", Field, 23},
 		{"QUICConfig.TLSConfig", Field, 21},
 		{"QUICConn", Type, 21},
 		{"QUICEncryptionLevel", Type, 21},
@@ -1032,6 +1118,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"VersionTLS12", Const, 2},
 		{"VersionTLS13", Const, 12},
 		{"X25519", Const, 8},
+		{"X25519MLKEM768", Const, 24},
 		{"X509KeyPair", Func, 0},
 	},
 	"crypto/x509": {
@@ -1056,6 +1143,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"(ConstraintViolationError).Error", Method, 0},
 		{"(HostnameError).Error", Method, 0},
 		{"(InsecureAlgorithmError).Error", Method, 6},
+		{"(OID).AppendBinary", Method, 24},
+		{"(OID).AppendText", Method, 24},
 		{"(OID).Equal", Method, 22},
 		{"(OID).EqualASN1OID", Method, 22},
 		{"(OID).MarshalBinary", Method, 23},
@@ -1084,6 +1173,10 @@ var PackageSymbols = map[string][]Symbol{
 		{"Certificate.Extensions", Field, 2},
 		{"Certificate.ExtraExtensions", Field, 2},
 		{"Certificate.IPAddresses", Field, 1},
+		{"Certificate.InhibitAnyPolicy", Field, 24},
+		{"Certificate.InhibitAnyPolicyZero", Field, 24},
+		{"Certificate.InhibitPolicyMapping", Field, 24},
+		{"Certificate.InhibitPolicyMappingZero", Field, 24},
 		{"Certificate.IsCA", Field, 0},
 		{"Certificate.Issuer", Field, 0},
 		{"Certificate.IssuingCertificateURL", Field, 2},
@@ -1100,6 +1193,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"Certificate.PermittedURIDomains", Field, 10},
 		{"Certificate.Policies", Field, 22},
 		{"Certificate.PolicyIdentifiers", Field, 0},
+		{"Certificate.PolicyMappings", Field, 24},
 		{"Certificate.PublicKey", Field, 0},
 		{"Certificate.PublicKeyAlgorithm", Field, 0},
 		{"Certificate.Raw", Field, 0},
@@ -1107,6 +1201,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"Certificate.RawSubject", Field, 0},
 		{"Certificate.RawSubjectPublicKeyInfo", Field, 0},
 		{"Certificate.RawTBSCertificate", Field, 0},
+		{"Certificate.RequireExplicitPolicy", Field, 24},
+		{"Certificate.RequireExplicitPolicyZero", Field, 24},
 		{"Certificate.SerialNumber", Field, 0},
 		{"Certificate.Signature", Field, 0},
 		{"Certificate.SignatureAlgorithm", Field, 0},
@@ -1198,6 +1294,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"NameConstraintsWithoutSANs", Const, 10},
 		{"NameMismatch", Const, 8},
 		{"NewCertPool", Func, 0},
+		{"NoValidChains", Const, 24},
 		{"NotAuthorizedToSign", Const, 0},
 		{"OID", Type, 22},
 		{"OIDFromInts", Func, 22},
@@ -1219,6 +1316,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"ParsePKCS8PrivateKey", Func, 0},
 		{"ParsePKIXPublicKey", Func, 0},
 		{"ParseRevocationList", Func, 19},
+		{"PolicyMapping", Type, 24},
+		{"PolicyMapping.IssuerDomainPolicy", Field, 24},
+		{"PolicyMapping.SubjectDomainPolicy", Field, 24},
 		{"PublicKeyAlgorithm", Type, 0},
 		{"PureEd25519", Const, 13},
 		{"RSA", Const, 0},
@@ -1265,6 +1365,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"UnknownPublicKeyAlgorithm", Const, 0},
 		{"UnknownSignatureAlgorithm", Const, 0},
 		{"VerifyOptions", Type, 0},
+		{"VerifyOptions.CertificatePolicies", Field, 24},
 		{"VerifyOptions.CurrentTime", Field, 0},
 		{"VerifyOptions.DNSName", Field, 0},
 		{"VerifyOptions.Intermediates", Field, 0},
@@ -1975,6 +2076,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*File).DynString", Method, 1},
 		{"(*File).DynValue", Method, 21},
 		{"(*File).DynamicSymbols", Method, 4},
+		{"(*File).DynamicVersionNeeds", Method, 24},
+		{"(*File).DynamicVersions", Method, 24},
 		{"(*File).ImportedLibraries", Method, 0},
 		{"(*File).ImportedSymbols", Method, 0},
 		{"(*File).Section", Method, 0},
@@ -2240,6 +2343,19 @@ var PackageSymbols = map[string][]Symbol{
 		{"DynFlag", Type, 0},
 		{"DynFlag1", Type, 21},
 		{"DynTag", Type, 0},
+		{"DynamicVersion", Type, 24},
+		{"DynamicVersion.Deps", Field, 24},
+		{"DynamicVersion.Flags", Field, 24},
+		{"DynamicVersion.Index", Field, 24},
+		{"DynamicVersion.Name", Field, 24},
+		{"DynamicVersionDep", Type, 24},
+		{"DynamicVersionDep.Dep", Field, 24},
+		{"DynamicVersionDep.Flags", Field, 24},
+		{"DynamicVersionDep.Index", Field, 24},
+		{"DynamicVersionFlag", Type, 24},
+		{"DynamicVersionNeed", Type, 24},
+		{"DynamicVersionNeed.Name", Field, 24},
+		{"DynamicVersionNeed.Needs", Field, 24},
 		{"EI_ABIVERSION", Const, 0},
 		{"EI_CLASS", Const, 0},
 		{"EI_DATA", Const, 0},
@@ -3726,8 +3842,19 @@ var PackageSymbols = map[string][]Symbol{
 		{"Symbol.Size", Field, 0},
 		{"Symbol.Value", Field, 0},
 		{"Symbol.Version", Field, 13},
+		{"Symbol.VersionIndex", Field, 24},
+		{"Symbol.VersionScope", Field, 24},
+		{"SymbolVersionScope", Type, 24},
 		{"Type", Type, 0},
+		{"VER_FLG_BASE", Const, 24},
+		{"VER_FLG_INFO", Const, 24},
+		{"VER_FLG_WEAK", Const, 24},
 		{"Version", Type, 0},
+		{"VersionScopeGlobal", Const, 24},
+		{"VersionScopeHidden", Const, 24},
+		{"VersionScopeLocal", Const, 24},
+		{"VersionScopeNone", Const, 24},
+		{"VersionScopeSpecific", Const, 24},
 	},
 	"debug/gosym": {
 		{"(*DecodingError).Error", Method, 0},
@@ -4453,8 +4580,10 @@ var PackageSymbols = map[string][]Symbol{
 		{"FS", Type, 16},
 	},
 	"encoding": {
+		{"BinaryAppender", Type, 24},
 		{"BinaryMarshaler", Type, 2},
 		{"BinaryUnmarshaler", Type, 2},
+		{"TextAppender", Type, 24},
 		{"TextMarshaler", Type, 2},
 		{"TextUnmarshaler", Type, 2},
 	},
@@ -5984,13 +6113,16 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Interface).Complete", Method, 5},
 		{"(*Interface).Embedded", Method, 5},
 		{"(*Interface).EmbeddedType", Method, 11},
+		{"(*Interface).EmbeddedTypes", Method, 24},
 		{"(*Interface).Empty", Method, 5},
 		{"(*Interface).ExplicitMethod", Method, 5},
+		{"(*Interface).ExplicitMethods", Method, 24},
 		{"(*Interface).IsComparable", Method, 18},
 		{"(*Interface).IsImplicit", Method, 18},
 		{"(*Interface).IsMethodSet", Method, 18},
 		{"(*Interface).MarkImplicit", Method, 18},
 		{"(*Interface).Method", Method, 5},
+		{"(*Interface).Methods", Method, 24},
 		{"(*Interface).NumEmbeddeds", Method, 5},
 		{"(*Interface).NumExplicitMethods", Method, 5},
 		{"(*Interface).NumMethods", Method, 5},
@@ -6011,9 +6143,11 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*MethodSet).At", Method, 5},
 		{"(*MethodSet).Len", Method, 5},
 		{"(*MethodSet).Lookup", Method, 5},
+		{"(*MethodSet).Methods", Method, 24},
 		{"(*MethodSet).String", Method, 5},
 		{"(*Named).AddMethod", Method, 5},
 		{"(*Named).Method", Method, 5},
+		{"(*Named).Methods", Method, 24},
 		{"(*Named).NumMethods", Method, 5},
 		{"(*Named).Obj", Method, 5},
 		{"(*Named).Origin", Method, 18},
@@ -6054,6 +6188,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Pointer).String", Method, 5},
 		{"(*Pointer).Underlying", Method, 5},
 		{"(*Scope).Child", Method, 5},
+		{"(*Scope).Children", Method, 24},
 		{"(*Scope).Contains", Method, 5},
 		{"(*Scope).End", Method, 5},
 		{"(*Scope).Innermost", Method, 5},
@@ -6089,6 +6224,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*StdSizes).Offsetsof", Method, 5},
 		{"(*StdSizes).Sizeof", Method, 5},
 		{"(*Struct).Field", Method, 5},
+		{"(*Struct).Fields", Method, 24},
 		{"(*Struct).NumFields", Method, 5},
 		{"(*Struct).String", Method, 5},
 		{"(*Struct).Tag", Method, 5},
@@ -6100,8 +6236,10 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Tuple).Len", Method, 5},
 		{"(*Tuple).String", Method, 5},
 		{"(*Tuple).Underlying", Method, 5},
+		{"(*Tuple).Variables", Method, 24},
 		{"(*TypeList).At", Method, 18},
 		{"(*TypeList).Len", Method, 18},
+		{"(*TypeList).Types", Method, 24},
 		{"(*TypeName).Exported", Method, 5},
 		{"(*TypeName).Id", Method, 5},
 		{"(*TypeName).IsAlias", Method, 9},
@@ -6119,9 +6257,11 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*TypeParam).Underlying", Method, 18},
 		{"(*TypeParamList).At", Method, 18},
 		{"(*TypeParamList).Len", Method, 18},
+		{"(*TypeParamList).TypeParams", Method, 24},
 		{"(*Union).Len", Method, 18},
 		{"(*Union).String", Method, 18},
 		{"(*Union).Term", Method, 18},
+		{"(*Union).Terms", Method, 24},
 		{"(*Union).Underlying", Method, 18},
 		{"(*Var).Anonymous", Method, 5},
 		{"(*Var).Embedded", Method, 11},
@@ -6392,10 +6532,12 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Hash).WriteByte", Method, 14},
 		{"(*Hash).WriteString", Method, 14},
 		{"Bytes", Func, 19},
+		{"Comparable", Func, 24},
 		{"Hash", Type, 14},
 		{"MakeSeed", Func, 14},
 		{"Seed", Type, 14},
 		{"String", Func, 19},
+		{"WriteComparable", Func, 24},
 	},
 	"html": {
 		{"EscapeString", Func, 0},
@@ -7082,6 +7224,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*JSONHandler).WithGroup", Method, 21},
 		{"(*Level).UnmarshalJSON", Method, 21},
 		{"(*Level).UnmarshalText", Method, 21},
+		{"(*LevelVar).AppendText", Method, 24},
 		{"(*LevelVar).Level", Method, 21},
 		{"(*LevelVar).MarshalText", Method, 21},
 		{"(*LevelVar).Set", Method, 21},
@@ -7110,6 +7253,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(Attr).Equal", Method, 21},
 		{"(Attr).String", Method, 21},
 		{"(Kind).String", Method, 21},
+		{"(Level).AppendText", Method, 24},
 		{"(Level).Level", Method, 21},
 		{"(Level).MarshalJSON", Method, 21},
 		{"(Level).MarshalText", Method, 21},
@@ -7140,6 +7284,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"Debug", Func, 21},
 		{"DebugContext", Func, 21},
 		{"Default", Func, 21},
+		{"DiscardHandler", Var, 24},
 		{"Duration", Func, 21},
 		{"DurationValue", Func, 21},
 		{"Error", Func, 21},
@@ -7375,6 +7520,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Float).Acc", Method, 5},
 		{"(*Float).Add", Method, 5},
 		{"(*Float).Append", Method, 5},
+		{"(*Float).AppendText", Method, 24},
 		{"(*Float).Cmp", Method, 5},
 		{"(*Float).Copy", Method, 5},
 		{"(*Float).Float32", Method, 5},
@@ -7421,6 +7567,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Int).And", Method, 0},
 		{"(*Int).AndNot", Method, 0},
 		{"(*Int).Append", Method, 6},
+		{"(*Int).AppendText", Method, 24},
 		{"(*Int).Binomial", Method, 0},
 		{"(*Int).Bit", Method, 0},
 		{"(*Int).BitLen", Method, 0},
@@ -7477,6 +7624,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Int).Xor", Method, 0},
 		{"(*Rat).Abs", Method, 0},
 		{"(*Rat).Add", Method, 0},
+		{"(*Rat).AppendText", Method, 24},
 		{"(*Rat).Cmp", Method, 0},
 		{"(*Rat).Denom", Method, 0},
 		{"(*Rat).Float32", Method, 4},
@@ -7659,11 +7807,13 @@ var PackageSymbols = map[string][]Symbol{
 		{"Zipf", Type, 0},
 	},
 	"math/rand/v2": {
+		{"(*ChaCha8).AppendBinary", Method, 24},
 		{"(*ChaCha8).MarshalBinary", Method, 22},
 		{"(*ChaCha8).Read", Method, 23},
 		{"(*ChaCha8).Seed", Method, 22},
 		{"(*ChaCha8).Uint64", Method, 22},
 		{"(*ChaCha8).UnmarshalBinary", Method, 22},
+		{"(*PCG).AppendBinary", Method, 24},
 		{"(*PCG).MarshalBinary", Method, 22},
 		{"(*PCG).Seed", Method, 22},
 		{"(*PCG).Uint64", Method, 22},
@@ -7931,6 +8081,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*UnixListener).SyscallConn", Method, 10},
 		{"(Flags).String", Method, 0},
 		{"(HardwareAddr).String", Method, 0},
+		{"(IP).AppendText", Method, 24},
 		{"(IP).DefaultMask", Method, 0},
 		{"(IP).Equal", Method, 0},
 		{"(IP).IsGlobalUnicast", Method, 0},
@@ -8131,6 +8282,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*MaxBytesError).Error", Method, 19},
 		{"(*ProtocolError).Error", Method, 0},
 		{"(*ProtocolError).Is", Method, 21},
+		{"(*Protocols).SetHTTP1", Method, 24},
+		{"(*Protocols).SetHTTP2", Method, 24},
+		{"(*Protocols).SetUnencryptedHTTP2", Method, 24},
 		{"(*Request).AddCookie", Method, 0},
 		{"(*Request).BasicAuth", Method, 4},
 		{"(*Request).Clone", Method, 13},
@@ -8190,6 +8344,10 @@ var PackageSymbols = map[string][]Symbol{
 		{"(Header).Values", Method, 14},
 		{"(Header).Write", Method, 0},
 		{"(Header).WriteSubset", Method, 0},
+		{"(Protocols).HTTP1", Method, 24},
+		{"(Protocols).HTTP2", Method, 24},
+		{"(Protocols).String", Method, 24},
+		{"(Protocols).UnencryptedHTTP2", Method, 24},
 		{"AllowQuerySemicolons", Func, 17},
 		{"CanonicalHeaderKey", Func, 0},
 		{"Client", Type, 0},
@@ -8252,6 +8410,18 @@ var PackageSymbols = map[string][]Symbol{
 		{"FileSystem", Type, 0},
 		{"Flusher", Type, 0},
 		{"Get", Func, 0},
+		{"HTTP2Config", Type, 24},
+		{"HTTP2Config.CountError", Field, 24},
+		{"HTTP2Config.MaxConcurrentStreams", Field, 24},
+		{"HTTP2Config.MaxDecoderHeaderTableSize", Field, 24},
+		{"HTTP2Config.MaxEncoderHeaderTableSize", Field, 24},
+		{"HTTP2Config.MaxReadFrameSize", Field, 24},
+		{"HTTP2Config.MaxReceiveBufferPerConnection", Field, 24},
+		{"HTTP2Config.MaxReceiveBufferPerStream", Field, 24},
+		{"HTTP2Config.PermitProhibitedCipherSuites", Field, 24},
+		{"HTTP2Config.PingTimeout", Field, 24},
+		{"HTTP2Config.SendPingTimeout", Field, 24},
+		{"HTTP2Config.WriteByteTimeout", Field, 24},
 		{"Handle", Func, 0},
 		{"HandleFunc", Func, 0},
 		{"Handler", Type, 0},
@@ -8292,6 +8462,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"PostForm", Func, 0},
 		{"ProtocolError", Type, 0},
 		{"ProtocolError.ErrorString", Field, 0},
+		{"Protocols", Type, 24},
 		{"ProxyFromEnvironment", Func, 0},
 		{"ProxyURL", Func, 0},
 		{"PushOptions", Type, 8},
@@ -8361,9 +8532,11 @@ var PackageSymbols = map[string][]Symbol{
 		{"Server.ConnState", Field, 3},
 		{"Server.DisableGeneralOptionsHandler", Field, 20},
 		{"Server.ErrorLog", Field, 3},
+		{"Server.HTTP2", Field, 24},
 		{"Server.Handler", Field, 0},
 		{"Server.IdleTimeout", Field, 8},
 		{"Server.MaxHeaderBytes", Field, 0},
+		{"Server.Protocols", Field, 24},
 		{"Server.ReadHeaderTimeout", Field, 8},
 		{"Server.ReadTimeout", Field, 0},
 		{"Server.TLSConfig", Field, 0},
@@ -8453,12 +8626,14 @@ var PackageSymbols = map[string][]Symbol{
 		{"Transport.ExpectContinueTimeout", Field, 6},
 		{"Transport.ForceAttemptHTTP2", Field, 13},
 		{"Transport.GetProxyConnectHeader", Field, 16},
+		{"Transport.HTTP2", Field, 24},
 		{"Transport.IdleConnTimeout", Field, 7},
 		{"Transport.MaxConnsPerHost", Field, 11},
 		{"Transport.MaxIdleConns", Field, 7},
 		{"Transport.MaxIdleConnsPerHost", Field, 0},
 		{"Transport.MaxResponseHeaderBytes", Field, 7},
 		{"Transport.OnProxyConnectResponse", Field, 20},
+		{"Transport.Protocols", Field, 24},
 		{"Transport.Proxy", Field, 0},
 		{"Transport.ProxyConnectHeader", Field, 8},
 		{"Transport.ReadBufferSize", Field, 13},
@@ -8646,6 +8821,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*AddrPort).UnmarshalText", Method, 18},
 		{"(*Prefix).UnmarshalBinary", Method, 18},
 		{"(*Prefix).UnmarshalText", Method, 18},
+		{"(Addr).AppendBinary", Method, 24},
+		{"(Addr).AppendText", Method, 24},
 		{"(Addr).AppendTo", Method, 18},
 		{"(Addr).As16", Method, 18},
 		{"(Addr).As4", Method, 18},
@@ -8676,6 +8853,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"(Addr).WithZone", Method, 18},
 		{"(Addr).Zone", Method, 18},
 		{"(AddrPort).Addr", Method, 18},
+		{"(AddrPort).AppendBinary", Method, 24},
+		{"(AddrPort).AppendText", Method, 24},
 		{"(AddrPort).AppendTo", Method, 18},
 		{"(AddrPort).Compare", Method, 22},
 		{"(AddrPort).IsValid", Method, 18},
@@ -8684,6 +8863,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"(AddrPort).Port", Method, 18},
 		{"(AddrPort).String", Method, 18},
 		{"(Prefix).Addr", Method, 18},
+		{"(Prefix).AppendBinary", Method, 24},
+		{"(Prefix).AppendText", Method, 24},
 		{"(Prefix).AppendTo", Method, 18},
 		{"(Prefix).Bits", Method, 18},
 		{"(Prefix).Contains", Method, 18},
@@ -8868,6 +9049,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*Error).Temporary", Method, 6},
 		{"(*Error).Timeout", Method, 6},
 		{"(*Error).Unwrap", Method, 13},
+		{"(*URL).AppendBinary", Method, 24},
 		{"(*URL).EscapedFragment", Method, 15},
 		{"(*URL).EscapedPath", Method, 5},
 		{"(*URL).Hostname", Method, 8},
@@ -8967,6 +9149,17 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*ProcessState).SysUsage", Method, 0},
 		{"(*ProcessState).SystemTime", Method, 0},
 		{"(*ProcessState).UserTime", Method, 0},
+		{"(*Root).Close", Method, 24},
+		{"(*Root).Create", Method, 24},
+		{"(*Root).FS", Method, 24},
+		{"(*Root).Lstat", Method, 24},
+		{"(*Root).Mkdir", Method, 24},
+		{"(*Root).Name", Method, 24},
+		{"(*Root).Open", Method, 24},
+		{"(*Root).OpenFile", Method, 24},
+		{"(*Root).OpenRoot", Method, 24},
+		{"(*Root).Remove", Method, 24},
+		{"(*Root).Stat", Method, 24},
 		{"(*SyscallError).Error", Method, 0},
 		{"(*SyscallError).Timeout", Method, 10},
 		{"(*SyscallError).Unwrap", Method, 13},
@@ -9060,6 +9253,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"O_WRONLY", Const, 0},
 		{"Open", Func, 0},
 		{"OpenFile", Func, 0},
+		{"OpenInRoot", Func, 24},
+		{"OpenRoot", Func, 24},
 		{"PathError", Type, 0},
 		{"PathError.Err", Field, 0},
 		{"PathError.Op", Field, 0},
@@ -9081,6 +9276,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"Remove", Func, 0},
 		{"RemoveAll", Func, 0},
 		{"Rename", Func, 0},
+		{"Root", Type, 24},
 		{"SEEK_CUR", Const, 0},
 		{"SEEK_END", Const, 0},
 		{"SEEK_SET", Const, 0},
@@ -9422,6 +9618,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"Zero", Func, 0},
 	},
 	"regexp": {
+		{"(*Regexp).AppendText", Method, 24},
 		{"(*Regexp).Copy", Method, 6},
 		{"(*Regexp).Expand", Method, 0},
 		{"(*Regexp).ExpandString", Method, 0},
@@ -9602,6 +9799,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*StackRecord).Stack", Method, 0},
 		{"(*TypeAssertionError).Error", Method, 0},
 		{"(*TypeAssertionError).RuntimeError", Method, 0},
+		{"(Cleanup).Stop", Method, 24},
+		{"AddCleanup", Func, 24},
 		{"BlockProfile", Func, 1},
 		{"BlockProfileRecord", Type, 1},
 		{"BlockProfileRecord.Count", Field, 1},
@@ -9612,6 +9811,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"Caller", Func, 0},
 		{"Callers", Func, 0},
 		{"CallersFrames", Func, 7},
+		{"Cleanup", Type, 24},
 		{"Compiler", Const, 0},
 		{"Error", Type, 0},
 		{"Frame", Type, 7},
@@ -9974,6 +10174,8 @@ var PackageSymbols = map[string][]Symbol{
 		{"EqualFold", Func, 0},
 		{"Fields", Func, 0},
 		{"FieldsFunc", Func, 0},
+		{"FieldsFuncSeq", Func, 24},
+		{"FieldsSeq", Func, 24},
 		{"HasPrefix", Func, 0},
 		{"HasSuffix", Func, 0},
 		{"Index", Func, 0},
@@ -9986,6 +10188,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"LastIndexAny", Func, 0},
 		{"LastIndexByte", Func, 5},
 		{"LastIndexFunc", Func, 0},
+		{"Lines", Func, 24},
 		{"Map", Func, 0},
 		{"NewReader", Func, 0},
 		{"NewReplacer", Func, 0},
@@ -9997,7 +10200,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"Split", Func, 0},
 		{"SplitAfter", Func, 0},
 		{"SplitAfterN", Func, 0},
+		{"SplitAfterSeq", Func, 24},
 		{"SplitN", Func, 0},
+		{"SplitSeq", Func, 24},
 		{"Title", Func, 0},
 		{"ToLower", Func, 0},
 		{"ToLowerSpecial", Func, 0},
@@ -16413,7 +16618,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"ValueOf", Func, 0},
 	},
 	"testing": {
+		{"(*B).Chdir", Method, 24},
 		{"(*B).Cleanup", Method, 14},
+		{"(*B).Context", Method, 24},
 		{"(*B).Elapsed", Method, 20},
 		{"(*B).Error", Method, 0},
 		{"(*B).Errorf", Method, 0},
@@ -16425,6 +16632,7 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*B).Helper", Method, 9},
 		{"(*B).Log", Method, 0},
 		{"(*B).Logf", Method, 0},
+		{"(*B).Loop", Method, 24},
 		{"(*B).Name", Method, 8},
 		{"(*B).ReportAllocs", Method, 1},
 		{"(*B).ReportMetric", Method, 13},
@@ -16442,7 +16650,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*B).StopTimer", Method, 0},
 		{"(*B).TempDir", Method, 15},
 		{"(*F).Add", Method, 18},
+		{"(*F).Chdir", Method, 24},
 		{"(*F).Cleanup", Method, 18},
+		{"(*F).Context", Method, 24},
 		{"(*F).Error", Method, 18},
 		{"(*F).Errorf", Method, 18},
 		{"(*F).Fail", Method, 18},
@@ -16463,7 +16673,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"(*F).TempDir", Method, 18},
 		{"(*M).Run", Method, 4},
 		{"(*PB).Next", Method, 3},
+		{"(*T).Chdir", Method, 24},
 		{"(*T).Cleanup", Method, 14},
+		{"(*T).Context", Method, 24},
 		{"(*T).Deadline", Method, 15},
 		{"(*T).Error", Method, 0},
 		{"(*T).Errorf", Method, 0},
@@ -16954,7 +17166,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"(Time).Add", Method, 0},
 		{"(Time).AddDate", Method, 0},
 		{"(Time).After", Method, 0},
+		{"(Time).AppendBinary", Method, 24},
 		{"(Time).AppendFormat", Method, 5},
+		{"(Time).AppendText", Method, 24},
 		{"(Time).Before", Method, 0},
 		{"(Time).Clock", Method, 0},
 		{"(Time).Compare", Method, 20},
@@ -17428,4 +17642,9 @@ var PackageSymbols = map[string][]Symbol{
 		{"String", Func, 0},
 		{"StringData", Func, 0},
 	},
+	"weak": {
+		{"(Pointer).Value", Method, 24},
+		{"Make", Func, 24},
+		{"Pointer", Type, 24},
+	},
 }
diff --git a/vendor/golang.org/x/tools/internal/testenv/testenv.go b/vendor/golang.org/x/tools/internal/testenv/testenv.go
index d4a17ce039..144f4f8fd6 100644
--- a/vendor/golang.org/x/tools/internal/testenv/testenv.go
+++ b/vendor/golang.org/x/tools/internal/testenv/testenv.go
@@ -7,9 +7,12 @@
 package testenv
 
 import (
+	"bufio"
 	"bytes"
+	"context"
 	"fmt"
 	"go/build"
+	"log"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -21,6 +24,7 @@ import (
 	"time"
 
 	"golang.org/x/mod/modfile"
+	"golang.org/x/tools/internal/gocommand"
 	"golang.org/x/tools/internal/goroot"
 )
 
@@ -323,6 +327,36 @@ func Go1Point() int {
 	panic("bad release tags")
 }
 
+// NeedsGoCommand1Point skips t if the ambient go command version in the PATH
+// of the current process is older than 1.x.
+//
+// NeedsGoCommand1Point memoizes the result of running the go command, so
+// should be called after all mutations of PATH.
+func NeedsGoCommand1Point(t testing.TB, x int) {
+	NeedsTool(t, "go")
+	go1point, err := goCommand1Point()
+	if err != nil {
+		panic(fmt.Sprintf("unable to determine go version: %v", err))
+	}
+	if go1point < x {
+		t.Helper()
+		t.Skipf("go command is version 1.%d, older than required 1.%d", go1point, x)
+	}
+}
+
+var (
+	goCommand1PointOnce sync.Once
+	goCommand1Point_    int
+	goCommand1PointErr  error
+)
+
+func goCommand1Point() (int, error) {
+	goCommand1PointOnce.Do(func() {
+		goCommand1Point_, goCommand1PointErr = gocommand.GoVersion(context.Background(), gocommand.Invocation{}, new(gocommand.Runner))
+	})
+	return goCommand1Point_, goCommand1PointErr
+}
+
 // NeedsGo1Point skips t if the Go version used to run the test is older than
 // 1.x.
 func NeedsGo1Point(t testing.TB, x int) {
@@ -332,6 +366,23 @@ func NeedsGo1Point(t testing.TB, x int) {
 	}
 }
 
+// SkipAfterGoCommand1Point skips t if the ambient go command version in the PATH of
+// the current process is newer than 1.x.
+//
+// SkipAfterGoCommand1Point memoizes the result of running the go command, so
+// should be called after any mutation of PATH.
+func SkipAfterGoCommand1Point(t testing.TB, x int) {
+	NeedsTool(t, "go")
+	go1point, err := goCommand1Point()
+	if err != nil {
+		panic(fmt.Sprintf("unable to determine go version: %v", err))
+	}
+	if go1point > x {
+		t.Helper()
+		t.Skipf("go command is version 1.%d, newer than maximum 1.%d", go1point, x)
+	}
+}
+
 // SkipAfterGo1Point skips t if the Go version used to run the test is newer than
 // 1.x.
 func SkipAfterGo1Point(t testing.TB, x int) {
@@ -490,3 +541,59 @@ func NeedsGoExperiment(t testing.TB, flag string) {
 		t.Skipf("skipping test: flag %q is not set in GOEXPERIMENT=%q", flag, goexp)
 	}
 }
+
+// NeedsGOROOTDir skips the test if GOROOT/dir does not exist, and GOROOT is a
+// released version of Go (=has a VERSION file). Some GOROOT directories are
+// removed by cmd/distpack.
+//
+// See also golang/go#70081.
+func NeedsGOROOTDir(t *testing.T, dir string) {
+	gorootTest := filepath.Join(GOROOT(t), dir)
+	if _, err := os.Stat(gorootTest); os.IsNotExist(err) {
+		if _, err := os.Stat(filepath.Join(GOROOT(t), "VERSION")); err == nil {
+			t.Skipf("skipping: GOROOT/%s not present", dir)
+		}
+	}
+}
+
+// RedirectStderr causes os.Stderr (and the global logger) to be
+// temporarily replaced so that writes to it are sent to t.Log.
+// It is restored at test cleanup.
+func RedirectStderr(t testing.TB) {
+	t.Setenv("RedirectStderr", "") // side effect: assert t.Parallel wasn't called
+
+	// TODO(adonovan): if https://go.dev/issue/59928 is accepted,
+	// simply set w = t.Output() and dispense with the pipe.
+	r, w, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("pipe: %v", err)
+	}
+	done := make(chan struct{})
+	go func() {
+		for sc := bufio.NewScanner(r); sc.Scan(); {
+			t.Log(sc.Text())
+		}
+		r.Close()
+		close(done)
+	}()
+
+	// Also do the same for the global logger.
+	savedWriter, savedPrefix, savedFlags := log.Writer(), log.Prefix(), log.Flags()
+	log.SetPrefix("log: ")
+	log.SetOutput(w)
+	log.SetFlags(0)
+
+	oldStderr := os.Stderr
+	os.Stderr = w
+	t.Cleanup(func() {
+		w.Close() // ignore error
+		os.Stderr = oldStderr
+
+		log.SetOutput(savedWriter)
+		log.SetPrefix(savedPrefix)
+		log.SetFlags(savedFlags)
+
+		// Don't let test finish before final t.Log.
+		<-done
+	})
+}
diff --git a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go
deleted file mode 100644
index ff9437a36c..0000000000
--- a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// package tokeninternal provides access to some internal features of the token
-// package.
-package tokeninternal
-
-import (
-	"fmt"
-	"go/token"
-	"sort"
-	"sync"
-	"unsafe"
-)
-
-// GetLines returns the table of line-start offsets from a token.File.
-func GetLines(file *token.File) []int {
-	// token.File has a Lines method on Go 1.21 and later.
-	if file, ok := (interface{})(file).(interface{ Lines() []int }); ok {
-		return file.Lines()
-	}
-
-	// This declaration must match that of token.File.
-	// This creates a risk of dependency skew.
-	// For now we check that the size of the two
-	// declarations is the same, on the (fragile) assumption
-	// that future changes would add fields.
-	type tokenFile119 struct {
-		_     string
-		_     int
-		_     int
-		mu    sync.Mutex // we're not complete monsters
-		lines []int
-		_     []struct{}
-	}
-
-	if unsafe.Sizeof(*file) != unsafe.Sizeof(tokenFile119{}) {
-		panic("unexpected token.File size")
-	}
-	var ptr *tokenFile119
-	type uP = unsafe.Pointer
-	*(*uP)(uP(&ptr)) = uP(file)
-	ptr.mu.Lock()
-	defer ptr.mu.Unlock()
-	return ptr.lines
-}
-
-// AddExistingFiles adds the specified files to the FileSet if they
-// are not already present. It panics if any pair of files in the
-// resulting FileSet would overlap.
-func AddExistingFiles(fset *token.FileSet, files []*token.File) {
-	// Punch through the FileSet encapsulation.
-	type tokenFileSet struct {
-		// This type remained essentially consistent from go1.16 to go1.21.
-		mutex sync.RWMutex
-		base  int
-		files []*token.File
-		_     *token.File // changed to atomic.Pointer[token.File] in go1.19
-	}
-
-	// If the size of token.FileSet changes, this will fail to compile.
-	const delta = int64(unsafe.Sizeof(tokenFileSet{})) - int64(unsafe.Sizeof(token.FileSet{}))
-	var _ [-delta * delta]int
-
-	type uP = unsafe.Pointer
-	var ptr *tokenFileSet
-	*(*uP)(uP(&ptr)) = uP(fset)
-	ptr.mutex.Lock()
-	defer ptr.mutex.Unlock()
-
-	// Merge and sort.
-	newFiles := append(ptr.files, files...)
-	sort.Slice(newFiles, func(i, j int) bool {
-		return newFiles[i].Base() < newFiles[j].Base()
-	})
-
-	// Reject overlapping files.
-	// Discard adjacent identical files.
-	out := newFiles[:0]
-	for i, file := range newFiles {
-		if i > 0 {
-			prev := newFiles[i-1]
-			if file == prev {
-				continue
-			}
-			if prev.Base()+prev.Size()+1 > file.Base() {
-				panic(fmt.Sprintf("file %s (%d-%d) overlaps with file %s (%d-%d)",
-					prev.Name(), prev.Base(), prev.Base()+prev.Size(),
-					file.Name(), file.Base(), file.Base()+file.Size()))
-			}
-		}
-		out = append(out, file)
-	}
-	newFiles = out
-
-	ptr.files = newFiles
-
-	// Advance FileSet.Base().
-	if len(newFiles) > 0 {
-		last := newFiles[len(newFiles)-1]
-		newBase := last.Base() + last.Size() + 1
-		if ptr.base < newBase {
-			ptr.base = newBase
-		}
-	}
-}
-
-// FileSetFor returns a new FileSet containing a sequence of new Files with
-// the same base, size, and line as the input files, for use in APIs that
-// require a FileSet.
-//
-// Precondition: the input files must be non-overlapping, and sorted in order
-// of their Base.
-func FileSetFor(files ...*token.File) *token.FileSet {
-	fset := token.NewFileSet()
-	for _, f := range files {
-		f2 := fset.AddFile(f.Name(), f.Base(), f.Size())
-		lines := GetLines(f)
-		f2.SetLines(lines)
-	}
-	return fset
-}
-
-// CloneFileSet creates a new FileSet holding all files in fset. It does not
-// create copies of the token.Files in fset: they are added to the resulting
-// FileSet unmodified.
-func CloneFileSet(fset *token.FileSet) *token.FileSet {
-	var files []*token.File
-	fset.Iterate(func(f *token.File) bool {
-		files = append(files, f)
-		return true
-	})
-	newFileSet := token.NewFileSet()
-	AddExistingFiles(newFileSet, files)
-	return newFileSet
-}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go
new file mode 100644
index 0000000000..cdae2b8e81
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typeparams/common.go
@@ -0,0 +1,68 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package typeparams contains common utilities for writing tools that
+// interact with generic Go code, as introduced with Go 1.18. It
+// supplements the standard library APIs. Notably, the StructuralTerms
+// API computes a minimal representation of the structural
+// restrictions on a type parameter.
+//
+// An external version of these APIs is available in the
+// golang.org/x/exp/typeparams module.
+package typeparams
+
+import (
+	"go/ast"
+	"go/token"
+	"go/types"
+)
+
+// UnpackIndexExpr extracts data from AST nodes that represent index
+// expressions.
+//
+// For an ast.IndexExpr, the resulting indices slice will contain exactly one
+// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable
+// number of index expressions.
+//
+// For nodes that don't represent index expressions, the first return value of
+// UnpackIndexExpr will be nil.
+func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) {
+	switch e := n.(type) {
+	case *ast.IndexExpr:
+		return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack
+	case *ast.IndexListExpr:
+		return e.X, e.Lbrack, e.Indices, e.Rbrack
+	}
+	return nil, token.NoPos, nil, token.NoPos
+}
+
+// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on
+// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0
+// will panic.
+func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
+	switch len(indices) {
+	case 0:
+		panic("empty indices")
+	case 1:
+		return &ast.IndexExpr{
+			X:      x,
+			Lbrack: lbrack,
+			Index:  indices[0],
+			Rbrack: rbrack,
+		}
+	default:
+		return &ast.IndexListExpr{
+			X:       x,
+			Lbrack:  lbrack,
+			Indices: indices,
+			Rbrack:  rbrack,
+		}
+	}
+}
+
+// IsTypeParam reports whether t is a type parameter (or an alias of one).
+func IsTypeParam(t types.Type) bool {
+	_, ok := types.Unalias(t).(*types.TypeParam)
+	return ok
+}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go
new file mode 100644
index 0000000000..27a2b17929
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typeparams/coretype.go
@@ -0,0 +1,155 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typeparams
+
+import (
+	"fmt"
+	"go/types"
+)
+
+// CoreType returns the core type of T or nil if T does not have a core type.
+//
+// See https://go.dev/ref/spec#Core_types for the definition of a core type.
+func CoreType(T types.Type) types.Type {
+	U := T.Underlying()
+	if _, ok := U.(*types.Interface); !ok {
+		return U // for non-interface types,
+	}
+
+	terms, err := NormalTerms(U)
+	if len(terms) == 0 || err != nil {
+		// len(terms) -> empty type set of interface.
+		// err != nil => U is invalid, exceeds complexity bounds, or has an empty type set.
+		return nil // no core type.
+	}
+
+	U = terms[0].Type().Underlying()
+	var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying())
+	for identical = 1; identical < len(terms); identical++ {
+		if !types.Identical(U, terms[identical].Type().Underlying()) {
+			break
+		}
+	}
+
+	if identical == len(terms) {
+		// https://go.dev/ref/spec#Core_types
+		// "There is a single type U which is the underlying type of all types in the type set of T"
+		return U
+	}
+	ch, ok := U.(*types.Chan)
+	if !ok {
+		return nil // no core type as identical < len(terms) and U is not a channel.
+	}
+	// https://go.dev/ref/spec#Core_types
+	// "the type chan E if T contains only bidirectional channels, or the type chan<- E or
+	// <-chan E depending on the direction of the directional channels present."
+	for chans := identical; chans < len(terms); chans++ {
+		curr, ok := terms[chans].Type().Underlying().(*types.Chan)
+		if !ok {
+			return nil
+		}
+		if !types.Identical(ch.Elem(), curr.Elem()) {
+			return nil // channel elements are not identical.
+		}
+		if ch.Dir() == types.SendRecv {
+			// ch is bidirectional. We can safely always use curr's direction.
+			ch = curr
+		} else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() {
+			// ch and curr are not bidirectional and not the same direction.
+			return nil
+		}
+	}
+	return ch
+}
+
+// NormalTerms returns a slice of terms representing the normalized structural
+// type restrictions of a type, if any.
+//
+// For all types other than *types.TypeParam, *types.Interface, and
+// *types.Union, this is just a single term with Tilde() == false and
+// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see
+// below.
+//
+// Structural type restrictions of a type parameter are created via
+// non-interface types embedded in its constraint interface (directly, or via a
+// chain of interface embeddings). For example, in the declaration type
+// T[P interface{~int; m()}] int the structural restriction of the type
+// parameter P is ~int.
+//
+// With interface embedding and unions, the specification of structural type
+// restrictions may be arbitrarily complex. For example, consider the
+// following:
+//
+//	type A interface{ ~string|~[]byte }
+//
+//	type B interface{ int|string }
+//
+//	type C interface { ~string|~int }
+//
+//	type T[P interface{ A|B; C }] int
+//
+// In this example, the structural type restriction of P is ~string|int: A|B
+// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
+// which when intersected with C (~string|~int) yields ~string|int.
+//
+// NormalTerms computes these expansions and reductions, producing a
+// "normalized" form of the embeddings. A structural restriction is normalized
+// if it is a single union containing no interface terms, and is minimal in the
+// sense that removing any term changes the set of types satisfying the
+// constraint. It is left as a proof for the reader that, modulo sorting, there
+// is exactly one such normalized form.
+//
+// Because the minimal representation always takes this form, NormalTerms
+// returns a slice of tilde terms corresponding to the terms of the union in
+// the normalized structural restriction. An error is returned if the type is
+// invalid, exceeds complexity bounds, or has an empty type set. In the latter
+// case, NormalTerms returns ErrEmptyTypeSet.
+//
+// NormalTerms makes no guarantees about the order of terms, except that it
+// is deterministic.
+func NormalTerms(T types.Type) ([]*types.Term, error) {
+	// typeSetOf(T) == typeSetOf(Unalias(T))
+	typ := types.Unalias(T)
+	if named, ok := typ.(*types.Named); ok {
+		typ = named.Underlying()
+	}
+	switch typ := typ.(type) {
+	case *types.TypeParam:
+		return StructuralTerms(typ)
+	case *types.Union:
+		return UnionTermSet(typ)
+	case *types.Interface:
+		return InterfaceTermSet(typ)
+	default:
+		return []*types.Term{types.NewTerm(false, T)}, nil
+	}
+}
+
+// Deref returns the type of the variable pointed to by t,
+// if t's core type is a pointer; otherwise it returns t.
+//
+// Do not assume that Deref(T)==T implies T is not a pointer:
+// consider "type T *T", for example.
+//
+// TODO(adonovan): ideally this would live in typesinternal, but that
+// creates an import cycle. Move there when we melt this package down.
+func Deref(t types.Type) types.Type {
+	if ptr, ok := CoreType(t).(*types.Pointer); ok {
+		return ptr.Elem()
+	}
+	return t
+}
+
+// MustDeref returns the type of the variable pointed to by t.
+// It panics if t's core type is not a pointer.
+//
+// TODO(adonovan): ideally this would live in typesinternal, but that
+// creates an import cycle. Move there when we melt this package down.
+func MustDeref(t types.Type) types.Type {
+	if ptr, ok := CoreType(t).(*types.Pointer); ok {
+		return ptr.Elem()
+	}
+	panic(fmt.Sprintf("%v is not a pointer", t))
+}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/free.go b/vendor/golang.org/x/tools/internal/typeparams/free.go
new file mode 100644
index 0000000000..0ade5c2949
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typeparams/free.go
@@ -0,0 +1,131 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typeparams
+
+import (
+	"go/types"
+
+	"golang.org/x/tools/internal/aliases"
+)
+
+// Free is a memoization of the set of free type parameters within a
+// type. It makes a sequence of calls to [Free.Has] for overlapping
+// types more efficient. The zero value is ready for use.
+//
+// NOTE: Adapted from go/types/infer.go. If it is later exported, factor.
+type Free struct {
+	seen map[types.Type]bool
+}
+
+// Has reports whether the specified type has a free type parameter.
+func (w *Free) Has(typ types.Type) (res bool) {
+	// detect cycles
+	if x, ok := w.seen[typ]; ok {
+		return x
+	}
+	if w.seen == nil {
+		w.seen = make(map[types.Type]bool)
+	}
+	w.seen[typ] = false
+	defer func() {
+		w.seen[typ] = res
+	}()
+
+	switch t := typ.(type) {
+	case nil, *types.Basic: // TODO(gri) should nil be handled here?
+		break
+
+	case *types.Alias:
+		if aliases.TypeParams(t).Len() > aliases.TypeArgs(t).Len() {
+			return true // This is an uninstantiated Alias.
+		}
+		// The expansion of an alias can have free type parameters,
+		// whether or not the alias itself has type parameters:
+		//
+		//   func _[K comparable]() {
+		//     type Set      = map[K]bool // free(Set)      = {K}
+		//     type MapTo[V] = map[K]V    // free(Map[foo]) = {V}
+		//   }
+		//
+		// So, we must Unalias.
+		return w.Has(types.Unalias(t))
+
+	case *types.Array:
+		return w.Has(t.Elem())
+
+	case *types.Slice:
+		return w.Has(t.Elem())
+
+	case *types.Struct:
+		for i, n := 0, t.NumFields(); i < n; i++ {
+			if w.Has(t.Field(i).Type()) {
+				return true
+			}
+		}
+
+	case *types.Pointer:
+		return w.Has(t.Elem())
+
+	case *types.Tuple:
+		n := t.Len()
+		for i := 0; i < n; i++ {
+			if w.Has(t.At(i).Type()) {
+				return true
+			}
+		}
+
+	case *types.Signature:
+		// t.tparams may not be nil if we are looking at a signature
+		// of a generic function type (or an interface method) that is
+		// part of the type we're testing. We don't care about these type
+		// parameters.
+		// Similarly, the receiver of a method may declare (rather than
+		// use) type parameters, we don't care about those either.
+		// Thus, we only need to look at the input and result parameters.
+		return w.Has(t.Params()) || w.Has(t.Results())
+
+	case *types.Interface:
+		for i, n := 0, t.NumMethods(); i < n; i++ {
+			if w.Has(t.Method(i).Type()) {
+				return true
+			}
+		}
+		terms, err := InterfaceTermSet(t)
+		if err != nil {
+			return false // ill typed
+		}
+		for _, term := range terms {
+			if w.Has(term.Type()) {
+				return true
+			}
+		}
+
+	case *types.Map:
+		return w.Has(t.Key()) || w.Has(t.Elem())
+
+	case *types.Chan:
+		return w.Has(t.Elem())
+
+	case *types.Named:
+		args := t.TypeArgs()
+		if params := t.TypeParams(); params.Len() > args.Len() {
+			return true // this is an uninstantiated named type.
+		}
+		for i, n := 0, args.Len(); i < n; i++ {
+			if w.Has(args.At(i)) {
+				return true
+			}
+		}
+		return w.Has(t.Underlying()) // recurse for types local to parameterized functions
+
+	case *types.TypeParam:
+		return true
+
+	default:
+		panic(t) // unreachable
+	}
+
+	return false
+}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go
new file mode 100644
index 0000000000..93c80fdc96
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typeparams/normalize.go
@@ -0,0 +1,218 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typeparams
+
+import (
+	"errors"
+	"fmt"
+	"go/types"
+	"os"
+	"strings"
+)
+
+//go:generate go run copytermlist.go
+
+const debug = false
+
+var ErrEmptyTypeSet = errors.New("empty type set")
+
+// StructuralTerms returns a slice of terms representing the normalized
+// structural type restrictions of a type parameter, if any.
+//
+// Structural type restrictions of a type parameter are created via
+// non-interface types embedded in its constraint interface (directly, or via a
+// chain of interface embeddings). For example, in the declaration
+//
+//	type T[P interface{~int; m()}] int
+//
+// the structural restriction of the type parameter P is ~int.
+//
+// With interface embedding and unions, the specification of structural type
+// restrictions may be arbitrarily complex. For example, consider the
+// following:
+//
+//	type A interface{ ~string|~[]byte }
+//
+//	type B interface{ int|string }
+//
+//	type C interface { ~string|~int }
+//
+//	type T[P interface{ A|B; C }] int
+//
+// In this example, the structural type restriction of P is ~string|int: A|B
+// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
+// which when intersected with C (~string|~int) yields ~string|int.
+//
+// StructuralTerms computes these expansions and reductions, producing a
+// "normalized" form of the embeddings. A structural restriction is normalized
+// if it is a single union containing no interface terms, and is minimal in the
+// sense that removing any term changes the set of types satisfying the
+// constraint. It is left as a proof for the reader that, modulo sorting, there
+// is exactly one such normalized form.
+//
+// Because the minimal representation always takes this form, StructuralTerms
+// returns a slice of tilde terms corresponding to the terms of the union in
+// the normalized structural restriction. An error is returned if the
+// constraint interface is invalid, exceeds complexity bounds, or has an empty
+// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet.
+//
+// StructuralTerms makes no guarantees about the order of terms, except that it
+// is deterministic.
+func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) {
+	constraint := tparam.Constraint()
+	if constraint == nil {
+		return nil, fmt.Errorf("%s has nil constraint", tparam)
+	}
+	iface, _ := constraint.Underlying().(*types.Interface)
+	if iface == nil {
+		return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying())
+	}
+	return InterfaceTermSet(iface)
+}
+
+// InterfaceTermSet computes the normalized terms for a constraint interface,
+// returning an error if the term set cannot be computed or is empty. In the
+// latter case, the error will be ErrEmptyTypeSet.
+//
+// See the documentation of StructuralTerms for more information on
+// normalization.
+func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) {
+	return computeTermSet(iface)
+}
+
+// UnionTermSet computes the normalized terms for a union, returning an error
+// if the term set cannot be computed or is empty. In the latter case, the
+// error will be ErrEmptyTypeSet.
+//
+// See the documentation of StructuralTerms for more information on
+// normalization.
+func UnionTermSet(union *types.Union) ([]*types.Term, error) {
+	return computeTermSet(union)
+}
+
+func computeTermSet(typ types.Type) ([]*types.Term, error) {
+	tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0)
+	if err != nil {
+		return nil, err
+	}
+	if tset.terms.isEmpty() {
+		return nil, ErrEmptyTypeSet
+	}
+	if tset.terms.isAll() {
+		return nil, nil
+	}
+	var terms []*types.Term
+	for _, term := range tset.terms {
+		terms = append(terms, types.NewTerm(term.tilde, term.typ))
+	}
+	return terms, nil
+}
+
+// A termSet holds the normalized set of terms for a given type.
+//
+// The name termSet is intentionally distinct from 'type set': a type set is
+// all types that implement a type (and includes method restrictions), whereas
+// a term set just represents the structural restrictions on a type.
+type termSet struct {
+	complete bool
+	terms    termlist
+}
+
+func indentf(depth int, format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...)
+}
+
+func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) {
+	if t == nil {
+		panic("nil type")
+	}
+
+	if debug {
+		indentf(depth, "%s", t.String())
+		defer func() {
+			if err != nil {
+				indentf(depth, "=> %s", err)
+			} else {
+				indentf(depth, "=> %s", res.terms.String())
+			}
+		}()
+	}
+
+	const maxTermCount = 100
+	if tset, ok := seen[t]; ok {
+		if !tset.complete {
+			return nil, fmt.Errorf("cycle detected in the declaration of %s", t)
+		}
+		return tset, nil
+	}
+
+	// Mark the current type as seen to avoid infinite recursion.
+	tset := new(termSet)
+	defer func() {
+		tset.complete = true
+	}()
+	seen[t] = tset
+
+	switch u := t.Underlying().(type) {
+	case *types.Interface:
+		// The term set of an interface is the intersection of the term sets of its
+		// embedded types.
+		tset.terms = allTermlist
+		for i := 0; i < u.NumEmbeddeds(); i++ {
+			embedded := u.EmbeddedType(i)
+			if _, ok := embedded.Underlying().(*types.TypeParam); ok {
+				return nil, fmt.Errorf("invalid embedded type %T", embedded)
+			}
+			tset2, err := computeTermSetInternal(embedded, seen, depth+1)
+			if err != nil {
+				return nil, err
+			}
+			tset.terms = tset.terms.intersect(tset2.terms)
+		}
+	case *types.Union:
+		// The term set of a union is the union of term sets of its terms.
+		tset.terms = nil
+		for i := 0; i < u.Len(); i++ {
+			t := u.Term(i)
+			var terms termlist
+			switch t.Type().Underlying().(type) {
+			case *types.Interface:
+				tset2, err := computeTermSetInternal(t.Type(), seen, depth+1)
+				if err != nil {
+					return nil, err
+				}
+				terms = tset2.terms
+			case *types.TypeParam, *types.Union:
+				// A stand-alone type parameter or union is not permitted as union
+				// term.
+				return nil, fmt.Errorf("invalid union term %T", t)
+			default:
+				if t.Type() == types.Typ[types.Invalid] {
+					continue
+				}
+				terms = termlist{{t.Tilde(), t.Type()}}
+			}
+			tset.terms = tset.terms.union(terms)
+			if len(tset.terms) > maxTermCount {
+				return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
+			}
+		}
+	case *types.TypeParam:
+		panic("unreachable")
+	default:
+		// For all other types, the term set is just a single non-tilde term
+		// holding the type itself.
+		if u != types.Typ[types.Invalid] {
+			tset.terms = termlist{{false, t}}
+		}
+	}
+	return tset, nil
+}
+
+// under is a facade for the go/types internal function of the same name. It is
+// used by typeterm.go.
+func under(t types.Type) types.Type {
+	return t.Underlying()
+}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/vendor/golang.org/x/tools/internal/typeparams/termlist.go
new file mode 100644
index 0000000000..cbd12f8013
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typeparams/termlist.go
@@ -0,0 +1,163 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by copytermlist.go DO NOT EDIT.
+
+package typeparams
+
+import (
+	"bytes"
+	"go/types"
+)
+
+// A termlist represents the type set represented by the union
+// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn.
+// A termlist is in normal form if all terms are disjoint.
+// termlist operations don't require the operands to be in
+// normal form.
+type termlist []*term
+
+// allTermlist represents the set of all types.
+// It is in normal form.
+var allTermlist = termlist{new(term)}
+
+// String prints the termlist exactly (without normalization).
+func (xl termlist) String() string {
+	if len(xl) == 0 {
+		return "∅"
+	}
+	var buf bytes.Buffer
+	for i, x := range xl {
+		if i > 0 {
+			buf.WriteString(" | ")
+		}
+		buf.WriteString(x.String())
+	}
+	return buf.String()
+}
+
+// isEmpty reports whether the termlist xl represents the empty set of types.
+func (xl termlist) isEmpty() bool {
+	// If there's a non-nil term, the entire list is not empty.
+	// If the termlist is in normal form, this requires at most
+	// one iteration.
+	for _, x := range xl {
+		if x != nil {
+			return false
+		}
+	}
+	return true
+}
+
+// isAll reports whether the termlist xl represents the set of all types.
+func (xl termlist) isAll() bool {
+	// If there's a 𝓤 term, the entire list is 𝓤.
+	// If the termlist is in normal form, this requires at most
+	// one iteration.
+	for _, x := range xl {
+		if x != nil && x.typ == nil {
+			return true
+		}
+	}
+	return false
+}
+
+// norm returns the normal form of xl.
+func (xl termlist) norm() termlist {
+	// Quadratic algorithm, but good enough for now.
+	// TODO(gri) fix asymptotic performance
+	used := make([]bool, len(xl))
+	var rl termlist
+	for i, xi := range xl {
+		if xi == nil || used[i] {
+			continue
+		}
+		for j := i + 1; j < len(xl); j++ {
+			xj := xl[j]
+			if xj == nil || used[j] {
+				continue
+			}
+			if u1, u2 := xi.union(xj); u2 == nil {
+				// If we encounter a 𝓤 term, the entire list is 𝓤.
+				// Exit early.
+				// (Note that this is not just an optimization;
+				// if we continue, we may end up with a 𝓤 term
+				// and other terms and the result would not be
+				// in normal form.)
+				if u1.typ == nil {
+					return allTermlist
+				}
+				xi = u1
+				used[j] = true // xj is now unioned into xi - ignore it in future iterations
+			}
+		}
+		rl = append(rl, xi)
+	}
+	return rl
+}
+
+// union returns the union xl ∪ yl.
+func (xl termlist) union(yl termlist) termlist {
+	return append(xl, yl...).norm()
+}
+
+// intersect returns the intersection xl ∩ yl.
+func (xl termlist) intersect(yl termlist) termlist {
+	if xl.isEmpty() || yl.isEmpty() {
+		return nil
+	}
+
+	// Quadratic algorithm, but good enough for now.
+	// TODO(gri) fix asymptotic performance
+	var rl termlist
+	for _, x := range xl {
+		for _, y := range yl {
+			if r := x.intersect(y); r != nil {
+				rl = append(rl, r)
+			}
+		}
+	}
+	return rl.norm()
+}
+
+// equal reports whether xl and yl represent the same type set.
+func (xl termlist) equal(yl termlist) bool {
+	// TODO(gri) this should be more efficient
+	return xl.subsetOf(yl) && yl.subsetOf(xl)
+}
+
+// includes reports whether t ∈ xl.
+func (xl termlist) includes(t types.Type) bool {
+	for _, x := range xl {
+		if x.includes(t) {
+			return true
+		}
+	}
+	return false
+}
+
+// supersetOf reports whether y ⊆ xl.
+func (xl termlist) supersetOf(y *term) bool {
+	for _, x := range xl {
+		if y.subsetOf(x) {
+			return true
+		}
+	}
+	return false
+}
+
+// subsetOf reports whether xl ⊆ yl.
+func (xl termlist) subsetOf(yl termlist) bool {
+	if yl.isEmpty() {
+		return xl.isEmpty()
+	}
+
+	// each term x of xl must be a subset of yl
+	for _, x := range xl {
+		if !yl.supersetOf(x) {
+			return false // x is not a subset yl
+		}
+	}
+	return true
+}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go
new file mode 100644
index 0000000000..7350bb702a
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go
@@ -0,0 +1,169 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by copytermlist.go DO NOT EDIT.
+
+package typeparams
+
+import "go/types"
+
+// A term describes elementary type sets:
+//
+//	 ∅:  (*term)(nil)     == ∅                      // set of no types (empty set)
+//	 𝓤:  &term{}          == 𝓤                      // set of all types (𝓤niverse)
+//	 T:  &term{false, T}  == {T}                    // set of type T
+//	~t:  &term{true, t}   == {t' | under(t') == t}  // set of types with underlying type t
+type term struct {
+	tilde bool // valid if typ != nil
+	typ   types.Type
+}
+
+func (x *term) String() string {
+	switch {
+	case x == nil:
+		return "∅"
+	case x.typ == nil:
+		return "𝓤"
+	case x.tilde:
+		return "~" + x.typ.String()
+	default:
+		return x.typ.String()
+	}
+}
+
+// equal reports whether x and y represent the same type set.
+func (x *term) equal(y *term) bool {
+	// easy cases
+	switch {
+	case x == nil || y == nil:
+		return x == y
+	case x.typ == nil || y.typ == nil:
+		return x.typ == y.typ
+	}
+	// ∅ ⊂ x, y ⊂ 𝓤
+
+	return x.tilde == y.tilde && types.Identical(x.typ, y.typ)
+}
+
+// union returns the union x ∪ y: zero, one, or two non-nil terms.
+func (x *term) union(y *term) (_, _ *term) {
+	// easy cases
+	switch {
+	case x == nil && y == nil:
+		return nil, nil // ∅ ∪ ∅ == ∅
+	case x == nil:
+		return y, nil // ∅ ∪ y == y
+	case y == nil:
+		return x, nil // x ∪ ∅ == x
+	case x.typ == nil:
+		return x, nil // 𝓤 ∪ y == 𝓤
+	case y.typ == nil:
+		return y, nil // x ∪ 𝓤 == 𝓤
+	}
+	// ∅ ⊂ x, y ⊂ 𝓤
+
+	if x.disjoint(y) {
+		return x, y // x ∪ y == (x, y) if x ∩ y == ∅
+	}
+	// x.typ == y.typ
+
+	// ~t ∪ ~t == ~t
+	// ~t ∪  T == ~t
+	//  T ∪ ~t == ~t
+	//  T ∪  T ==  T
+	if x.tilde || !y.tilde {
+		return x, nil
+	}
+	return y, nil
+}
+
+// intersect returns the intersection x ∩ y.
+func (x *term) intersect(y *term) *term {
+	// easy cases
+	switch {
+	case x == nil || y == nil:
+		return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅
+	case x.typ == nil:
+		return y // 𝓤 ∩ y == y
+	case y.typ == nil:
+		return x // x ∩ 𝓤 == x
+	}
+	// ∅ ⊂ x, y ⊂ 𝓤
+
+	if x.disjoint(y) {
+		return nil // x ∩ y == ∅ if x ∩ y == ∅
+	}
+	// x.typ == y.typ
+
+	// ~t ∩ ~t == ~t
+	// ~t ∩  T ==  T
+	//  T ∩ ~t ==  T
+	//  T ∩  T ==  T
+	if !x.tilde || y.tilde {
+		return x
+	}
+	return y
+}
+
+// includes reports whether t ∈ x.
+func (x *term) includes(t types.Type) bool {
+	// easy cases
+	switch {
+	case x == nil:
+		return false // t ∈ ∅ == false
+	case x.typ == nil:
+		return true // t ∈ 𝓤 == true
+	}
+	// ∅ ⊂ x ⊂ 𝓤
+
+	u := t
+	if x.tilde {
+		u = under(u)
+	}
+	return types.Identical(x.typ, u)
+}
+
+// subsetOf reports whether x ⊆ y.
+func (x *term) subsetOf(y *term) bool {
+	// easy cases
+	switch {
+	case x == nil:
+		return true // ∅ ⊆ y == true
+	case y == nil:
+		return false // x ⊆ ∅ == false since x != ∅
+	case y.typ == nil:
+		return true // x ⊆ 𝓤 == true
+	case x.typ == nil:
+		return false // 𝓤 ⊆ y == false since y != 𝓤
+	}
+	// ∅ ⊂ x, y ⊂ 𝓤
+
+	if x.disjoint(y) {
+		return false // x ⊆ y == false if x ∩ y == ∅
+	}
+	// x.typ == y.typ
+
+	// ~t ⊆ ~t == true
+	// ~t ⊆ T == false
+	//  T ⊆ ~t == true
+	//  T ⊆  T == true
+	return !x.tilde || y.tilde
+}
+
+// disjoint reports whether x ∩ y == ∅.
+// x.typ and y.typ must not be nil.
+func (x *term) disjoint(y *term) bool {
+	if debug && (x.typ == nil || y.typ == nil) {
+		panic("invalid argument(s)")
+	}
+	ux := x.typ
+	if y.tilde {
+		ux = under(ux)
+	}
+	uy := y.typ
+	if x.tilde {
+		uy = under(uy)
+	}
+	return !types.Identical(ux, uy)
+}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/element.go b/vendor/golang.org/x/tools/internal/typesinternal/element.go
new file mode 100644
index 0000000000..4957f02164
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typesinternal/element.go
@@ -0,0 +1,133 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typesinternal
+
+import (
+	"fmt"
+	"go/types"
+
+	"golang.org/x/tools/go/types/typeutil"
+)
+
+// ForEachElement calls f for type T and each type reachable from its
+// type through reflection. It does this by recursively stripping off
+// type constructors; in addition, for each named type N, the type *N
+// is added to the result as it may have additional methods.
+//
+// The caller must provide an initially empty set used to de-duplicate
+// identical types, potentially across multiple calls to ForEachElement.
+// (Its final value holds all the elements seen, matching the arguments
+// passed to f.)
+//
+// TODO(adonovan): share/harmonize with go/callgraph/rta.
+func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T types.Type, f func(types.Type)) {
+	var visit func(T types.Type, skip bool)
+	visit = func(T types.Type, skip bool) {
+		if !skip {
+			if seen, _ := rtypes.Set(T, true).(bool); seen {
+				return // de-dup
+			}
+
+			f(T) // notify caller of new element type
+		}
+
+		// Recursion over signatures of each method.
+		tmset := msets.MethodSet(T)
+		for i := 0; i < tmset.Len(); i++ {
+			sig := tmset.At(i).Type().(*types.Signature)
+			// It is tempting to call visit(sig, false)
+			// but, as noted in golang.org/cl/65450043,
+			// the Signature.Recv field is ignored by
+			// types.Identical and typeutil.Map, which
+			// is confusing at best.
+			//
+			// More importantly, the true signature rtype
+			// reachable from a method using reflection
+			// has no receiver but an extra ordinary parameter.
+			// For the Read method of io.Reader we want:
+			//   func(Reader, []byte) (int, error)
+			// but here sig is:
+			//   func([]byte) (int, error)
+			// with .Recv = Reader (though it is hard to
+			// notice because it doesn't affect Signature.String
+			// or types.Identical).
+			//
+			// TODO(adonovan): construct and visit the correct
+			// non-method signature with an extra parameter
+			// (though since unnamed func types have no methods
+			// there is essentially no actual demand for this).
+			//
+			// TODO(adonovan): document whether or not it is
+			// safe to skip non-exported methods (as RTA does).
+			visit(sig.Params(), true)  // skip the Tuple
+			visit(sig.Results(), true) // skip the Tuple
+		}
+
+		switch T := T.(type) {
+		case *types.Alias:
+			visit(types.Unalias(T), skip) // emulates the pre-Alias behavior
+
+		case *types.Basic:
+			// nop
+
+		case *types.Interface:
+			// nop---handled by recursion over method set.
+
+		case *types.Pointer:
+			visit(T.Elem(), false)
+
+		case *types.Slice:
+			visit(T.Elem(), false)
+
+		case *types.Chan:
+			visit(T.Elem(), false)
+
+		case *types.Map:
+			visit(T.Key(), false)
+			visit(T.Elem(), false)
+
+		case *types.Signature:
+			if T.Recv() != nil {
+				panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv()))
+			}
+			visit(T.Params(), true)  // skip the Tuple
+			visit(T.Results(), true) // skip the Tuple
+
+		case *types.Named:
+			// A pointer-to-named type can be derived from a named
+			// type via reflection.  It may have methods too.
+			visit(types.NewPointer(T), false)
+
+			// Consider 'type T struct{S}' where S has methods.
+			// Reflection provides no way to get from T to struct{S},
+			// only to S, so the method set of struct{S} is unwanted,
+			// so set 'skip' flag during recursion.
+			visit(T.Underlying(), true) // skip the unnamed type
+
+		case *types.Array:
+			visit(T.Elem(), false)
+
+		case *types.Struct:
+			for i, n := 0, T.NumFields(); i < n; i++ {
+				// TODO(adonovan): document whether or not
+				// it is safe to skip non-exported fields.
+				visit(T.Field(i).Type(), false)
+			}
+
+		case *types.Tuple:
+			for i, n := 0, T.Len(); i < n; i++ {
+				visit(T.At(i).Type(), false)
+			}
+
+		case *types.TypeParam, *types.Union:
+			// forEachReachable must not be called on parameterized types.
+			panic(T)
+
+		default:
+			panic(T)
+		}
+	}
+	visit(T, false)
+}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go b/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
index 834e05381c..235a6defc4 100644
--- a/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
+++ b/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
@@ -838,7 +838,7 @@ const (
 	// InvalidCap occurs when an argument to the cap built-in function is not of
 	// supported type.
 	//
-	// See https://golang.org/ref/spec#Lengthand_capacity for information on
+	// See https://golang.org/ref/spec#Length_and_capacity for information on
 	// which underlying types are supported as arguments to cap and len.
 	//
 	// Example:
@@ -859,7 +859,7 @@ const (
 	// InvalidCopy occurs when the arguments are not of slice type or do not
 	// have compatible type.
 	//
-	// See https://golang.org/ref/spec#Appendingand_copying_slices for more
+	// See https://golang.org/ref/spec#Appending_and_copying_slices for more
 	// information on the type requirements for the copy built-in.
 	//
 	// Example:
@@ -897,7 +897,7 @@ const (
 	// InvalidLen occurs when an argument to the len built-in function is not of
 	// supported type.
 	//
-	// See https://golang.org/ref/spec#Lengthand_capacity for information on
+	// See https://golang.org/ref/spec#Length_and_capacity for information on
 	// which underlying types are supported as arguments to cap and len.
 	//
 	// Example:
@@ -914,7 +914,7 @@ const (
 
 	// InvalidMake occurs when make is called with an unsupported type argument.
 	//
-	// See https://golang.org/ref/spec#Makingslices_maps_and_channels for
+	// See https://golang.org/ref/spec#Making_slices_maps_and_channels for
 	// information on the types that may be created using make.
 	//
 	// Example:
@@ -966,7 +966,7 @@ const (
 	//  var _ = string(x)
 	InvalidConversion
 
-	// InvalidUntypedConversion occurs when an there is no valid implicit
+	// InvalidUntypedConversion occurs when there is no valid implicit
 	// conversion from an untyped value satisfying the type constraints of the
 	// context in which it is used.
 	//
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go b/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
new file mode 100644
index 0000000000..b64f714eb3
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
@@ -0,0 +1,46 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typesinternal
+
+import (
+	"go/ast"
+	"go/types"
+	"strconv"
+)
+
+// FileQualifier returns a [types.Qualifier] function that qualifies
+// imported symbols appropriately based on the import environment of a given
+// file.
+// If the same package is imported multiple times, the last appearance is
+// recorded.
+func FileQualifier(f *ast.File, pkg *types.Package) types.Qualifier {
+	// Construct mapping of import paths to their defined names.
+	// It is only necessary to look at renaming imports.
+	imports := make(map[string]string)
+	for _, imp := range f.Imports {
+		if imp.Name != nil && imp.Name.Name != "_" {
+			path, _ := strconv.Unquote(imp.Path.Value)
+			imports[path] = imp.Name.Name
+		}
+	}
+
+	// Define qualifier to replace full package paths with names of the imports.
+	return func(p *types.Package) string {
+		if p == nil || p == pkg {
+			return ""
+		}
+
+		if name, ok := imports[p.Path()]; ok {
+			if name == "." {
+				return ""
+			} else {
+				return name
+			}
+		}
+
+		// If there is no local renaming, fall back to the package name.
+		return p.Name()
+	}
+}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/recv.go b/vendor/golang.org/x/tools/internal/typesinternal/recv.go
index fea7c8b75e..8352ea7617 100644
--- a/vendor/golang.org/x/tools/internal/typesinternal/recv.go
+++ b/vendor/golang.org/x/tools/internal/typesinternal/recv.go
@@ -6,20 +6,21 @@ package typesinternal
 
 import (
 	"go/types"
-
-	"golang.org/x/tools/internal/aliases"
 )
 
 // ReceiverNamed returns the named type (if any) associated with the
 // type of recv, which may be of the form N or *N, or aliases thereof.
 // It also reports whether a Pointer was present.
+//
+// The named result may be nil if recv is from a method on an
+// anonymous interface or struct types or in ill-typed code.
 func ReceiverNamed(recv *types.Var) (isPtr bool, named *types.Named) {
 	t := recv.Type()
-	if ptr, ok := aliases.Unalias(t).(*types.Pointer); ok {
+	if ptr, ok := types.Unalias(t).(*types.Pointer); ok {
 		isPtr = true
 		t = ptr.Elem()
 	}
-	named, _ = aliases.Unalias(t).(*types.Named)
+	named, _ = types.Unalias(t).(*types.Named)
 	return
 }
 
@@ -36,7 +37,7 @@ func ReceiverNamed(recv *types.Var) (isPtr bool, named *types.Named) {
 // indirection from the type, regardless of named types (analogous to
 // a LOAD instruction).
 func Unpointer(t types.Type) types.Type {
-	if ptr, ok := aliases.Unalias(t).(*types.Pointer); ok {
+	if ptr, ok := types.Unalias(t).(*types.Pointer); ok {
 		return ptr.Elem()
 	}
 	return t
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go
index 8392328612..3453487963 100644
--- a/vendor/golang.org/x/tools/internal/typesinternal/types.go
+++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go
@@ -11,6 +11,8 @@ import (
 	"go/types"
 	"reflect"
 	"unsafe"
+
+	"golang.org/x/tools/internal/aliases"
 )
 
 func SetUsesCgo(conf *types.Config) bool {
@@ -63,3 +65,63 @@ func NameRelativeTo(pkg *types.Package) types.Qualifier {
 		return other.Name()
 	}
 }
+
+// A NamedOrAlias is a [types.Type] that is named (as
+// defined by the spec) and capable of bearing type parameters: it
+// abstracts aliases ([types.Alias]) and defined types
+// ([types.Named]).
+//
+// Every type declared by an explicit "type" declaration is a
+// NamedOrAlias. (Built-in type symbols may additionally
+// have type [types.Basic], which is not a NamedOrAlias,
+// though the spec regards them as "named".)
+//
+// NamedOrAlias cannot expose the Origin method, because
+// [types.Alias.Origin] and [types.Named.Origin] have different
+// (covariant) result types; use [Origin] instead.
+type NamedOrAlias interface {
+	types.Type
+	Obj() *types.TypeName
+	// TODO(hxjiang): add method TypeArgs() *types.TypeList after stop supporting go1.22.
+}
+
+// TypeParams is a light shim around t.TypeParams().
+// (go/types.Alias).TypeParams requires >= 1.23.
+func TypeParams(t NamedOrAlias) *types.TypeParamList {
+	switch t := t.(type) {
+	case *types.Alias:
+		return aliases.TypeParams(t)
+	case *types.Named:
+		return t.TypeParams()
+	}
+	return nil
+}
+
+// TypeArgs is a light shim around t.TypeArgs().
+// (go/types.Alias).TypeArgs requires >= 1.23.
+func TypeArgs(t NamedOrAlias) *types.TypeList {
+	switch t := t.(type) {
+	case *types.Alias:
+		return aliases.TypeArgs(t)
+	case *types.Named:
+		return t.TypeArgs()
+	}
+	return nil
+}
+
+// Origin returns the generic type of the Named or Alias type t if it
+// is instantiated, otherwise it returns t.
+func Origin(t NamedOrAlias) NamedOrAlias {
+	switch t := t.(type) {
+	case *types.Alias:
+		return aliases.Origin(t)
+	case *types.Named:
+		return t.Origin()
+	}
+	return t
+}
+
+// IsPackageLevel reports whether obj is a package-level symbol.
+func IsPackageLevel(obj types.Object) bool {
+	return obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope()
+}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/varkind.go b/vendor/golang.org/x/tools/internal/typesinternal/varkind.go
new file mode 100644
index 0000000000..e5da049511
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typesinternal/varkind.go
@@ -0,0 +1,40 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typesinternal
+
+// TODO(adonovan): when CL 645115 lands, define the go1.25 version of
+// this API that actually does something.
+
+import "go/types"
+
+type VarKind uint8
+
+const (
+	_          VarKind = iota // (not meaningful)
+	PackageVar                // a package-level variable
+	LocalVar                  // a local variable
+	RecvVar                   // a method receiver variable
+	ParamVar                  // a function parameter variable
+	ResultVar                 // a function result variable
+	FieldVar                  // a struct field
+)
+
+func (kind VarKind) String() string {
+	return [...]string{
+		0:          "VarKind(0)",
+		PackageVar: "PackageVar",
+		LocalVar:   "LocalVar",
+		RecvVar:    "RecvVar",
+		ParamVar:   "ParamVar",
+		ResultVar:  "ResultVar",
+		FieldVar:   "FieldVar",
+	}[kind]
+}
+
+// GetVarKind returns an invalid VarKind.
+func GetVarKind(v *types.Var) VarKind { return 0 }
+
+// SetVarKind has no effect.
+func SetVarKind(v *types.Var, kind VarKind) {}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go b/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
new file mode 100644
index 0000000000..d272949c17
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
@@ -0,0 +1,392 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typesinternal
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"go/types"
+	"strings"
+)
+
+// ZeroString returns the string representation of the zero value for any type t.
+// The boolean result indicates whether the type is or contains an invalid type
+// or a non-basic (constraint) interface type.
+//
+// Even for invalid input types, ZeroString may return a partially correct
+// string representation. The caller should use the returned isValid boolean
+// to determine the validity of the expression.
+//
+// When assigning to a wider type (such as 'any'), it's the caller's
+// responsibility to handle any necessary type conversions.
+//
+// This string can be used on the right-hand side of an assignment where the
+// left-hand side has that explicit type.
+// References to named types are qualified by an appropriate (optional)
+// qualifier function.
+// Exception: This does not apply to tuples. Their string representation is
+// informational only and cannot be used in an assignment.
+//
+// See [ZeroExpr] for a variant that returns an [ast.Expr].
+func ZeroString(t types.Type, qual types.Qualifier) (_ string, isValid bool) {
+	switch t := t.(type) {
+	case *types.Basic:
+		switch {
+		case t.Info()&types.IsBoolean != 0:
+			return "false", true
+		case t.Info()&types.IsNumeric != 0:
+			return "0", true
+		case t.Info()&types.IsString != 0:
+			return `""`, true
+		case t.Kind() == types.UnsafePointer:
+			fallthrough
+		case t.Kind() == types.UntypedNil:
+			return "nil", true
+		case t.Kind() == types.Invalid:
+			return "invalid", false
+		default:
+			panic(fmt.Sprintf("ZeroString for unexpected type %v", t))
+		}
+
+	case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
+		return "nil", true
+
+	case *types.Interface:
+		if !t.IsMethodSet() {
+			return "invalid", false
+		}
+		return "nil", true
+
+	case *types.Named:
+		switch under := t.Underlying().(type) {
+		case *types.Struct, *types.Array:
+			return types.TypeString(t, qual) + "{}", true
+		default:
+			return ZeroString(under, qual)
+		}
+
+	case *types.Alias:
+		switch t.Underlying().(type) {
+		case *types.Struct, *types.Array:
+			return types.TypeString(t, qual) + "{}", true
+		default:
+			// A type parameter can have alias but alias type's underlying type
+			// can never be a type parameter.
+			// Use types.Unalias to preserve the info of type parameter instead
+			// of call Underlying() going right through and get the underlying
+			// type of the type parameter which is always an interface.
+			return ZeroString(types.Unalias(t), qual)
+		}
+
+	case *types.Array, *types.Struct:
+		return types.TypeString(t, qual) + "{}", true
+
+	case *types.TypeParam:
+		// Assumes func new is not shadowed.
+		return "*new(" + types.TypeString(t, qual) + ")", true
+
+	case *types.Tuple:
+		// Tuples are not normal values.
+		// We are currently format as "(t[0], ..., t[n])". Could be something else.
+		isValid := true
+		components := make([]string, t.Len())
+		for i := 0; i < t.Len(); i++ {
+			comp, ok := ZeroString(t.At(i).Type(), qual)
+
+			components[i] = comp
+			isValid = isValid && ok
+		}
+		return "(" + strings.Join(components, ", ") + ")", isValid
+
+	case *types.Union:
+		// Variables of these types cannot be created, so it makes
+		// no sense to ask for their zero value.
+		panic(fmt.Sprintf("invalid type for a variable: %v", t))
+
+	default:
+		panic(t) // unreachable.
+	}
+}
+
+// ZeroExpr returns the ast.Expr representation of the zero value for any type t.
+// The boolean result indicates whether the type is or contains an invalid type
+// or a non-basic (constraint) interface type.
+//
+// Even for invalid input types, ZeroExpr may return a partially correct ast.Expr
+// representation. The caller should use the returned isValid boolean to determine
+// the validity of the expression.
+//
+// This function is designed for types suitable for variables and should not be
+// used with Tuple or Union types.References to named types are qualified by an
+// appropriate (optional) qualifier function.
+//
+// See [ZeroString] for a variant that returns a string.
+func ZeroExpr(t types.Type, qual types.Qualifier) (_ ast.Expr, isValid bool) {
+	switch t := t.(type) {
+	case *types.Basic:
+		switch {
+		case t.Info()&types.IsBoolean != 0:
+			return &ast.Ident{Name: "false"}, true
+		case t.Info()&types.IsNumeric != 0:
+			return &ast.BasicLit{Kind: token.INT, Value: "0"}, true
+		case t.Info()&types.IsString != 0:
+			return &ast.BasicLit{Kind: token.STRING, Value: `""`}, true
+		case t.Kind() == types.UnsafePointer:
+			fallthrough
+		case t.Kind() == types.UntypedNil:
+			return ast.NewIdent("nil"), true
+		case t.Kind() == types.Invalid:
+			return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false
+		default:
+			panic(fmt.Sprintf("ZeroExpr for unexpected type %v", t))
+		}
+
+	case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
+		return ast.NewIdent("nil"), true
+
+	case *types.Interface:
+		if !t.IsMethodSet() {
+			return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false
+		}
+		return ast.NewIdent("nil"), true
+
+	case *types.Named:
+		switch under := t.Underlying().(type) {
+		case *types.Struct, *types.Array:
+			return &ast.CompositeLit{
+				Type: TypeExpr(t, qual),
+			}, true
+		default:
+			return ZeroExpr(under, qual)
+		}
+
+	case *types.Alias:
+		switch t.Underlying().(type) {
+		case *types.Struct, *types.Array:
+			return &ast.CompositeLit{
+				Type: TypeExpr(t, qual),
+			}, true
+		default:
+			return ZeroExpr(types.Unalias(t), qual)
+		}
+
+	case *types.Array, *types.Struct:
+		return &ast.CompositeLit{
+			Type: TypeExpr(t, qual),
+		}, true
+
+	case *types.TypeParam:
+		return &ast.StarExpr{ // *new(T)
+			X: &ast.CallExpr{
+				// Assumes func new is not shadowed.
+				Fun: ast.NewIdent("new"),
+				Args: []ast.Expr{
+					ast.NewIdent(t.Obj().Name()),
+				},
+			},
+		}, true
+
+	case *types.Tuple:
+		// Unlike ZeroString, there is no ast.Expr can express tuple by
+		// "(t[0], ..., t[n])".
+		panic(fmt.Sprintf("invalid type for a variable: %v", t))
+
+	case *types.Union:
+		// Variables of these types cannot be created, so it makes
+		// no sense to ask for their zero value.
+		panic(fmt.Sprintf("invalid type for a variable: %v", t))
+
+	default:
+		panic(t) // unreachable.
+	}
+}
+
+// IsZeroExpr uses simple syntactic heuristics to report whether expr
+// is a obvious zero value, such as 0, "", nil, or false.
+// It cannot do better without type information.
+func IsZeroExpr(expr ast.Expr) bool {
+	switch e := expr.(type) {
+	case *ast.BasicLit:
+		return e.Value == "0" || e.Value == `""`
+	case *ast.Ident:
+		return e.Name == "nil" || e.Name == "false"
+	default:
+		return false
+	}
+}
+
+// TypeExpr returns syntax for the specified type. References to named types
+// are qualified by an appropriate (optional) qualifier function.
+// It may panic for types such as Tuple or Union.
+func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
+	switch t := t.(type) {
+	case *types.Basic:
+		switch t.Kind() {
+		case types.UnsafePointer:
+			return &ast.SelectorExpr{X: ast.NewIdent(qual(types.NewPackage("unsafe", "unsafe"))), Sel: ast.NewIdent("Pointer")}
+		default:
+			return ast.NewIdent(t.Name())
+		}
+
+	case *types.Pointer:
+		return &ast.UnaryExpr{
+			Op: token.MUL,
+			X:  TypeExpr(t.Elem(), qual),
+		}
+
+	case *types.Array:
+		return &ast.ArrayType{
+			Len: &ast.BasicLit{
+				Kind:  token.INT,
+				Value: fmt.Sprintf("%d", t.Len()),
+			},
+			Elt: TypeExpr(t.Elem(), qual),
+		}
+
+	case *types.Slice:
+		return &ast.ArrayType{
+			Elt: TypeExpr(t.Elem(), qual),
+		}
+
+	case *types.Map:
+		return &ast.MapType{
+			Key:   TypeExpr(t.Key(), qual),
+			Value: TypeExpr(t.Elem(), qual),
+		}
+
+	case *types.Chan:
+		dir := ast.ChanDir(t.Dir())
+		if t.Dir() == types.SendRecv {
+			dir = ast.SEND | ast.RECV
+		}
+		return &ast.ChanType{
+			Dir:   dir,
+			Value: TypeExpr(t.Elem(), qual),
+		}
+
+	case *types.Signature:
+		var params []*ast.Field
+		for i := 0; i < t.Params().Len(); i++ {
+			params = append(params, &ast.Field{
+				Type: TypeExpr(t.Params().At(i).Type(), qual),
+				Names: []*ast.Ident{
+					{
+						Name: t.Params().At(i).Name(),
+					},
+				},
+			})
+		}
+		if t.Variadic() {
+			last := params[len(params)-1]
+			last.Type = &ast.Ellipsis{Elt: last.Type.(*ast.ArrayType).Elt}
+		}
+		var returns []*ast.Field
+		for i := 0; i < t.Results().Len(); i++ {
+			returns = append(returns, &ast.Field{
+				Type: TypeExpr(t.Results().At(i).Type(), qual),
+			})
+		}
+		return &ast.FuncType{
+			Params: &ast.FieldList{
+				List: params,
+			},
+			Results: &ast.FieldList{
+				List: returns,
+			},
+		}
+
+	case *types.TypeParam:
+		pkgName := qual(t.Obj().Pkg())
+		if pkgName == "" || t.Obj().Pkg() == nil {
+			return ast.NewIdent(t.Obj().Name())
+		}
+		return &ast.SelectorExpr{
+			X:   ast.NewIdent(pkgName),
+			Sel: ast.NewIdent(t.Obj().Name()),
+		}
+
+	// types.TypeParam also implements interface NamedOrAlias. To differentiate,
+	// case TypeParam need to be present before case NamedOrAlias.
+	// TODO(hxjiang): remove this comment once TypeArgs() is added to interface
+	// NamedOrAlias.
+	case NamedOrAlias:
+		var expr ast.Expr = ast.NewIdent(t.Obj().Name())
+		if pkgName := qual(t.Obj().Pkg()); pkgName != "." && pkgName != "" {
+			expr = &ast.SelectorExpr{
+				X:   ast.NewIdent(pkgName),
+				Sel: expr.(*ast.Ident),
+			}
+		}
+
+		// TODO(hxjiang): call t.TypeArgs after adding method TypeArgs() to
+		// typesinternal.NamedOrAlias.
+		if hasTypeArgs, ok := t.(interface{ TypeArgs() *types.TypeList }); ok {
+			if typeArgs := hasTypeArgs.TypeArgs(); typeArgs != nil && typeArgs.Len() > 0 {
+				var indices []ast.Expr
+				for i := range typeArgs.Len() {
+					indices = append(indices, TypeExpr(typeArgs.At(i), qual))
+				}
+				expr = &ast.IndexListExpr{
+					X:       expr,
+					Indices: indices,
+				}
+			}
+		}
+
+		return expr
+
+	case *types.Struct:
+		return ast.NewIdent(t.String())
+
+	case *types.Interface:
+		return ast.NewIdent(t.String())
+
+	case *types.Union:
+		if t.Len() == 0 {
+			panic("Union type should have at least one term")
+		}
+		// Same as go/ast, the return expression will put last term in the
+		// Y field at topmost level of BinaryExpr.
+		// For union of type "float32 | float64 | int64", the structure looks
+		// similar to:
+		// {
+		// 	X: {
+		// 		X: float32,
+		// 		Op: |
+		// 		Y: float64,
+		// 	}
+		// 	Op: |,
+		// 	Y: int64,
+		// }
+		var union ast.Expr
+		for i := range t.Len() {
+			term := t.Term(i)
+			termExpr := TypeExpr(term.Type(), qual)
+			if term.Tilde() {
+				termExpr = &ast.UnaryExpr{
+					Op: token.TILDE,
+					X:  termExpr,
+				}
+			}
+			if i == 0 {
+				union = termExpr
+			} else {
+				union = &ast.BinaryExpr{
+					X:  union,
+					Op: token.OR,
+					Y:  termExpr,
+				}
+			}
+		}
+		return union
+
+	case *types.Tuple:
+		panic("invalid input type types.Tuple")
+
+	default:
+		panic("unreachable")
+	}
+}
diff --git a/vendor/golang.org/x/tools/internal/versions/constraint.go b/vendor/golang.org/x/tools/internal/versions/constraint.go
deleted file mode 100644
index 179063d484..0000000000
--- a/vendor/golang.org/x/tools/internal/versions/constraint.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2024 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package versions
-
-import "go/build/constraint"
-
-// ConstraintGoVersion is constraint.GoVersion (if built with go1.21+).
-// Otherwise nil.
-//
-// Deprecate once x/tools is after go1.21.
-var ConstraintGoVersion func(x constraint.Expr) string
diff --git a/vendor/golang.org/x/tools/internal/versions/toolchain.go b/vendor/golang.org/x/tools/internal/versions/toolchain.go
deleted file mode 100644
index 377bf7a53b..0000000000
--- a/vendor/golang.org/x/tools/internal/versions/toolchain.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2024 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package versions
-
-// toolchain is maximum version (<1.22) that the go toolchain used
-// to build the current tool is known to support.
-//
-// When a tool is built with >=1.22, the value of toolchain is unused.
-//
-// x/tools does not support building with go <1.18. So we take this
-// as the minimum possible maximum.
-var toolchain string = Go1_18
diff --git a/vendor/golang.org/x/tools/internal/versions/types.go b/vendor/golang.org/x/tools/internal/versions/types.go
index 562eef21fa..0fc10ce4eb 100644
--- a/vendor/golang.org/x/tools/internal/versions/types.go
+++ b/vendor/golang.org/x/tools/internal/versions/types.go
@@ -5,15 +5,29 @@
 package versions
 
 import (
+	"go/ast"
 	"go/types"
 )
 
-// GoVersion returns the Go version of the type package.
-// It returns zero if no version can be determined.
-func GoVersion(pkg *types.Package) string {
-	// TODO(taking): x/tools can call GoVersion() [from 1.21] after 1.25.
-	if pkg, ok := any(pkg).(interface{ GoVersion() string }); ok {
-		return pkg.GoVersion()
+// FileVersion returns a file's Go version.
+// The reported version is an unknown Future version if a
+// version cannot be determined.
+func FileVersion(info *types.Info, file *ast.File) string {
+	// In tools built with Go >= 1.22, the Go version of a file
+	// follow a cascades of sources:
+	// 1) types.Info.FileVersion, which follows the cascade:
+	//   1.a) file version (ast.File.GoVersion),
+	//   1.b) the package version (types.Config.GoVersion), or
+	// 2) is some unknown Future version.
+	//
+	// File versions require a valid package version to be provided to types
+	// in Config.GoVersion. Config.GoVersion is either from the package's module
+	// or the toolchain (go run). This value should be provided by go/packages
+	// or unitchecker.Config.GoVersion.
+	if v := info.FileVersions[file]; IsValid(v) {
+		return v
 	}
-	return ""
+	// Note: we could instead return runtime.Version() [if valid].
+	// This would act as a max version on what a tool can support.
+	return Future
 }
diff --git a/vendor/golang.org/x/tools/internal/versions/types_go121.go b/vendor/golang.org/x/tools/internal/versions/types_go121.go
deleted file mode 100644
index b4345d3349..0000000000
--- a/vendor/golang.org/x/tools/internal/versions/types_go121.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.22
-// +build !go1.22
-
-package versions
-
-import (
-	"go/ast"
-	"go/types"
-)
-
-// FileVersion returns a language version (<=1.21) derived from runtime.Version()
-// or an unknown future version.
-func FileVersion(info *types.Info, file *ast.File) string {
-	// In x/tools built with Go <= 1.21, we do not have Info.FileVersions
-	// available. We use a go version derived from the toolchain used to
-	// compile the tool by default.
-	// This will be <= go1.21. We take this as the maximum version that
-	// this tool can support.
-	//
-	// There are no features currently in x/tools that need to tell fine grained
-	// differences for versions <1.22.
-	return toolchain
-}
-
-// InitFileVersions is a noop when compiled with this Go version.
-func InitFileVersions(*types.Info) {}
diff --git a/vendor/golang.org/x/tools/internal/versions/types_go122.go b/vendor/golang.org/x/tools/internal/versions/types_go122.go
deleted file mode 100644
index aac5db62c9..0000000000
--- a/vendor/golang.org/x/tools/internal/versions/types_go122.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.22
-// +build go1.22
-
-package versions
-
-import (
-	"go/ast"
-	"go/types"
-)
-
-// FileVersion returns a file's Go version.
-// The reported version is an unknown Future version if a
-// version cannot be determined.
-func FileVersion(info *types.Info, file *ast.File) string {
-	// In tools built with Go >= 1.22, the Go version of a file
-	// follow a cascades of sources:
-	// 1) types.Info.FileVersion, which follows the cascade:
-	//   1.a) file version (ast.File.GoVersion),
-	//   1.b) the package version (types.Config.GoVersion), or
-	// 2) is some unknown Future version.
-	//
-	// File versions require a valid package version to be provided to types
-	// in Config.GoVersion. Config.GoVersion is either from the package's module
-	// or the toolchain (go run). This value should be provided by go/packages
-	// or unitchecker.Config.GoVersion.
-	if v := info.FileVersions[file]; IsValid(v) {
-		return v
-	}
-	// Note: we could instead return runtime.Version() [if valid].
-	// This would act as a max version on what a tool can support.
-	return Future
-}
-
-// InitFileVersions initializes info to record Go versions for Go files.
-func InitFileVersions(info *types.Info) {
-	info.FileVersions = make(map[*ast.File]string)
-}
diff --git a/vendor/golang.org/x/tools/txtar/fs.go b/vendor/golang.org/x/tools/txtar/fs.go
index e37397e7b7..fc8df12c18 100644
--- a/vendor/golang.org/x/tools/txtar/fs.go
+++ b/vendor/golang.org/x/tools/txtar/fs.go
@@ -10,6 +10,7 @@ import (
 	"io"
 	"io/fs"
 	"path"
+	"slices"
 	"time"
 )
 
@@ -152,10 +153,7 @@ func (fsys *filesystem) ReadFile(name string) ([]byte, error) {
 		return nil, err
 	}
 	if file, ok := file.(*openFile); ok {
-		// TODO: use slices.Clone once x/tools has 1.21 available.
-		cp := make([]byte, file.size)
-		copy(cp, file.data)
-		return cp, err
+		return slices.Clone(file.data), nil
 	}
 	return nil, &fs.PathError{Op: "read", Path: name, Err: fs.ErrInvalid}
 }
diff --git a/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go b/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go
deleted file mode 100644
index 7172b43d38..0000000000
--- a/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go
+++ /dev/null
@@ -1,496 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: google/protobuf/any.proto
-
-// Package anypb contains generated types for google/protobuf/any.proto.
-//
-// The Any message is a dynamic representation of any other message value.
-// It is functionally a tuple of the full name of the remote message type and
-// the serialized bytes of the remote message value.
-//
-// # Constructing an Any
-//
-// An Any message containing another message value is constructed using New:
-//
-//	any, err := anypb.New(m)
-//	if err != nil {
-//		... // handle error
-//	}
-//	... // make use of any
-//
-// # Unmarshaling an Any
-//
-// With a populated Any message, the underlying message can be serialized into
-// a remote concrete message value in a few ways.
-//
-// If the exact concrete type is known, then a new (or pre-existing) instance
-// of that message can be passed to the UnmarshalTo method:
-//
-//	m := new(foopb.MyMessage)
-//	if err := any.UnmarshalTo(m); err != nil {
-//		... // handle error
-//	}
-//	... // make use of m
-//
-// If the exact concrete type is not known, then the UnmarshalNew method can be
-// used to unmarshal the contents into a new instance of the remote message type:
-//
-//	m, err := any.UnmarshalNew()
-//	if err != nil {
-//		... // handle error
-//	}
-//	... // make use of m
-//
-// UnmarshalNew uses the global type registry to resolve the message type and
-// construct a new instance of that message to unmarshal into. In order for a
-// message type to appear in the global registry, the Go type representing that
-// protobuf message type must be linked into the Go binary. For messages
-// generated by protoc-gen-go, this is achieved through an import of the
-// generated Go package representing a .proto file.
-//
-// A common pattern with UnmarshalNew is to use a type switch with the resulting
-// proto.Message value:
-//
-//	switch m := m.(type) {
-//	case *foopb.MyMessage:
-//		... // make use of m as a *foopb.MyMessage
-//	case *barpb.OtherMessage:
-//		... // make use of m as a *barpb.OtherMessage
-//	case *bazpb.SomeMessage:
-//		... // make use of m as a *bazpb.SomeMessage
-//	}
-//
-// This pattern ensures that the generated packages containing the message types
-// listed in the case clauses are linked into the Go binary and therefore also
-// registered in the global registry.
-//
-// # Type checking an Any
-//
-// In order to type check whether an Any message represents some other message,
-// then use the MessageIs method:
-//
-//	if any.MessageIs((*foopb.MyMessage)(nil)) {
-//		... // make use of any, knowing that it contains a foopb.MyMessage
-//	}
-//
-// The MessageIs method can also be used with an allocated instance of the target
-// message type if the intention is to unmarshal into it if the type matches:
-//
-//	m := new(foopb.MyMessage)
-//	if any.MessageIs(m) {
-//		if err := any.UnmarshalTo(m); err != nil {
-//			... // handle error
-//		}
-//		... // make use of m
-//	}
-package anypb
-
-import (
-	proto "google.golang.org/protobuf/proto"
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoregistry "google.golang.org/protobuf/reflect/protoregistry"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	reflect "reflect"
-	strings "strings"
-	sync "sync"
-)
-
-// `Any` contains an arbitrary serialized protocol buffer message along with a
-// URL that describes the type of the serialized message.
-//
-// Protobuf library provides support to pack/unpack Any values in the form
-// of utility functions or additional generated methods of the Any type.
-//
-// Example 1: Pack and unpack a message in C++.
-//
-//	Foo foo = ...;
-//	Any any;
-//	any.PackFrom(foo);
-//	...
-//	if (any.UnpackTo(&foo)) {
-//	  ...
-//	}
-//
-// Example 2: Pack and unpack a message in Java.
-//
-//	   Foo foo = ...;
-//	   Any any = Any.pack(foo);
-//	   ...
-//	   if (any.is(Foo.class)) {
-//	     foo = any.unpack(Foo.class);
-//	   }
-//	   // or ...
-//	   if (any.isSameTypeAs(Foo.getDefaultInstance())) {
-//	     foo = any.unpack(Foo.getDefaultInstance());
-//	   }
-//
-//	Example 3: Pack and unpack a message in Python.
-//
-//	   foo = Foo(...)
-//	   any = Any()
-//	   any.Pack(foo)
-//	   ...
-//	   if any.Is(Foo.DESCRIPTOR):
-//	     any.Unpack(foo)
-//	     ...
-//
-//	Example 4: Pack and unpack a message in Go
-//
-//	    foo := &pb.Foo{...}
-//	    any, err := anypb.New(foo)
-//	    if err != nil {
-//	      ...
-//	    }
-//	    ...
-//	    foo := &pb.Foo{}
-//	    if err := any.UnmarshalTo(foo); err != nil {
-//	      ...
-//	    }
-//
-// The pack methods provided by protobuf library will by default use
-// 'type.googleapis.com/full.type.name' as the type URL and the unpack
-// methods only use the fully qualified type name after the last '/'
-// in the type URL, for example "foo.bar.com/x/y.z" will yield type
-// name "y.z".
-//
-// JSON
-// ====
-// The JSON representation of an `Any` value uses the regular
-// representation of the deserialized, embedded message, with an
-// additional field `@type` which contains the type URL. Example:
-//
-//	package google.profile;
-//	message Person {
-//	  string first_name = 1;
-//	  string last_name = 2;
-//	}
-//
-//	{
-//	  "@type": "type.googleapis.com/google.profile.Person",
-//	  "firstName": ,
-//	  "lastName": 
-//	}
-//
-// If the embedded message type is well-known and has a custom JSON
-// representation, that representation will be embedded adding a field
-// `value` which holds the custom JSON in addition to the `@type`
-// field. Example (for message [google.protobuf.Duration][]):
-//
-//	{
-//	  "@type": "type.googleapis.com/google.protobuf.Duration",
-//	  "value": "1.212s"
-//	}
-type Any struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	// A URL/resource name that uniquely identifies the type of the serialized
-	// protocol buffer message. This string must contain at least
-	// one "/" character. The last segment of the URL's path must represent
-	// the fully qualified name of the type (as in
-	// `path/google.protobuf.Duration`). The name should be in a canonical form
-	// (e.g., leading "." is not accepted).
-	//
-	// In practice, teams usually precompile into the binary all types that they
-	// expect it to use in the context of Any. However, for URLs which use the
-	// scheme `http`, `https`, or no scheme, one can optionally set up a type
-	// server that maps type URLs to message definitions as follows:
-	//
-	//   - If no scheme is provided, `https` is assumed.
-	//   - An HTTP GET on the URL must yield a [google.protobuf.Type][]
-	//     value in binary format, or produce an error.
-	//   - Applications are allowed to cache lookup results based on the
-	//     URL, or have them precompiled into a binary to avoid any
-	//     lookup. Therefore, binary compatibility needs to be preserved
-	//     on changes to types. (Use versioned type names to manage
-	//     breaking changes.)
-	//
-	// Note: this functionality is not currently available in the official
-	// protobuf release, and it is not used for type URLs beginning with
-	// type.googleapis.com. As of May 2023, there are no widely used type server
-	// implementations and no plans to implement one.
-	//
-	// Schemes other than `http`, `https` (or the empty scheme) might be
-	// used with implementation specific semantics.
-	TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
-	// Must be a valid serialized protocol buffer of the above specified type.
-	Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
-}
-
-// New marshals src into a new Any instance.
-func New(src proto.Message) (*Any, error) {
-	dst := new(Any)
-	if err := dst.MarshalFrom(src); err != nil {
-		return nil, err
-	}
-	return dst, nil
-}
-
-// MarshalFrom marshals src into dst as the underlying message
-// using the provided marshal options.
-//
-// If no options are specified, call dst.MarshalFrom instead.
-func MarshalFrom(dst *Any, src proto.Message, opts proto.MarshalOptions) error {
-	const urlPrefix = "type.googleapis.com/"
-	if src == nil {
-		return protoimpl.X.NewError("invalid nil source message")
-	}
-	b, err := opts.Marshal(src)
-	if err != nil {
-		return err
-	}
-	dst.TypeUrl = urlPrefix + string(src.ProtoReflect().Descriptor().FullName())
-	dst.Value = b
-	return nil
-}
-
-// UnmarshalTo unmarshals the underlying message from src into dst
-// using the provided unmarshal options.
-// It reports an error if dst is not of the right message type.
-//
-// If no options are specified, call src.UnmarshalTo instead.
-func UnmarshalTo(src *Any, dst proto.Message, opts proto.UnmarshalOptions) error {
-	if src == nil {
-		return protoimpl.X.NewError("invalid nil source message")
-	}
-	if !src.MessageIs(dst) {
-		got := dst.ProtoReflect().Descriptor().FullName()
-		want := src.MessageName()
-		return protoimpl.X.NewError("mismatched message type: got %q, want %q", got, want)
-	}
-	return opts.Unmarshal(src.GetValue(), dst)
-}
-
-// UnmarshalNew unmarshals the underlying message from src into dst,
-// which is newly created message using a type resolved from the type URL.
-// The message type is resolved according to opt.Resolver,
-// which should implement protoregistry.MessageTypeResolver.
-// It reports an error if the underlying message type could not be resolved.
-//
-// If no options are specified, call src.UnmarshalNew instead.
-func UnmarshalNew(src *Any, opts proto.UnmarshalOptions) (dst proto.Message, err error) {
-	if src.GetTypeUrl() == "" {
-		return nil, protoimpl.X.NewError("invalid empty type URL")
-	}
-	if opts.Resolver == nil {
-		opts.Resolver = protoregistry.GlobalTypes
-	}
-	r, ok := opts.Resolver.(protoregistry.MessageTypeResolver)
-	if !ok {
-		return nil, protoregistry.NotFound
-	}
-	mt, err := r.FindMessageByURL(src.GetTypeUrl())
-	if err != nil {
-		if err == protoregistry.NotFound {
-			return nil, err
-		}
-		return nil, protoimpl.X.NewError("could not resolve %q: %v", src.GetTypeUrl(), err)
-	}
-	dst = mt.New().Interface()
-	return dst, opts.Unmarshal(src.GetValue(), dst)
-}
-
-// MessageIs reports whether the underlying message is of the same type as m.
-func (x *Any) MessageIs(m proto.Message) bool {
-	if m == nil {
-		return false
-	}
-	url := x.GetTypeUrl()
-	name := string(m.ProtoReflect().Descriptor().FullName())
-	if !strings.HasSuffix(url, name) {
-		return false
-	}
-	return len(url) == len(name) || url[len(url)-len(name)-1] == '/'
-}
-
-// MessageName reports the full name of the underlying message,
-// returning an empty string if invalid.
-func (x *Any) MessageName() protoreflect.FullName {
-	url := x.GetTypeUrl()
-	name := protoreflect.FullName(url)
-	if i := strings.LastIndexByte(url, '/'); i >= 0 {
-		name = name[i+len("/"):]
-	}
-	if !name.IsValid() {
-		return ""
-	}
-	return name
-}
-
-// MarshalFrom marshals m into x as the underlying message.
-func (x *Any) MarshalFrom(m proto.Message) error {
-	return MarshalFrom(x, m, proto.MarshalOptions{})
-}
-
-// UnmarshalTo unmarshals the contents of the underlying message of x into m.
-// It resets m before performing the unmarshal operation.
-// It reports an error if m is not of the right message type.
-func (x *Any) UnmarshalTo(m proto.Message) error {
-	return UnmarshalTo(x, m, proto.UnmarshalOptions{})
-}
-
-// UnmarshalNew unmarshals the contents of the underlying message of x into
-// a newly allocated message of the specified type.
-// It reports an error if the underlying message type could not be resolved.
-func (x *Any) UnmarshalNew() (proto.Message, error) {
-	return UnmarshalNew(x, proto.UnmarshalOptions{})
-}
-
-func (x *Any) Reset() {
-	*x = Any{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_google_protobuf_any_proto_msgTypes[0]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *Any) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Any) ProtoMessage() {}
-
-func (x *Any) ProtoReflect() protoreflect.Message {
-	mi := &file_google_protobuf_any_proto_msgTypes[0]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use Any.ProtoReflect.Descriptor instead.
-func (*Any) Descriptor() ([]byte, []int) {
-	return file_google_protobuf_any_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Any) GetTypeUrl() string {
-	if x != nil {
-		return x.TypeUrl
-	}
-	return ""
-}
-
-func (x *Any) GetValue() []byte {
-	if x != nil {
-		return x.Value
-	}
-	return nil
-}
-
-var File_google_protobuf_any_proto protoreflect.FileDescriptor
-
-var file_google_protobuf_any_proto_rawDesc = []byte{
-	0x0a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x67, 0x6f, 0x6f,
-	0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x36, 0x0a, 0x03,
-	0x41, 0x6e, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14,
-	0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76,
-	0x61, 0x6c, 0x75, 0x65, 0x42, 0x76, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
-	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x08, 0x41, 0x6e, 0x79,
-	0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
-	0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f,
-	0x61, 0x6e, 0x79, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f,
-	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65,
-	0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
-	file_google_protobuf_any_proto_rawDescOnce sync.Once
-	file_google_protobuf_any_proto_rawDescData = file_google_protobuf_any_proto_rawDesc
-)
-
-func file_google_protobuf_any_proto_rawDescGZIP() []byte {
-	file_google_protobuf_any_proto_rawDescOnce.Do(func() {
-		file_google_protobuf_any_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_protobuf_any_proto_rawDescData)
-	})
-	return file_google_protobuf_any_proto_rawDescData
-}
-
-var file_google_protobuf_any_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_google_protobuf_any_proto_goTypes = []any{
-	(*Any)(nil), // 0: google.protobuf.Any
-}
-var file_google_protobuf_any_proto_depIdxs = []int32{
-	0, // [0:0] is the sub-list for method output_type
-	0, // [0:0] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_google_protobuf_any_proto_init() }
-func file_google_protobuf_any_proto_init() {
-	if File_google_protobuf_any_proto != nil {
-		return
-	}
-	if !protoimpl.UnsafeEnabled {
-		file_google_protobuf_any_proto_msgTypes[0].Exporter = func(v any, i int) any {
-			switch v := v.(*Any); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_google_protobuf_any_proto_rawDesc,
-			NumEnums:      0,
-			NumMessages:   1,
-			NumExtensions: 0,
-			NumServices:   0,
-		},
-		GoTypes:           file_google_protobuf_any_proto_goTypes,
-		DependencyIndexes: file_google_protobuf_any_proto_depIdxs,
-		MessageInfos:      file_google_protobuf_any_proto_msgTypes,
-	}.Build()
-	File_google_protobuf_any_proto = out.File
-	file_google_protobuf_any_proto_rawDesc = nil
-	file_google_protobuf_any_proto_goTypes = nil
-	file_google_protobuf_any_proto_depIdxs = nil
-}
diff --git a/vendor/google.golang.org/protobuf/types/known/durationpb/duration.pb.go b/vendor/google.golang.org/protobuf/types/known/durationpb/duration.pb.go
deleted file mode 100644
index 1b71bcd910..0000000000
--- a/vendor/google.golang.org/protobuf/types/known/durationpb/duration.pb.go
+++ /dev/null
@@ -1,374 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: google/protobuf/duration.proto
-
-// Package durationpb contains generated types for google/protobuf/duration.proto.
-//
-// The Duration message represents a signed span of time.
-//
-// # Conversion to a Go Duration
-//
-// The AsDuration method can be used to convert a Duration message to a
-// standard Go time.Duration value:
-//
-//	d := dur.AsDuration()
-//	... // make use of d as a time.Duration
-//
-// Converting to a time.Duration is a common operation so that the extensive
-// set of time-based operations provided by the time package can be leveraged.
-// See https://golang.org/pkg/time for more information.
-//
-// The AsDuration method performs the conversion on a best-effort basis.
-// Durations with denormal values (e.g., nanoseconds beyond -99999999 and
-// +99999999, inclusive; or seconds and nanoseconds with opposite signs)
-// are normalized during the conversion to a time.Duration. To manually check for
-// invalid Duration per the documented limitations in duration.proto,
-// additionally call the CheckValid method:
-//
-//	if err := dur.CheckValid(); err != nil {
-//		... // handle error
-//	}
-//
-// Note that the documented limitations in duration.proto does not protect a
-// Duration from overflowing the representable range of a time.Duration in Go.
-// The AsDuration method uses saturation arithmetic such that an overflow clamps
-// the resulting value to the closest representable value (e.g., math.MaxInt64
-// for positive overflow and math.MinInt64 for negative overflow).
-//
-// # Conversion from a Go Duration
-//
-// The durationpb.New function can be used to construct a Duration message
-// from a standard Go time.Duration value:
-//
-//	dur := durationpb.New(d)
-//	... // make use of d as a *durationpb.Duration
-package durationpb
-
-import (
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	math "math"
-	reflect "reflect"
-	sync "sync"
-	time "time"
-)
-
-// A Duration represents a signed, fixed-length span of time represented
-// as a count of seconds and fractions of seconds at nanosecond
-// resolution. It is independent of any calendar and concepts like "day"
-// or "month". It is related to Timestamp in that the difference between
-// two Timestamp values is a Duration and it can be added or subtracted
-// from a Timestamp. Range is approximately +-10,000 years.
-//
-// # Examples
-//
-// Example 1: Compute Duration from two Timestamps in pseudo code.
-//
-//	Timestamp start = ...;
-//	Timestamp end = ...;
-//	Duration duration = ...;
-//
-//	duration.seconds = end.seconds - start.seconds;
-//	duration.nanos = end.nanos - start.nanos;
-//
-//	if (duration.seconds < 0 && duration.nanos > 0) {
-//	  duration.seconds += 1;
-//	  duration.nanos -= 1000000000;
-//	} else if (duration.seconds > 0 && duration.nanos < 0) {
-//	  duration.seconds -= 1;
-//	  duration.nanos += 1000000000;
-//	}
-//
-// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
-//
-//	Timestamp start = ...;
-//	Duration duration = ...;
-//	Timestamp end = ...;
-//
-//	end.seconds = start.seconds + duration.seconds;
-//	end.nanos = start.nanos + duration.nanos;
-//
-//	if (end.nanos < 0) {
-//	  end.seconds -= 1;
-//	  end.nanos += 1000000000;
-//	} else if (end.nanos >= 1000000000) {
-//	  end.seconds += 1;
-//	  end.nanos -= 1000000000;
-//	}
-//
-// Example 3: Compute Duration from datetime.timedelta in Python.
-//
-//	td = datetime.timedelta(days=3, minutes=10)
-//	duration = Duration()
-//	duration.FromTimedelta(td)
-//
-// # JSON Mapping
-//
-// In JSON format, the Duration type is encoded as a string rather than an
-// object, where the string ends in the suffix "s" (indicating seconds) and
-// is preceded by the number of seconds, with nanoseconds expressed as
-// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
-// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
-// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
-// microsecond should be expressed in JSON format as "3.000001s".
-type Duration struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	// Signed seconds of the span of time. Must be from -315,576,000,000
-	// to +315,576,000,000 inclusive. Note: these bounds are computed from:
-	// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
-	Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
-	// Signed fractions of a second at nanosecond resolution of the span
-	// of time. Durations less than one second are represented with a 0
-	// `seconds` field and a positive or negative `nanos` field. For durations
-	// of one second or more, a non-zero value for the `nanos` field must be
-	// of the same sign as the `seconds` field. Must be from -999,999,999
-	// to +999,999,999 inclusive.
-	Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
-}
-
-// New constructs a new Duration from the provided time.Duration.
-func New(d time.Duration) *Duration {
-	nanos := d.Nanoseconds()
-	secs := nanos / 1e9
-	nanos -= secs * 1e9
-	return &Duration{Seconds: int64(secs), Nanos: int32(nanos)}
-}
-
-// AsDuration converts x to a time.Duration,
-// returning the closest duration value in the event of overflow.
-func (x *Duration) AsDuration() time.Duration {
-	secs := x.GetSeconds()
-	nanos := x.GetNanos()
-	d := time.Duration(secs) * time.Second
-	overflow := d/time.Second != time.Duration(secs)
-	d += time.Duration(nanos) * time.Nanosecond
-	overflow = overflow || (secs < 0 && nanos < 0 && d > 0)
-	overflow = overflow || (secs > 0 && nanos > 0 && d < 0)
-	if overflow {
-		switch {
-		case secs < 0:
-			return time.Duration(math.MinInt64)
-		case secs > 0:
-			return time.Duration(math.MaxInt64)
-		}
-	}
-	return d
-}
-
-// IsValid reports whether the duration is valid.
-// It is equivalent to CheckValid == nil.
-func (x *Duration) IsValid() bool {
-	return x.check() == 0
-}
-
-// CheckValid returns an error if the duration is invalid.
-// In particular, it checks whether the value is within the range of
-// -10000 years to +10000 years inclusive.
-// An error is reported for a nil Duration.
-func (x *Duration) CheckValid() error {
-	switch x.check() {
-	case invalidNil:
-		return protoimpl.X.NewError("invalid nil Duration")
-	case invalidUnderflow:
-		return protoimpl.X.NewError("duration (%v) exceeds -10000 years", x)
-	case invalidOverflow:
-		return protoimpl.X.NewError("duration (%v) exceeds +10000 years", x)
-	case invalidNanosRange:
-		return protoimpl.X.NewError("duration (%v) has out-of-range nanos", x)
-	case invalidNanosSign:
-		return protoimpl.X.NewError("duration (%v) has seconds and nanos with different signs", x)
-	default:
-		return nil
-	}
-}
-
-const (
-	_ = iota
-	invalidNil
-	invalidUnderflow
-	invalidOverflow
-	invalidNanosRange
-	invalidNanosSign
-)
-
-func (x *Duration) check() uint {
-	const absDuration = 315576000000 // 10000yr * 365.25day/yr * 24hr/day * 60min/hr * 60sec/min
-	secs := x.GetSeconds()
-	nanos := x.GetNanos()
-	switch {
-	case x == nil:
-		return invalidNil
-	case secs < -absDuration:
-		return invalidUnderflow
-	case secs > +absDuration:
-		return invalidOverflow
-	case nanos <= -1e9 || nanos >= +1e9:
-		return invalidNanosRange
-	case (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0):
-		return invalidNanosSign
-	default:
-		return 0
-	}
-}
-
-func (x *Duration) Reset() {
-	*x = Duration{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_google_protobuf_duration_proto_msgTypes[0]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *Duration) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Duration) ProtoMessage() {}
-
-func (x *Duration) ProtoReflect() protoreflect.Message {
-	mi := &file_google_protobuf_duration_proto_msgTypes[0]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use Duration.ProtoReflect.Descriptor instead.
-func (*Duration) Descriptor() ([]byte, []int) {
-	return file_google_protobuf_duration_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Duration) GetSeconds() int64 {
-	if x != nil {
-		return x.Seconds
-	}
-	return 0
-}
-
-func (x *Duration) GetNanos() int32 {
-	if x != nil {
-		return x.Nanos
-	}
-	return 0
-}
-
-var File_google_protobuf_duration_proto protoreflect.FileDescriptor
-
-var file_google_protobuf_duration_proto_rawDesc = []byte{
-	0x0a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x12, 0x0f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x22, 0x3a, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
-	0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
-	0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6e, 0x6f, 0x73,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x42, 0x83, 0x01,
-	0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x0d, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
-	0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67,
-	0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x64,
-	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x47,
-	0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79,
-	0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
-	file_google_protobuf_duration_proto_rawDescOnce sync.Once
-	file_google_protobuf_duration_proto_rawDescData = file_google_protobuf_duration_proto_rawDesc
-)
-
-func file_google_protobuf_duration_proto_rawDescGZIP() []byte {
-	file_google_protobuf_duration_proto_rawDescOnce.Do(func() {
-		file_google_protobuf_duration_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_protobuf_duration_proto_rawDescData)
-	})
-	return file_google_protobuf_duration_proto_rawDescData
-}
-
-var file_google_protobuf_duration_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_google_protobuf_duration_proto_goTypes = []any{
-	(*Duration)(nil), // 0: google.protobuf.Duration
-}
-var file_google_protobuf_duration_proto_depIdxs = []int32{
-	0, // [0:0] is the sub-list for method output_type
-	0, // [0:0] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_google_protobuf_duration_proto_init() }
-func file_google_protobuf_duration_proto_init() {
-	if File_google_protobuf_duration_proto != nil {
-		return
-	}
-	if !protoimpl.UnsafeEnabled {
-		file_google_protobuf_duration_proto_msgTypes[0].Exporter = func(v any, i int) any {
-			switch v := v.(*Duration); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_google_protobuf_duration_proto_rawDesc,
-			NumEnums:      0,
-			NumMessages:   1,
-			NumExtensions: 0,
-			NumServices:   0,
-		},
-		GoTypes:           file_google_protobuf_duration_proto_goTypes,
-		DependencyIndexes: file_google_protobuf_duration_proto_depIdxs,
-		MessageInfos:      file_google_protobuf_duration_proto_msgTypes,
-	}.Build()
-	File_google_protobuf_duration_proto = out.File
-	file_google_protobuf_duration_proto_rawDesc = nil
-	file_google_protobuf_duration_proto_goTypes = nil
-	file_google_protobuf_duration_proto_depIdxs = nil
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 7bd9e08ed0..28173a5711 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,7 +1,3 @@
-# github.com/BurntSushi/toml v1.3.2
-## explicit; go 1.16
-github.com/BurntSushi/toml
-github.com/BurntSushi/toml/internal
 # github.com/Masterminds/squirrel v1.5.4
 ## explicit; go 1.14
 github.com/Masterminds/squirrel
@@ -151,6 +147,11 @@ github.com/bradfitz/iter
 ## explicit; go 1.21
 github.com/brianvoe/gofakeit/v6
 github.com/brianvoe/gofakeit/v6/data
+# github.com/brianvoe/gofakeit/v7 v7.2.1
+## explicit; go 1.22
+github.com/brianvoe/gofakeit/v7
+github.com/brianvoe/gofakeit/v7/data
+github.com/brianvoe/gofakeit/v7/source
 # github.com/btcsuite/btcd v0.22.1
 ## explicit; go 1.17
 github.com/btcsuite/btcd/btcec
@@ -219,7 +220,7 @@ github.com/edsrzf/mmap-go
 ## explicit; go 1.14
 github.com/elastic/gosigar
 github.com/elastic/gosigar/sys/windows
-# github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.19
+# github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.21
 ## explicit; go 1.21
 github.com/ethereum/go-ethereum
 github.com/ethereum/go-ethereum/accounts
@@ -284,10 +285,6 @@ github.com/ethereum/go-ethereum/rlp/internal/rlpstruct
 github.com/ethereum/go-ethereum/rpc
 github.com/ethereum/go-ethereum/signer/core/apitypes
 github.com/ethereum/go-ethereum/trie
-# github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
-## explicit
-github.com/fjl/memsize
-github.com/fjl/memsize/memsizeui
 # github.com/flynn/noise v1.1.0
 ## explicit; go 1.16
 github.com/flynn/noise
@@ -356,10 +353,6 @@ github.com/golang/groupcache/singleflight
 # github.com/golang/protobuf v1.5.3
 ## explicit; go 1.9
 github.com/golang/protobuf/proto
-github.com/golang/protobuf/ptypes
-github.com/golang/protobuf/ptypes/any
-github.com/golang/protobuf/ptypes/duration
-github.com/golang/protobuf/ptypes/timestamp
 # github.com/golang/snappy v0.0.4
 ## explicit
 github.com/golang/snappy
@@ -713,9 +706,6 @@ github.com/mutecomm/go-sqlcipher/v4
 # github.com/nfnt/resize v0.0.0-00010101000000-000000000000 => github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088
 ## explicit
 github.com/nfnt/resize
-# github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
-## explicit
-github.com/okzk/sdnotify
 # github.com/olekukonko/tablewriter v0.0.5
 ## explicit; go 1.12
 github.com/olekukonko/tablewriter
@@ -952,16 +942,13 @@ github.com/shirou/gopsutil/internal/common
 # github.com/shopspring/decimal v1.2.0
 ## explicit; go 1.13
 github.com/shopspring/decimal
-# github.com/siphiuel/lc-proxy-wrapper v0.0.0-20230516150924-246507cee8c7
-## explicit; go 1.18
-github.com/siphiuel/lc-proxy-wrapper
 # github.com/spaolacci/murmur3 v1.1.0
 ## explicit
 github.com/spaolacci/murmur3
 # github.com/status-im/doubleratchet v3.0.0+incompatible
 ## explicit
 github.com/status-im/doubleratchet
-# github.com/status-im/extkeys v1.1.0
+# github.com/status-im/extkeys v1.2.0
 ## explicit; go 1.21
 github.com/status-im/extkeys
 # github.com/status-im/markdown v0.0.0-20240404192634-b7e33c6ac3d4
@@ -972,7 +959,6 @@ github.com/status-im/markdown/parser
 # github.com/status-im/migrate/v4 v4.6.2-status.3
 ## explicit; go 1.12
 github.com/status-im/migrate/v4
-github.com/status-im/migrate/v4/database/postgres
 github.com/status-im/migrate/v4/database/sqlcipher
 github.com/status-im/migrate/v4/internal/url
 github.com/status-im/migrate/v4/source/go_bindata
@@ -1117,7 +1103,7 @@ github.com/waku-org/go-zerokit-rln-x86_64/libs/x86_64-pc-windows-gnu
 github.com/waku-org/go-zerokit-rln-x86_64/libs/x86_64-unknown-linux-gnu
 github.com/waku-org/go-zerokit-rln-x86_64/libs/x86_64-unknown-linux-musl
 github.com/waku-org/go-zerokit-rln-x86_64/rln
-# github.com/waku-org/waku-go-bindings v0.0.0-20250528131356-4af668737057
+# github.com/waku-org/waku-go-bindings v0.0.0-20250714110306-6feba5b0df4d
 ## explicit; go 1.21
 github.com/waku-org/waku-go-bindings/utils
 github.com/waku-org/waku-go-bindings/waku
@@ -1231,7 +1217,7 @@ go.uber.org/zap/internal/exit
 go.uber.org/zap/internal/pool
 go.uber.org/zap/internal/stacktrace
 go.uber.org/zap/zapcore
-# golang.org/x/crypto v0.26.0
+# golang.org/x/crypto v0.33.0
 ## explicit; go 1.20
 golang.org/x/crypto/blake2b
 golang.org/x/crypto/blake2s
@@ -1248,15 +1234,14 @@ golang.org/x/crypto/ripemd160
 golang.org/x/crypto/salsa20/salsa
 golang.org/x/crypto/scrypt
 golang.org/x/crypto/sha3
-golang.org/x/crypto/ssh/terminal
 # golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
 ## explicit; go 1.20
 golang.org/x/exp/constraints
 golang.org/x/exp/maps
 golang.org/x/exp/rand
 golang.org/x/exp/slices
-# golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
-## explicit; go 1.12
+# golang.org/x/image v0.24.0
+## explicit; go 1.18
 golang.org/x/image/bmp
 golang.org/x/image/draw
 golang.org/x/image/font
@@ -1270,13 +1255,13 @@ golang.org/x/image/vector
 golang.org/x/image/vp8
 golang.org/x/image/vp8l
 golang.org/x/image/webp
-# golang.org/x/mod v0.20.0
-## explicit; go 1.18
+# golang.org/x/mod v0.23.0
+## explicit; go 1.22.0
 golang.org/x/mod/internal/lazyregexp
 golang.org/x/mod/modfile
 golang.org/x/mod/module
 golang.org/x/mod/semver
-# golang.org/x/net v0.28.0
+# golang.org/x/net v0.35.0
 ## explicit; go 1.18
 golang.org/x/net/bpf
 golang.org/x/net/dns/dnsmessage
@@ -1294,21 +1279,17 @@ golang.org/x/net/ipv6
 golang.org/x/net/proxy
 golang.org/x/net/publicsuffix
 golang.org/x/net/route
-# golang.org/x/sync v0.8.0
+# golang.org/x/sync v0.11.0
 ## explicit; go 1.18
 golang.org/x/sync/errgroup
 golang.org/x/sync/singleflight
-# golang.org/x/sys v0.24.0
+# golang.org/x/sys v0.30.0
 ## explicit; go 1.18
 golang.org/x/sys/cpu
 golang.org/x/sys/execabs
-golang.org/x/sys/plan9
 golang.org/x/sys/unix
 golang.org/x/sys/windows
-# golang.org/x/term v0.23.0
-## explicit; go 1.18
-golang.org/x/term
-# golang.org/x/text v0.17.0
+# golang.org/x/text v0.22.0
 ## explicit; go 1.18
 golang.org/x/text/cases
 golang.org/x/text/encoding
@@ -1335,12 +1316,14 @@ golang.org/x/text/unicode/norm
 # golang.org/x/time v0.5.0
 ## explicit; go 1.18
 golang.org/x/time/rate
-# golang.org/x/tools v0.24.0
-## explicit; go 1.19
+# golang.org/x/tools v0.30.0
+## explicit; go 1.22.0
 golang.org/x/tools/cmd/goimports
 golang.org/x/tools/cover
 golang.org/x/tools/go/analysis
 golang.org/x/tools/go/analysis/analysistest
+golang.org/x/tools/go/analysis/checker
+golang.org/x/tools/go/analysis/internal
 golang.org/x/tools/go/analysis/internal/analysisflags
 golang.org/x/tools/go/analysis/internal/checker
 golang.org/x/tools/go/analysis/passes/inspect
@@ -1351,9 +1334,11 @@ golang.org/x/tools/go/ast/inspector
 golang.org/x/tools/go/gcexportdata
 golang.org/x/tools/go/packages
 golang.org/x/tools/go/types/objectpath
+golang.org/x/tools/go/types/typeutil
 golang.org/x/tools/imports
 golang.org/x/tools/internal/aliases
 golang.org/x/tools/internal/analysisinternal
+golang.org/x/tools/internal/astutil/edge
 golang.org/x/tools/internal/diff
 golang.org/x/tools/internal/diff/lcs
 golang.org/x/tools/internal/event
@@ -1366,12 +1351,12 @@ golang.org/x/tools/internal/gocommand
 golang.org/x/tools/internal/gopathwalk
 golang.org/x/tools/internal/goroot
 golang.org/x/tools/internal/imports
+golang.org/x/tools/internal/modindex
 golang.org/x/tools/internal/packagesinternal
 golang.org/x/tools/internal/pkgbits
-golang.org/x/tools/internal/robustio
 golang.org/x/tools/internal/stdlib
 golang.org/x/tools/internal/testenv
-golang.org/x/tools/internal/tokeninternal
+golang.org/x/tools/internal/typeparams
 golang.org/x/tools/internal/typesinternal
 golang.org/x/tools/internal/versions
 golang.org/x/tools/txtar
@@ -1417,8 +1402,6 @@ google.golang.org/protobuf/runtime/protoimpl
 google.golang.org/protobuf/types/descriptorpb
 google.golang.org/protobuf/types/dynamicpb
 google.golang.org/protobuf/types/gofeaturespb
-google.golang.org/protobuf/types/known/anypb
-google.golang.org/protobuf/types/known/durationpb
 google.golang.org/protobuf/types/known/timestamppb
 google.golang.org/protobuf/types/pluginpb
 # gopkg.in/go-playground/assert.v1 v1.2.1
diff --git a/waku/types/mailserver_test.go b/waku/types/mailserver_test.go
deleted file mode 100644
index 869150ef1c..0000000000
--- a/waku/types/mailserver_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package types_test
-
-import (
-	"encoding/json"
-	"testing"
-
-	"github.com/stretchr/testify/require"
-
-	"github.com/status-im/status-go/params"
-	"github.com/status-im/status-go/waku/types"
-)
-
-func TestMailserver_UnmarshalJSON(t *testing.T) {
-	fleets := params.GetSupportedFleets()
-
-	for _, fleet := range fleets {
-		for _, mailserver := range fleet.StoreNodes {
-			jsonData, err := json.Marshal(mailserver)
-			require.NoError(t, err)
-
-			var unmarshalled types.Mailserver
-			err = json.Unmarshal(jsonData, &unmarshalled)
-			require.NoError(t, err)
-
-			require.Equal(t, mailserver, unmarshalled)
-		}
-	}
-}
diff --git a/wakuv2/common/stats.go b/wakuv2/common/stats.go
deleted file mode 100644
index 751b4223bd..0000000000
--- a/wakuv2/common/stats.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package common
-
-import (
-	"sync"
-	"time"
-
-	"github.com/ethereum/go-ethereum/rlp"
-	"github.com/status-im/status-go/common"
-
-	wakutypes "github.com/status-im/status-go/waku/types"
-)
-
-type Measure struct {
-	Timestamp int64
-	Size      uint64
-}
-
-type StatsTracker struct {
-	Uploads   []Measure
-	Downloads []Measure
-
-	statsMutex sync.Mutex
-}
-
-const measurementPeriod = 15 * time.Second
-
-func measure(input interface{}) (*Measure, error) {
-	b, err := rlp.EncodeToBytes(input)
-	if err != nil {
-		return nil, err
-	}
-	return &Measure{
-		Timestamp: time.Now().UnixNano(),
-		Size:      uint64(len(b)),
-	}, nil
-
-}
-
-func (s *StatsTracker) AddUpload(input interface{}) {
-	go func(input interface{}) {
-		defer common.LogOnPanic()
-		m, err := measure(input)
-		if err != nil {
-			return
-		}
-
-		s.statsMutex.Lock()
-		defer s.statsMutex.Unlock()
-		s.Uploads = append(s.Uploads, *m)
-	}(input)
-}
-
-func (s *StatsTracker) AddDownload(input interface{}) {
-	go func(input interface{}) {
-		defer common.LogOnPanic()
-		m, err := measure(input)
-		if err != nil {
-			return
-		}
-
-		s.statsMutex.Lock()
-		defer s.statsMutex.Unlock()
-		s.Downloads = append(s.Downloads, *m)
-	}(input)
-}
-
-func (s *StatsTracker) AddUploadBytes(size uint64) {
-	go func(size uint64) {
-		defer common.LogOnPanic()
-		m := Measure{
-			Timestamp: time.Now().UnixNano(),
-			Size:      size,
-		}
-
-		s.statsMutex.Lock()
-		defer s.statsMutex.Unlock()
-		s.Uploads = append(s.Uploads, m)
-	}(size)
-}
-
-func (s *StatsTracker) AddDownloadBytes(size uint64) {
-	go func(size uint64) {
-		defer common.LogOnPanic()
-		m := Measure{
-			Timestamp: time.Now().UnixNano(),
-			Size:      size,
-		}
-
-		s.statsMutex.Lock()
-		defer s.statsMutex.Unlock()
-		s.Downloads = append(s.Downloads, m)
-	}(size)
-}
-
-func calculateAverage(measures []Measure, minTime int64) (validMeasures []Measure, rate uint64) {
-	for _, m := range measures {
-		if m.Timestamp > minTime {
-			// Only use recent measures
-			validMeasures = append(validMeasures, m)
-			rate += m.Size
-		}
-	}
-
-	rate /= (uint64(measurementPeriod) / uint64(1*time.Second))
-	return
-}
-
-func (s *StatsTracker) GetRatePerSecond() (uploadRate uint64, downloadRate uint64) {
-	s.statsMutex.Lock()
-	defer s.statsMutex.Unlock()
-	minTime := time.Now().Add(-measurementPeriod).UnixNano()
-	s.Uploads, uploadRate = calculateAverage(s.Uploads, minTime)
-	s.Downloads, downloadRate = calculateAverage(s.Downloads, minTime)
-	return
-}
-
-func (s *StatsTracker) GetStats() wakutypes.StatsSummary {
-	uploadRate, downloadRate := s.GetRatePerSecond()
-	summary := wakutypes.StatsSummary{
-		UploadRate:   uploadRate,
-		DownloadRate: downloadRate,
-	}
-	return summary
-}
diff --git a/wakuv2/persistence/queries.go b/wakuv2/persistence/queries.go
deleted file mode 100644
index e25ba6be04..0000000000
--- a/wakuv2/persistence/queries.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package persistence
-
-import (
-	"database/sql"
-	"fmt"
-)
-
-// Queries are the sqlite queries for a given table.
-type Queries struct {
-	deleteQuery  string
-	existsQuery  string
-	getQuery     string
-	putQuery     string
-	queryQuery   string
-	prefixQuery  string
-	limitQuery   string
-	offsetQuery  string
-	getSizeQuery string
-}
-
-// NewQueries creates a new set of queries for the passed table
-func NewQueries(tbl string, db *sql.DB) (*Queries, error) {
-	err := CreateTable(db, tbl)
-	if err != nil {
-		return nil, err
-	}
-	return &Queries{
-		deleteQuery:  fmt.Sprintf("DELETE FROM %s WHERE key = $1", tbl),
-		existsQuery:  fmt.Sprintf("SELECT exists(SELECT 1 FROM %s WHERE key=$1)", tbl),
-		getQuery:     fmt.Sprintf("SELECT data FROM %s WHERE key = $1", tbl),
-		putQuery:     fmt.Sprintf("INSERT INTO %s (key, data) VALUES ($1, $2)", tbl),
-		queryQuery:   fmt.Sprintf("SELECT key, data FROM %s", tbl),
-		prefixQuery:  ` WHERE key LIKE '%s%%' ORDER BY key`,
-		limitQuery:   ` LIMIT %d`,
-		offsetQuery:  ` OFFSET %d`,
-		getSizeQuery: fmt.Sprintf("SELECT length(data) FROM %s WHERE key = $1", tbl),
-	}, nil
-}
-
-// Delete returns the query for deleting a row.
-func (q Queries) Delete() string {
-	return q.deleteQuery
-}
-
-// Exists returns the query for determining if a row exists.
-func (q Queries) Exists() string {
-	return q.existsQuery
-}
-
-// Get returns the query for getting a row.
-func (q Queries) Get() string {
-	return q.getQuery
-}
-
-// Put returns the query for putting a row.
-func (q Queries) Put() string {
-	return q.putQuery
-}
-
-// Query returns the query for getting multiple rows.
-func (q Queries) Query() string {
-	return q.queryQuery
-}
-
-// Prefix returns the query fragment for getting a rows with a key prefix.
-func (q Queries) Prefix() string {
-	return q.prefixQuery
-}
-
-// Limit returns the query fragment for limiting results.
-func (q Queries) Limit() string {
-	return q.limitQuery
-}
-
-// Offset returns the query fragment for returning rows from a given offset.
-func (q Queries) Offset() string {
-	return q.offsetQuery
-}
-
-// GetSize returns the query for determining the size of a value.
-func (q Queries) GetSize() string {
-	return q.getSizeQuery
-}
-
-// CreateTable creates the table that will persist the peers
-func CreateTable(db *sql.DB, tableName string) error {
-	sqlStmt := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (key TEXT NOT NULL PRIMARY KEY ON CONFLICT REPLACE, data BYTEA);", tableName)
-	_, err := db.Exec(sqlStmt)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func Clean(db *sql.DB, tableName string) error {
-	// This is fully controlled by us
-	sqlStmt := fmt.Sprintf("DELETE FROM %s;", tableName) // nolint: gosec
-	_, err := db.Exec(sqlStmt)
-	if err != nil {
-		return err
-	}
-	return nil
-}
diff --git a/wakuv2/telemetry.go b/wakuv2/telemetry.go
deleted file mode 100644
index 5749bb2a81..0000000000
--- a/wakuv2/telemetry.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package wakuv2
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"time"
-
-	"github.com/google/uuid"
-	"github.com/libp2p/go-libp2p/core/metrics"
-	"github.com/libp2p/go-libp2p/core/protocol"
-	"go.uber.org/zap"
-
-	gocommon "github.com/status-im/status-go/common"
-
-	"github.com/waku-org/go-waku/waku/v2/protocol/filter"
-	"github.com/waku-org/go-waku/waku/v2/protocol/legacy_store"
-	"github.com/waku-org/go-waku/waku/v2/protocol/lightpush"
-	"github.com/waku-org/go-waku/waku/v2/protocol/relay"
-)
-
-type BandwidthTelemetryClient struct {
-	serverURL  string
-	httpClient *http.Client
-	hostID     string
-	logger     *zap.Logger
-}
-
-func NewBandwidthTelemetryClient(logger *zap.Logger, serverURL string) *BandwidthTelemetryClient {
-	return &BandwidthTelemetryClient{
-		serverURL:  serverURL,
-		httpClient: &http.Client{Timeout: time.Minute},
-		hostID:     uuid.NewString(),
-		logger:     logger.Named("bandwidth-telemetry"),
-	}
-}
-
-func getStatsPerProtocol(protocolID protocol.ID, stats map[protocol.ID]metrics.Stats) map[string]interface{} {
-	return map[string]interface{}{
-		"rateIn":   stats[protocolID].RateIn,
-		"rateOut":  stats[protocolID].RateOut,
-		"totalIn":  stats[protocolID].TotalIn,
-		"totalOut": stats[protocolID].TotalOut,
-	}
-}
-
-func (c *BandwidthTelemetryClient) getTelemetryRequestBody(stats map[protocol.ID]metrics.Stats) map[string]interface{} {
-	return map[string]interface{}{
-		"hostID":           c.hostID,
-		"relay":            getStatsPerProtocol(relay.WakuRelayID_v200, stats),
-		"store":            getStatsPerProtocol(legacy_store.StoreID_v20beta4, stats),
-		"filter-push":      getStatsPerProtocol(filter.FilterPushID_v20beta1, stats),
-		"filter-subscribe": getStatsPerProtocol(filter.FilterSubscribeID_v20beta1, stats),
-		"lightpush":        getStatsPerProtocol(lightpush.LightPushID_v20beta1, stats),
-	}
-}
-
-func (c *BandwidthTelemetryClient) PushProtocolStats(stats map[protocol.ID]metrics.Stats) {
-	defer gocommon.LogOnPanic()
-	url := fmt.Sprintf("%s/protocol-stats", c.serverURL)
-	body, _ := json.Marshal(c.getTelemetryRequestBody(stats))
-	_, err := c.httpClient.Post(url, "application/json", bytes.NewBuffer(body))
-	if err != nil {
-		c.logger.Error("Error sending message to telemetry server", zap.Error(err))
-	}
-}

From 51eeab269e833bc66c1390b7c6001618151ab465 Mon Sep 17 00:00:00 2001
From: pablo 
Date: Thu, 21 Aug 2025 10:21:30 +0300
Subject: [PATCH 3/5] fix: merge conflicts

---
 protocol/communities_key_distributor.go | 3 +--
 protocol/messenger.go                   | 3 +--
 protocol/messenger_communities.go       | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/protocol/communities_key_distributor.go b/protocol/communities_key_distributor.go
index 457484ec9f..e81130e2cf 100644
--- a/protocol/communities_key_distributor.go
+++ b/protocol/communities_key_distributor.go
@@ -9,7 +9,6 @@ import (
 	"github.com/status-im/status-go/protocol/common"
 	"github.com/status-im/status-go/protocol/communities"
 	"github.com/status-im/status-go/protocol/protobuf"
-	"github.com/status-im/status-go/wakuv2"
 )
 
 type CommunitiesKeyDistributorImpl struct {
@@ -95,7 +94,7 @@ func (ckd *CommunitiesKeyDistributorImpl) sendKeyExchangeMessage(community *comm
 		Recipients:            pubkeys,
 		MessageType:           protobuf.ApplicationMetadataMessage_CHAT_MESSAGE,
 		HashRatchetGroupID:    hashRatchetGroupID,
-		PubsubTopic:           community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()),
+		PubsubTopic:           community.PubsubTopic(messagingtypes.GlobalCommunityControlPubsubTopic()),
 	}
 	_, err := ckd.messaging.SendCommunityMessage(context.Background(), &rawMessage)
 
diff --git a/protocol/messenger.go b/protocol/messenger.go
index fccfa26e80..65284dbb1f 100644
--- a/protocol/messenger.go
+++ b/protocol/messenger.go
@@ -34,7 +34,6 @@ import (
 	"github.com/status-im/status-go/messaging"
 	messagingtypes "github.com/status-im/status-go/messaging/types"
 	multiaccountscommon "github.com/status-im/status-go/multiaccounts/common"
-	"github.com/status-im/status-go/wakuv2"
 
 	"github.com/status-im/status-go/multiaccounts"
 	"github.com/status-im/status-go/multiaccounts/accounts"
@@ -1817,7 +1816,7 @@ func (m *Messenger) dispatchMessage(ctx context.Context, rawMessage messagingtyp
 		// Use a single content-topic for all community chats.
 		// Reasoning: https://github.com/status-im/status-go/pull/5864
 		rawMessage.ContentTopic = community.UniversalChatID()
-		rawMessage.PubsubTopic = community.PubsubTopic(wakuv2.GlobalCommunityContentPubsubTopic())
+		rawMessage.PubsubTopic = community.PubsubTopic(messagingtypes.GlobalCommunityContentPubsubTopic())
 
 		canPost, err := m.communitiesManager.CanPost(&m.identity.PublicKey, chat.CommunityID, chat.CommunityChatID(), rawMessage.MessageType)
 		if err != nil {
diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go
index 08810b7ae6..baec04abff 100644
--- a/protocol/messenger_communities.go
+++ b/protocol/messenger_communities.go
@@ -203,7 +203,7 @@ func (m *Messenger) publishCommunityPrivilegedMemberSyncMessage(msg *communities
 		Sender:              community.PrivateKey(),
 		SkipEncryptionLayer: true,
 		MessageType:         protobuf.ApplicationMetadataMessage_COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE,
-		PubsubTopic:         community.PubsubTopic(wakuv2.GlobalCommunityControlPubsubTopic()),
+		PubsubTopic:         community.PubsubTopic(messagingtypes.GlobalCommunityControlPubsubTopic()),
 	}
 
 	for _, receivers := range msg.Receivers {

From 0aaa81aa8d555bdce7c0de3a9b256bcee27cabf9 Mon Sep 17 00:00:00 2001
From: pablo 
Date: Thu, 21 Aug 2025 10:35:10 +0300
Subject: [PATCH 4/5] fix: remove print

---
 protocol/messenger_communities.go | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go
index baec04abff..f4549c74e9 100644
--- a/protocol/messenger_communities.go
+++ b/protocol/messenger_communities.go
@@ -951,10 +951,6 @@ func (m *Messenger) initCommunityChats(community *communities.Community) ([]*Cha
 		return nil, err
 	}
 
-	for _, filter := range filters {
-		fmt.Printf(">>> filter: %s %s\n", filter.ChatID, filter.PubsubTopic)
-	}
-
 	if community.IsControlNode() {
 		// Init the community filter so we can receive messages on the community
 

From 18dc2c643699fb5e3e36cf80182604fd21e1f814 Mon Sep 17 00:00:00 2001
From: pablo 
Date: Thu, 21 Aug 2025 19:04:52 +0300
Subject: [PATCH 5/5] fix: add shard to tests

---
 tests-functional/docker-compose.waku.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tests-functional/docker-compose.waku.yml b/tests-functional/docker-compose.waku.yml
index 0fcaa9f1e2..e62b5771eb 100644
--- a/tests-functional/docker-compose.waku.yml
+++ b/tests-functional/docker-compose.waku.yml
@@ -22,6 +22,8 @@ services:
       "--rest-admin",
       "--shard=32",
       "--shard=64",
+      "--shard=128",
+      "--shard=256",
       "--staticnode=/dns4/store/tcp/60002/p2p/16Uiu2HAmCDqxtfF1DwBqs7UJ4TgSnjoh6j1RtE1hhQxLLao84jLi",
       "--storenode=/dns4/store/tcp/60002/p2p/16Uiu2HAmCDqxtfF1DwBqs7UJ4TgSnjoh6j1RtE1hhQxLLao84jLi",
       "--tcp-port=60001"
@@ -53,6 +55,8 @@ services:
       "--rest-admin",
       "--shard=32",
       "--shard=64",
+      "--shard=128",
+      "--shard=256",
       "--staticnode=/dns4/boot-1/tcp/60001/p2p/16Uiu2HAm3vFYHkGRURyJ6F7bwDyzMLtPEuCg4DU89T7km2u8Fjyb",
       "--store=true",
       "--tcp-port=60002"