flwr-nightly 1.9.0.dev20240426__tar.gz → 1.9.0.dev20240429__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flwr-nightly might be problematic. Click here for more details.

Files changed (217) hide show
  1. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/PKG-INFO +1 -1
  2. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/pyproject.toml +1 -1
  3. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/__init__.py +1 -1
  4. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/app.py +17 -93
  5. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/supernode/__init__.py +2 -0
  6. flwr_nightly-1.9.0.dev20240429/src/py/flwr/client/supernode/app.py +281 -0
  7. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +15 -0
  8. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/app.py +105 -1
  9. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +3 -1
  10. flwr_nightly-1.9.0.dev20240429/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +169 -0
  11. flwr_nightly-1.9.0.dev20240426/src/py/flwr/client/supernode/app.py +0 -119
  12. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/LICENSE +0 -0
  13. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/README.md +0 -0
  14. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/__init__.py +0 -0
  15. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/__init__.py +0 -0
  16. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/app.py +0 -0
  17. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/config_utils.py +0 -0
  18. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/example.py +0 -0
  19. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/__init__.py +0 -0
  20. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/new.py +0 -0
  21. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/__init__.py +0 -0
  22. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
  23. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
  24. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
  25. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  26. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  27. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  28. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  29. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
  30. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  31. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  32. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  33. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
  34. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  35. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  36. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
  37. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -0
  38. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -0
  39. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
  40. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/run/__init__.py +0 -0
  41. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/run/run.py +0 -0
  42. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/utils.py +0 -0
  43. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/client.py +0 -0
  44. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/client_app.py +0 -0
  45. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  46. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_client/__init__.py +0 -0
  47. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_client/connection.py +0 -0
  48. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  49. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -0
  50. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_rere_client/connection.py +0 -0
  51. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/heartbeat.py +0 -0
  52. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/message_handler/__init__.py +0 -0
  53. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/message_handler/message_handler.py +0 -0
  54. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/message_handler/task_handler.py +0 -0
  55. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/__init__.py +0 -0
  56. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
  57. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/comms_mods.py +0 -0
  58. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/localdp_mod.py +0 -0
  59. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  60. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  61. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  62. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/utils.py +0 -0
  63. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/node_state.py +0 -0
  64. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/node_state_tests.py +0 -0
  65. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/numpy_client.py +0 -0
  66. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/rest_client/__init__.py +0 -0
  67. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/rest_client/connection.py +0 -0
  68. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/typing.py +0 -0
  69. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/__init__.py +0 -0
  70. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/address.py +0 -0
  71. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/constant.py +0 -0
  72. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/context.py +0 -0
  73. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/date.py +0 -0
  74. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/differential_privacy.py +0 -0
  75. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/differential_privacy_constants.py +0 -0
  76. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/dp.py +0 -0
  77. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/exit_handlers.py +0 -0
  78. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/grpc.py +0 -0
  79. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/logger.py +0 -0
  80. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/message.py +0 -0
  81. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/object_ref.py +0 -0
  82. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/parameter.py +0 -0
  83. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/pyproject.py +0 -0
  84. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/__init__.py +0 -0
  85. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/configsrecord.py +0 -0
  86. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/conversion_utils.py +0 -0
  87. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/metricsrecord.py +0 -0
  88. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/parametersrecord.py +0 -0
  89. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/recordset.py +0 -0
  90. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/typeddict.py +0 -0
  91. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/recordset_compat.py +0 -0
  92. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/retry_invoker.py +0 -0
  93. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
  94. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  95. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  96. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  97. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
  98. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  99. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  100. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/serde.py +0 -0
  101. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/telemetry.py +0 -0
  102. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/typing.py +0 -0
  103. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/version.py +0 -0
  104. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/__init__.py +0 -0
  105. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2.py +0 -0
  106. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2.pyi +0 -0
  107. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
  108. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
  109. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2.py +0 -0
  110. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2.pyi +0 -0
  111. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
  112. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  113. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2.py +0 -0
  114. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
  115. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
  116. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
  117. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2.py +0 -0
  118. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2.pyi +0 -0
  119. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
  120. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  121. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2.py +0 -0
  122. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
  123. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
  124. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
  125. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2.py +0 -0
  126. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2.pyi +0 -0
  127. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
  128. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
  129. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2.py +0 -0
  130. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2.pyi +0 -0
  131. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
  132. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  133. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/py.typed +0 -0
  134. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/__init__.py +0 -0
  135. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/client_manager.py +0 -0
  136. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/client_proxy.py +0 -0
  137. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/__init__.py +0 -0
  138. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/app.py +0 -0
  139. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/app_utils.py +0 -0
  140. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/driver_client_proxy.py +0 -0
  141. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/legacy_context.py +0 -0
  142. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/criterion.py +0 -0
  143. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/driver/__init__.py +0 -0
  144. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/driver/driver.py +0 -0
  145. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/driver/grpc_driver.py +0 -0
  146. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/history.py +0 -0
  147. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/run_serverapp.py +0 -0
  148. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/server.py +0 -0
  149. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/server_app.py +0 -0
  150. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/server_config.py +0 -0
  151. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/__init__.py +0 -0
  152. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/aggregate.py +0 -0
  153. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/bulyan.py +0 -0
  154. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  155. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  156. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  157. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  158. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  159. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
  160. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedadam.py +0 -0
  161. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedavg.py +0 -0
  162. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
  163. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedavgm.py +0 -0
  164. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedmedian.py +0 -0
  165. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedopt.py +0 -0
  166. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedprox.py +0 -0
  167. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  168. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  169. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  170. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  171. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedyogi.py +0 -0
  172. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/krum.py +0 -0
  173. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/qfedavg.py +0 -0
  174. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/strategy.py +0 -0
  175. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/__init__.py +0 -0
  176. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
  177. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/driver/driver_grpc.py +0 -0
  178. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/driver/driver_servicer.py +0 -0
  179. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
  180. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  181. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  182. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  183. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  184. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  185. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
  186. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  187. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
  188. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  189. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
  190. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  191. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  192. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  193. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
  194. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -0
  195. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/__init__.py +0 -0
  196. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/in_memory_state.py +0 -0
  197. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/sqlite_state.py +0 -0
  198. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/state.py +0 -0
  199. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
  200. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/utils.py +0 -0
  201. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/typing.py +0 -0
  202. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/utils/__init__.py +0 -0
  203. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/utils/tensorboard.py +0 -0
  204. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/utils/validator.py +0 -0
  205. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/__init__.py +0 -0
  206. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/constant.py +0 -0
  207. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/default_workflows.py +0 -0
  208. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  209. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  210. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
  211. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/__init__.py +0 -0
  212. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/app.py +0 -0
  213. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
  214. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
  215. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  216. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
  217. {flwr_nightly-1.9.0.dev20240426 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/run_simulation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.9.0.dev20240426
3
+ Version: 1.9.0.dev20240429
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "flwr-nightly"
7
- version = "1.9.0.dev20240426"
7
+ version = "1.9.0.dev20240429"
8
8
  description = "Flower: A Friendly Federated Learning Framework"
9
9
  license = "Apache-2.0"
10
10
  authors = ["The Flower Authors <hello@flower.ai>"]
@@ -15,12 +15,12 @@
15
15
  """Flower client."""
16
16
 
17
17
 
18
- from .app import run_client_app as run_client_app
19
18
  from .app import start_client as start_client
20
19
  from .app import start_numpy_client as start_numpy_client
21
20
  from .client import Client as Client
22
21
  from .client_app import ClientApp as ClientApp
23
22
  from .numpy_client import NumPyClient as NumPyClient
23
+ from .supernode import run_client_app as run_client_app
24
24
  from .supernode import run_supernode as run_supernode
25
25
  from .typing import ClientFn as ClientFn
26
26
 
@@ -14,13 +14,12 @@
14
14
  # ==============================================================================
15
15
  """Flower client app."""
16
16
 
17
- import argparse
18
17
  import sys
19
18
  import time
20
19
  from logging import DEBUG, ERROR, INFO, WARN
21
- from pathlib import Path
22
20
  from typing import Callable, ContextManager, Optional, Tuple, Type, Union
23
21
 
22
+ from cryptography.hazmat.primitives.asymmetric import ec
24
23
  from grpc import RpcError
25
24
 
26
25
  from flwr.client.client import Client
@@ -36,10 +35,8 @@ from flwr.common.constant import (
36
35
  TRANSPORT_TYPES,
37
36
  ErrorCode,
38
37
  )
39
- from flwr.common.exit_handlers import register_exit_handlers
40
38
  from flwr.common.logger import log, warn_deprecated_feature
41
39
  from flwr.common.message import Error
42
- from flwr.common.object_ref import load_app, validate
43
40
  from flwr.common.retry_invoker import RetryInvoker, exponential
44
41
 
45
42
  from .grpc_client.connection import grpc_connection
@@ -47,94 +44,6 @@ from .grpc_rere_client.connection import grpc_request_response
47
44
  from .message_handler.message_handler import handle_control_message
48
45
  from .node_state import NodeState
49
46
  from .numpy_client import NumPyClient
50
- from .supernode.app import parse_args_run_client_app
51
-
52
-
53
- def run_client_app() -> None:
54
- """Run Flower client app."""
55
- log(INFO, "Long-running Flower client starting")
56
-
57
- event(EventType.RUN_CLIENT_APP_ENTER)
58
-
59
- args = _parse_args_run_client_app().parse_args()
60
-
61
- # Obtain certificates
62
- if args.insecure:
63
- if args.root_certificates is not None:
64
- sys.exit(
65
- "Conflicting options: The '--insecure' flag disables HTTPS, "
66
- "but '--root-certificates' was also specified. Please remove "
67
- "the '--root-certificates' option when running in insecure mode, "
68
- "or omit '--insecure' to use HTTPS."
69
- )
70
- log(
71
- WARN,
72
- "Option `--insecure` was set. "
73
- "Starting insecure HTTP client connected to %s.",
74
- args.server,
75
- )
76
- root_certificates = None
77
- else:
78
- # Load the certificates if provided, or load the system certificates
79
- cert_path = args.root_certificates
80
- if cert_path is None:
81
- root_certificates = None
82
- else:
83
- root_certificates = Path(cert_path).read_bytes()
84
- log(
85
- DEBUG,
86
- "Starting secure HTTPS client connected to %s "
87
- "with the following certificates: %s.",
88
- args.server,
89
- cert_path,
90
- )
91
-
92
- log(
93
- DEBUG,
94
- "Flower will load ClientApp `%s`",
95
- getattr(args, "client-app"),
96
- )
97
-
98
- client_app_dir = args.dir
99
- if client_app_dir is not None:
100
- sys.path.insert(0, client_app_dir)
101
-
102
- app_ref: str = getattr(args, "client-app")
103
- valid, error_msg = validate(app_ref)
104
- if not valid and error_msg:
105
- raise LoadClientAppError(error_msg) from None
106
-
107
- def _load() -> ClientApp:
108
- client_app = load_app(app_ref, LoadClientAppError)
109
-
110
- if not isinstance(client_app, ClientApp):
111
- raise LoadClientAppError(
112
- f"Attribute {app_ref} is not of type {ClientApp}",
113
- ) from None
114
-
115
- return client_app
116
-
117
- _start_client_internal(
118
- server_address=args.server,
119
- load_client_app_fn=_load,
120
- transport="rest" if args.rest else "grpc-rere",
121
- root_certificates=root_certificates,
122
- insecure=args.insecure,
123
- max_retries=args.max_retries,
124
- max_wait_time=args.max_wait_time,
125
- )
126
- register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
127
-
128
-
129
- def _parse_args_run_client_app() -> argparse.ArgumentParser:
130
- """Parse flower-client-app command line arguments."""
131
- parser = argparse.ArgumentParser(
132
- description="Start a Flower client app",
133
- )
134
-
135
- parse_args_run_client_app(parser=parser)
136
-
137
- return parser
138
47
 
139
48
 
140
49
  def _check_actionable_client(
@@ -165,6 +74,9 @@ def start_client(
165
74
  root_certificates: Optional[Union[bytes, str]] = None,
166
75
  insecure: Optional[bool] = None,
167
76
  transport: Optional[str] = None,
77
+ authentication_keys: Optional[
78
+ Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
79
+ ] = None,
168
80
  max_retries: Optional[int] = None,
169
81
  max_wait_time: Optional[float] = None,
170
82
  ) -> None:
@@ -249,6 +161,7 @@ def start_client(
249
161
  root_certificates=root_certificates,
250
162
  insecure=insecure,
251
163
  transport=transport,
164
+ authentication_keys=authentication_keys,
252
165
  max_retries=max_retries,
253
166
  max_wait_time=max_wait_time,
254
167
  )
@@ -269,6 +182,9 @@ def _start_client_internal(
269
182
  root_certificates: Optional[Union[bytes, str]] = None,
270
183
  insecure: Optional[bool] = None,
271
184
  transport: Optional[str] = None,
185
+ authentication_keys: Optional[
186
+ Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
187
+ ] = None,
272
188
  max_retries: Optional[int] = None,
273
189
  max_wait_time: Optional[float] = None,
274
190
  ) -> None:
@@ -393,6 +309,7 @@ def _start_client_internal(
393
309
  retry_invoker,
394
310
  grpc_max_message_length,
395
311
  root_certificates,
312
+ authentication_keys,
396
313
  ) as conn:
397
314
  # pylint: disable-next=W0612
398
315
  receive, send, create_node, delete_node, get_run = conn
@@ -606,7 +523,14 @@ def start_numpy_client(
606
523
 
607
524
  def _init_connection(transport: Optional[str], server_address: str) -> Tuple[
608
525
  Callable[
609
- [str, bool, RetryInvoker, int, Union[bytes, str, None]],
526
+ [
527
+ str,
528
+ bool,
529
+ RetryInvoker,
530
+ int,
531
+ Union[bytes, str, None],
532
+ Optional[Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]],
533
+ ],
610
534
  ContextManager[
611
535
  Tuple[
612
536
  Callable[[], Optional[Message]],
@@ -15,8 +15,10 @@
15
15
  """Flower SuperNode."""
16
16
 
17
17
 
18
+ from .app import run_client_app as run_client_app
18
19
  from .app import run_supernode as run_supernode
19
20
 
20
21
  __all__ = [
22
+ "run_client_app",
21
23
  "run_supernode",
22
24
  ]
@@ -0,0 +1,281 @@
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Flower SuperNode."""
16
+
17
+ import argparse
18
+ import sys
19
+ from logging import DEBUG, INFO, WARN
20
+ from pathlib import Path
21
+ from typing import Callable, Optional, Tuple
22
+
23
+ from cryptography.hazmat.primitives.asymmetric import ec
24
+ from cryptography.hazmat.primitives.serialization import (
25
+ load_ssh_private_key,
26
+ load_ssh_public_key,
27
+ )
28
+
29
+ from flwr.client.client_app import ClientApp, LoadClientAppError
30
+ from flwr.common import EventType, event
31
+ from flwr.common.exit_handlers import register_exit_handlers
32
+ from flwr.common.logger import log
33
+ from flwr.common.object_ref import load_app, validate
34
+ from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
35
+ ssh_types_to_elliptic_curve,
36
+ )
37
+
38
+ from ..app import _start_client_internal
39
+
40
+
41
+ def run_supernode() -> None:
42
+ """Run Flower SuperNode."""
43
+ log(INFO, "Starting Flower SuperNode")
44
+
45
+ event(EventType.RUN_SUPERNODE_ENTER)
46
+
47
+ _ = _parse_args_run_supernode().parse_args()
48
+
49
+ log(
50
+ DEBUG,
51
+ "Flower SuperNode starting...",
52
+ )
53
+
54
+ # Graceful shutdown
55
+ register_exit_handlers(
56
+ event_type=EventType.RUN_SUPERNODE_LEAVE,
57
+ )
58
+
59
+
60
+ def run_client_app() -> None:
61
+ """Run Flower client app."""
62
+ log(INFO, "Long-running Flower client starting")
63
+
64
+ event(EventType.RUN_CLIENT_APP_ENTER)
65
+
66
+ args = _parse_args_run_client_app().parse_args()
67
+
68
+ root_certificates = _get_certificates(args)
69
+ log(
70
+ DEBUG,
71
+ "Flower will load ClientApp `%s`",
72
+ getattr(args, "client-app"),
73
+ )
74
+ load_fn = _get_load_client_app_fn(args)
75
+ authentication_keys = _try_setup_client_authentication(args)
76
+
77
+ _start_client_internal(
78
+ server_address=args.server,
79
+ load_client_app_fn=load_fn,
80
+ transport="rest" if args.rest else "grpc-rere",
81
+ root_certificates=root_certificates,
82
+ insecure=args.insecure,
83
+ authentication_keys=authentication_keys,
84
+ max_retries=args.max_retries,
85
+ max_wait_time=args.max_wait_time,
86
+ )
87
+ register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
88
+
89
+
90
+ def _get_certificates(args: argparse.Namespace) -> Optional[bytes]:
91
+ """Load certificates if specified in args."""
92
+ # Obtain certificates
93
+ if args.insecure:
94
+ if args.root_certificates is not None:
95
+ sys.exit(
96
+ "Conflicting options: The '--insecure' flag disables HTTPS, "
97
+ "but '--root-certificates' was also specified. Please remove "
98
+ "the '--root-certificates' option when running in insecure mode, "
99
+ "or omit '--insecure' to use HTTPS."
100
+ )
101
+ log(
102
+ WARN,
103
+ "Option `--insecure` was set. "
104
+ "Starting insecure HTTP client connected to %s.",
105
+ args.server,
106
+ )
107
+ root_certificates = None
108
+ else:
109
+ # Load the certificates if provided, or load the system certificates
110
+ cert_path = args.root_certificates
111
+ if cert_path is None:
112
+ root_certificates = None
113
+ else:
114
+ root_certificates = Path(cert_path).read_bytes()
115
+ log(
116
+ DEBUG,
117
+ "Starting secure HTTPS client connected to %s "
118
+ "with the following certificates: %s.",
119
+ args.server,
120
+ cert_path,
121
+ )
122
+ return root_certificates
123
+
124
+
125
+ def _get_load_client_app_fn(
126
+ args: argparse.Namespace,
127
+ ) -> Callable[[], ClientApp]:
128
+ """Get the load_client_app_fn function."""
129
+ client_app_dir = args.dir
130
+ if client_app_dir is not None:
131
+ sys.path.insert(0, client_app_dir)
132
+
133
+ app_ref: str = getattr(args, "client-app")
134
+ valid, error_msg = validate(app_ref)
135
+ if not valid and error_msg:
136
+ raise LoadClientAppError(error_msg) from None
137
+
138
+ def _load() -> ClientApp:
139
+ client_app = load_app(app_ref, LoadClientAppError)
140
+
141
+ if not isinstance(client_app, ClientApp):
142
+ raise LoadClientAppError(
143
+ f"Attribute {app_ref} is not of type {ClientApp}",
144
+ ) from None
145
+
146
+ return client_app
147
+
148
+ return _load
149
+
150
+
151
+ def _parse_args_run_supernode() -> argparse.ArgumentParser:
152
+ """Parse flower-supernode command line arguments."""
153
+ parser = argparse.ArgumentParser(
154
+ description="Start a Flower SuperNode",
155
+ )
156
+
157
+ parser.add_argument(
158
+ "client-app",
159
+ nargs="?",
160
+ default="",
161
+ help="For example: `client:app` or `project.package.module:wrapper.app`. "
162
+ "This is optional and serves as the default ClientApp to be loaded when "
163
+ "the ServerApp does not specify `fab_id` and `fab_version`. "
164
+ "If not provided, defaults to an empty string.",
165
+ )
166
+ _parse_args_common(parser)
167
+ parser.add_argument(
168
+ "--flwr-dir",
169
+ default=None,
170
+ help="""The path containing installed Flower Apps.
171
+ By default, this value isequal to:
172
+
173
+ - `$FLWR_HOME/` if `$FLWR_HOME` is defined
174
+ - `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
175
+ - `$HOME/.flwr/` in all other cases
176
+ """,
177
+ )
178
+
179
+ return parser
180
+
181
+
182
+ def _parse_args_run_client_app() -> argparse.ArgumentParser:
183
+ """Parse flower-client-app command line arguments."""
184
+ parser = argparse.ArgumentParser(
185
+ description="Start a Flower client app",
186
+ )
187
+
188
+ parser.add_argument(
189
+ "client-app",
190
+ help="For example: `client:app` or `project.package.module:wrapper.app`",
191
+ )
192
+ _parse_args_common(parser=parser)
193
+
194
+ return parser
195
+
196
+
197
+ def _parse_args_common(parser: argparse.ArgumentParser) -> None:
198
+ parser.add_argument(
199
+ "--insecure",
200
+ action="store_true",
201
+ help="Run the client without HTTPS. By default, the client runs with "
202
+ "HTTPS enabled. Use this flag only if you understand the risks.",
203
+ )
204
+ parser.add_argument(
205
+ "--rest",
206
+ action="store_true",
207
+ help="Use REST as a transport layer for the client.",
208
+ )
209
+ parser.add_argument(
210
+ "--root-certificates",
211
+ metavar="ROOT_CERT",
212
+ type=str,
213
+ help="Specifies the path to the PEM-encoded root certificate file for "
214
+ "establishing secure HTTPS connections.",
215
+ )
216
+ parser.add_argument(
217
+ "--server",
218
+ default="0.0.0.0:9092",
219
+ help="Server address",
220
+ )
221
+ parser.add_argument(
222
+ "--max-retries",
223
+ type=int,
224
+ default=None,
225
+ help="The maximum number of times the client will try to connect to the"
226
+ "server before giving up in case of a connection error. By default,"
227
+ "it is set to None, meaning there is no limit to the number of tries.",
228
+ )
229
+ parser.add_argument(
230
+ "--max-wait-time",
231
+ type=float,
232
+ default=None,
233
+ help="The maximum duration before the client stops trying to"
234
+ "connect to the server in case of connection error. By default, it"
235
+ "is set to None, meaning there is no limit to the total time.",
236
+ )
237
+ parser.add_argument(
238
+ "--dir",
239
+ default="",
240
+ help="Add specified directory to the PYTHONPATH and load Flower "
241
+ "app from there."
242
+ " Default: current working directory.",
243
+ )
244
+ parser.add_argument(
245
+ "--authentication-keys",
246
+ nargs=2,
247
+ metavar=("CLIENT_PRIVATE_KEY", "CLIENT_PUBLIC_KEY"),
248
+ type=str,
249
+ help="Provide two file paths: (1) the client's private "
250
+ "key file, and (2) the client's public key file.",
251
+ )
252
+
253
+
254
+ def _try_setup_client_authentication(
255
+ args: argparse.Namespace,
256
+ ) -> Optional[Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]]:
257
+ if not args.authentication_keys:
258
+ return None
259
+
260
+ ssh_private_key = load_ssh_private_key(
261
+ Path(args.authentication_keys[0]).read_bytes(),
262
+ None,
263
+ )
264
+ ssh_public_key = load_ssh_public_key(Path(args.authentication_keys[1]).read_bytes())
265
+
266
+ try:
267
+ client_private_key, client_public_key = ssh_types_to_elliptic_curve(
268
+ ssh_private_key, ssh_public_key
269
+ )
270
+ except TypeError:
271
+ sys.exit(
272
+ "The file paths provided could not be read as a private and public "
273
+ "key pair. Client authentication requires an elliptic curve public and "
274
+ "private key pair. Please provide the file paths containing elliptic "
275
+ "curve private and public keys to '--authentication-keys'."
276
+ )
277
+
278
+ return (
279
+ client_private_key,
280
+ client_public_key,
281
+ )
@@ -117,3 +117,18 @@ def verify_hmac(key: bytes, message: bytes, hmac_value: bytes) -> bool:
117
117
  return True
118
118
  except InvalidSignature:
119
119
  return False
120
+
121
+
122
+ def ssh_types_to_elliptic_curve(
123
+ private_key: serialization.SSHPrivateKeyTypes,
124
+ public_key: serialization.SSHPublicKeyTypes,
125
+ ) -> Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]:
126
+ """Cast SSH key types to elliptic curve."""
127
+ if isinstance(private_key, ec.EllipticCurvePrivateKey) and isinstance(
128
+ public_key, ec.EllipticCurvePublicKey
129
+ ):
130
+ return (private_key, public_key)
131
+
132
+ raise TypeError(
133
+ "The provided key is not an EllipticCurvePrivateKey or EllipticCurvePublicKey"
134
+ )
@@ -16,15 +16,21 @@
16
16
 
17
17
  import argparse
18
18
  import asyncio
19
+ import csv
19
20
  import importlib.util
20
21
  import sys
21
22
  import threading
22
23
  from logging import ERROR, INFO, WARN
23
24
  from os.path import isfile
24
25
  from pathlib import Path
25
- from typing import List, Optional, Tuple
26
+ from typing import List, Optional, Sequence, Set, Tuple
26
27
 
27
28
  import grpc
29
+ from cryptography.hazmat.primitives.asymmetric import ec
30
+ from cryptography.hazmat.primitives.serialization import (
31
+ load_ssh_private_key,
32
+ load_ssh_public_key,
33
+ )
28
34
 
29
35
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
30
36
  from flwr.common.address import parse_address
@@ -36,6 +42,10 @@ from flwr.common.constant import (
36
42
  )
37
43
  from flwr.common.exit_handlers import register_exit_handlers
38
44
  from flwr.common.logger import log
45
+ from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
46
+ public_key_to_bytes,
47
+ ssh_types_to_elliptic_curve,
48
+ )
39
49
  from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
40
50
  add_FleetServicer_to_server,
41
51
  )
@@ -51,6 +61,7 @@ from .superlink.fleet.grpc_bidi.grpc_server import (
51
61
  start_grpc_server,
52
62
  )
53
63
  from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
64
+ from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
54
65
  from .superlink.fleet.vce import start_vce
55
66
  from .superlink.state import StateFactory
56
67
 
@@ -354,10 +365,28 @@ def run_superlink() -> None:
354
365
  sys.exit(f"Fleet IP address ({address_arg}) cannot be parsed.")
355
366
  host, port, is_v6 = parsed_address
356
367
  address = f"[{host}]:{port}" if is_v6 else f"{host}:{port}"
368
+
369
+ maybe_keys = _try_setup_client_authentication(args, certificates)
370
+ interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None
371
+ if maybe_keys is not None:
372
+ (
373
+ client_public_keys,
374
+ server_private_key,
375
+ server_public_key,
376
+ ) = maybe_keys
377
+ interceptors = [
378
+ AuthenticateServerInterceptor(
379
+ client_public_keys,
380
+ server_private_key,
381
+ server_public_key,
382
+ )
383
+ ]
384
+
357
385
  fleet_server = _run_fleet_api_grpc_rere(
358
386
  address=address,
359
387
  state_factory=state_factory,
360
388
  certificates=certificates,
389
+ interceptors=interceptors,
361
390
  )
362
391
  grpc_servers.append(fleet_server)
363
392
  elif args.fleet_api_type == TRANSPORT_TYPE_VCE:
@@ -390,6 +419,70 @@ def run_superlink() -> None:
390
419
  driver_server.wait_for_termination(timeout=1)
391
420
 
392
421
 
422
+ def _try_setup_client_authentication(
423
+ args: argparse.Namespace,
424
+ certificates: Optional[Tuple[bytes, bytes, bytes]],
425
+ ) -> Optional[Tuple[Set[bytes], ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]]:
426
+ if not args.require_client_authentication:
427
+ return None
428
+
429
+ if certificates is None:
430
+ sys.exit(
431
+ "Client authentication only works over secure connections. "
432
+ "Please provide certificate paths using '--certificates' when "
433
+ "enabling '--require-client-authentication'."
434
+ )
435
+
436
+ client_keys_file_path = Path(args.require_client_authentication[0])
437
+ if not client_keys_file_path.exists():
438
+ sys.exit(
439
+ "The provided path to the client public keys CSV file does not exist: "
440
+ f"{client_keys_file_path}. "
441
+ "Please provide the CSV file path containing known client public keys "
442
+ "to '--require-client-authentication'."
443
+ )
444
+
445
+ client_public_keys: Set[bytes] = set()
446
+ ssh_private_key = load_ssh_private_key(
447
+ Path(args.require_client_authentication[1]).read_bytes(),
448
+ None,
449
+ )
450
+ ssh_public_key = load_ssh_public_key(
451
+ Path(args.require_client_authentication[2]).read_bytes()
452
+ )
453
+
454
+ try:
455
+ server_private_key, server_public_key = ssh_types_to_elliptic_curve(
456
+ ssh_private_key, ssh_public_key
457
+ )
458
+ except TypeError:
459
+ sys.exit(
460
+ "The file paths provided could not be read as a private and public "
461
+ "key pair. Client authentication requires an elliptic curve public and "
462
+ "private key pair. Please provide the file paths containing elliptic "
463
+ "curve private and public keys to '--require-client-authentication'."
464
+ )
465
+
466
+ with open(client_keys_file_path, newline="", encoding="utf-8") as csvfile:
467
+ reader = csv.reader(csvfile)
468
+ for row in reader:
469
+ for element in row:
470
+ public_key = load_ssh_public_key(element.encode())
471
+ if isinstance(public_key, ec.EllipticCurvePublicKey):
472
+ client_public_keys.add(public_key_to_bytes(public_key))
473
+ else:
474
+ sys.exit(
475
+ "Error: Unable to parse the public keys in the .csv "
476
+ "file. Please ensure that the .csv file contains valid "
477
+ "SSH public keys and try again."
478
+ )
479
+ return (
480
+ client_public_keys,
481
+ server_private_key,
482
+ server_public_key,
483
+ )
484
+
485
+
393
486
  def _try_obtain_certificates(
394
487
  args: argparse.Namespace,
395
488
  ) -> Optional[Tuple[bytes, bytes, bytes]]:
@@ -417,6 +510,7 @@ def _run_fleet_api_grpc_rere(
417
510
  address: str,
418
511
  state_factory: StateFactory,
419
512
  certificates: Optional[Tuple[bytes, bytes, bytes]],
513
+ interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
420
514
  ) -> grpc.Server:
421
515
  """Run Fleet API (gRPC, request-response)."""
422
516
  # Create Fleet API gRPC server
@@ -429,6 +523,7 @@ def _run_fleet_api_grpc_rere(
429
523
  server_address=address,
430
524
  max_message_length=GRPC_MAX_MESSAGE_LENGTH,
431
525
  certificates=certificates,
526
+ interceptors=interceptors,
432
527
  )
433
528
 
434
529
  log(INFO, "Flower ECE: Starting Fleet API (gRPC-rere) on %s", address)
@@ -606,6 +701,15 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
606
701
  "Flower will just create a state in memory.",
607
702
  default=DATABASE,
608
703
  )
704
+ parser.add_argument(
705
+ "--require-client-authentication",
706
+ nargs=3,
707
+ metavar=("CLIENT_KEYS", "SERVER_PRIVATE_KEY", "SERVER_PUBLIC_KEY"),
708
+ type=str,
709
+ help="Provide three file paths: (1) a .csv file containing a list of "
710
+ "known client public keys for authentication, (2) the server's private "
711
+ "key file, and (3) the server's public key file.",
712
+ )
609
713
 
610
714
 
611
715
  def _add_args_driver_api(parser: argparse.ArgumentParser) -> None: