flwr-nightly 1.9.0.dev20240422__tar.gz → 1.9.0.dev20240424__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 (215) hide show
  1. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/PKG-INFO +1 -1
  2. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/pyproject.toml +1 -1
  3. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/new.py +1 -0
  4. flwr_nightly-1.9.0.dev20240424/src/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +94 -0
  5. flwr_nightly-1.9.0.dev20240424/src/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +17 -0
  6. flwr_nightly-1.9.0.dev20240424/src/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +24 -0
  7. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/grpc_client/connection.py +6 -1
  8. flwr_nightly-1.9.0.dev20240424/src/py/flwr/client/grpc_rere_client/client_interceptor.py +150 -0
  9. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/grpc_rere_client/connection.py +17 -2
  10. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/rest_client/connection.py +5 -1
  11. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/grpc.py +5 -1
  12. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +20 -1
  13. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/driver/driver_servicer.py +1 -1
  14. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/state/in_memory_state.py +37 -1
  15. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/state/sqlite_state.py +71 -4
  16. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/state/state.py +26 -0
  17. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/LICENSE +0 -0
  18. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/README.md +0 -0
  19. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/__init__.py +0 -0
  20. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/__init__.py +0 -0
  21. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/app.py +0 -0
  22. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/config_utils.py +0 -0
  23. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/example.py +0 -0
  24. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/__init__.py +0 -0
  25. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/__init__.py +0 -0
  26. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
  27. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
  28. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
  29. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  30. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  31. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  32. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  33. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  34. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  35. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  36. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  37. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  38. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
  39. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -0
  40. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
  41. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/run/__init__.py +0 -0
  42. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/run/run.py +0 -0
  43. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/cli/utils.py +0 -0
  44. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/__init__.py +0 -0
  45. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/app.py +0 -0
  46. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/client.py +0 -0
  47. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/client_app.py +0 -0
  48. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  49. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/grpc_client/__init__.py +0 -0
  50. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  51. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/heartbeat.py +0 -0
  52. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/message_handler/__init__.py +0 -0
  53. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/message_handler/message_handler.py +0 -0
  54. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/message_handler/task_handler.py +0 -0
  55. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/__init__.py +0 -0
  56. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
  57. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/comms_mods.py +0 -0
  58. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/localdp_mod.py +0 -0
  59. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  60. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  61. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  62. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/mod/utils.py +0 -0
  63. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/node_state.py +0 -0
  64. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/node_state_tests.py +0 -0
  65. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/numpy_client.py +0 -0
  66. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/rest_client/__init__.py +0 -0
  67. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/supernode/__init__.py +0 -0
  68. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/supernode/app.py +0 -0
  69. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/client/typing.py +0 -0
  70. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/__init__.py +0 -0
  71. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/address.py +0 -0
  72. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/constant.py +0 -0
  73. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/context.py +0 -0
  74. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/date.py +0 -0
  75. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/differential_privacy.py +0 -0
  76. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/differential_privacy_constants.py +0 -0
  77. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/dp.py +0 -0
  78. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/exit_handlers.py +0 -0
  79. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/logger.py +0 -0
  80. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/message.py +0 -0
  81. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/object_ref.py +0 -0
  82. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/parameter.py +0 -0
  83. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/pyproject.py +0 -0
  84. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/__init__.py +0 -0
  85. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/configsrecord.py +0 -0
  86. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/conversion_utils.py +0 -0
  87. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/metricsrecord.py +0 -0
  88. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/parametersrecord.py +0 -0
  89. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/recordset.py +0 -0
  90. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/record/typeddict.py +0 -0
  91. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/recordset_compat.py +0 -0
  92. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/retry_invoker.py +0 -0
  93. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
  94. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  95. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  96. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  97. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
  98. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  99. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  100. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/serde.py +0 -0
  101. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/telemetry.py +0 -0
  102. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/typing.py +0 -0
  103. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/common/version.py +0 -0
  104. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/__init__.py +0 -0
  105. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/driver_pb2.py +0 -0
  106. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/driver_pb2.pyi +0 -0
  107. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
  108. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
  109. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/error_pb2.py +0 -0
  110. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/error_pb2.pyi +0 -0
  111. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
  112. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  113. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/fleet_pb2.py +0 -0
  114. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
  115. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
  116. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
  117. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/node_pb2.py +0 -0
  118. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/node_pb2.pyi +0 -0
  119. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
  120. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  121. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/recordset_pb2.py +0 -0
  122. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
  123. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
  124. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
  125. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/task_pb2.py +0 -0
  126. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/task_pb2.pyi +0 -0
  127. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
  128. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
  129. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/transport_pb2.py +0 -0
  130. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/transport_pb2.pyi +0 -0
  131. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
  132. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  133. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/py.typed +0 -0
  134. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/__init__.py +0 -0
  135. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/app.py +0 -0
  136. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/client_manager.py +0 -0
  137. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/client_proxy.py +0 -0
  138. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/compat/__init__.py +0 -0
  139. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/compat/app.py +0 -0
  140. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/compat/app_utils.py +0 -0
  141. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/compat/driver_client_proxy.py +0 -0
  142. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/compat/legacy_context.py +0 -0
  143. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/criterion.py +0 -0
  144. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/driver/__init__.py +0 -0
  145. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/driver/driver.py +0 -0
  146. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/driver/grpc_driver.py +0 -0
  147. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/history.py +0 -0
  148. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/run_serverapp.py +0 -0
  149. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/server.py +0 -0
  150. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/server_app.py +0 -0
  151. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/server_config.py +0 -0
  152. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/__init__.py +0 -0
  153. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/aggregate.py +0 -0
  154. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/bulyan.py +0 -0
  155. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  156. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  157. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  158. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  159. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  160. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
  161. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedadam.py +0 -0
  162. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedavg.py +0 -0
  163. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
  164. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedavgm.py +0 -0
  165. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedmedian.py +0 -0
  166. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedopt.py +0 -0
  167. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedprox.py +0 -0
  168. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  169. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  170. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  171. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  172. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/fedyogi.py +0 -0
  173. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/krum.py +0 -0
  174. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/qfedavg.py +0 -0
  175. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/strategy/strategy.py +0 -0
  176. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/__init__.py +0 -0
  177. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
  178. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/driver/driver_grpc.py +0 -0
  179. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
  180. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  181. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  182. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  183. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  184. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  185. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  186. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
  187. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  188. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
  189. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  190. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
  191. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  192. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  193. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  194. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
  195. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -0
  196. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/state/__init__.py +0 -0
  197. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
  198. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/superlink/state/utils.py +0 -0
  199. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/typing.py +0 -0
  200. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/utils/__init__.py +0 -0
  201. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/utils/tensorboard.py +0 -0
  202. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/utils/validator.py +0 -0
  203. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/workflow/__init__.py +0 -0
  204. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/workflow/constant.py +0 -0
  205. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/workflow/default_workflows.py +0 -0
  206. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  207. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  208. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
  209. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/simulation/__init__.py +0 -0
  210. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/simulation/app.py +0 -0
  211. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
  212. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
  213. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  214. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
  215. {flwr_nightly-1.9.0.dev20240422 → flwr_nightly-1.9.0.dev20240424}/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.dev20240422
3
+ Version: 1.9.0.dev20240424
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.dev20240422"
7
+ version = "1.9.0.dev20240424"
8
8
  description = "Flower: A Friendly Federated Learning Framework"
9
9
  license = "Apache-2.0"
10
10
  authors = ["The Flower Authors <hello@flower.ai>"]
@@ -36,6 +36,7 @@ class MlFramework(str, Enum):
36
36
  NUMPY = "NumPy"
37
37
  PYTORCH = "PyTorch"
38
38
  TENSORFLOW = "TensorFlow"
39
+ SKLEARN = "sklearn"
39
40
 
40
41
 
41
42
  class TemplateNotFound(Exception):
@@ -0,0 +1,94 @@
1
+ """$project_name: A Flower / Scikit-Learn app."""
2
+
3
+ import warnings
4
+
5
+ import numpy as np
6
+ from flwr.client import NumPyClient, ClientApp
7
+ from flwr_datasets import FederatedDataset
8
+ from sklearn.linear_model import LogisticRegression
9
+ from sklearn.metrics import log_loss
10
+
11
+
12
+ def get_model_parameters(model):
13
+ if model.fit_intercept:
14
+ params = [
15
+ model.coef_,
16
+ model.intercept_,
17
+ ]
18
+ else:
19
+ params = [model.coef_]
20
+ return params
21
+
22
+
23
+ def set_model_params(model, params):
24
+ model.coef_ = params[0]
25
+ if model.fit_intercept:
26
+ model.intercept_ = params[1]
27
+ return model
28
+
29
+
30
+ def set_initial_params(model):
31
+ n_classes = 10 # MNIST has 10 classes
32
+ n_features = 784 # Number of features in dataset
33
+ model.classes_ = np.array([i for i in range(10)])
34
+
35
+ model.coef_ = np.zeros((n_classes, n_features))
36
+ if model.fit_intercept:
37
+ model.intercept_ = np.zeros((n_classes,))
38
+
39
+
40
+ class FlowerClient(NumPyClient):
41
+ def __init__(self, model, X_train, X_test, y_train, y_test):
42
+ self.model = model
43
+ self.X_train = X_train
44
+ self.X_test = X_test
45
+ self.y_train = y_train
46
+ self.y_test = y_test
47
+
48
+ def get_parameters(self, config):
49
+ return get_model_parameters(self.model)
50
+
51
+ def fit(self, parameters, config):
52
+ set_model_params(self.model, parameters)
53
+
54
+ # Ignore convergence failure due to low local epochs
55
+ with warnings.catch_warnings():
56
+ warnings.simplefilter("ignore")
57
+ self.model.fit(self.X_train, self.y_train)
58
+
59
+ return get_model_parameters(self.model), len(self.X_train), {}
60
+
61
+ def evaluate(self, parameters, config):
62
+ set_model_params(self.model, parameters)
63
+
64
+ loss = log_loss(self.y_test, self.model.predict_proba(self.X_test))
65
+ accuracy = self.model.score(self.X_test, self.y_test)
66
+
67
+ return loss, len(self.X_test), {"accuracy": accuracy}
68
+
69
+ fds = FederatedDataset(dataset="mnist", partitioners={"train": 2})
70
+
71
+ def client_fn(cid: str):
72
+ dataset = fds.load_partition(int(cid), "train").with_format("numpy")
73
+
74
+ X, y = dataset["image"].reshape((len(dataset), -1)), dataset["label"]
75
+
76
+ # Split the on edge data: 80% train, 20% test
77
+ X_train, X_test = X[: int(0.8 * len(X))], X[int(0.8 * len(X)) :]
78
+ y_train, y_test = y[: int(0.8 * len(y))], y[int(0.8 * len(y)) :]
79
+
80
+ # Create LogisticRegression Model
81
+ model = LogisticRegression(
82
+ penalty="l2",
83
+ max_iter=1, # local epoch
84
+ warm_start=True, # prevent refreshing weights when fitting
85
+ )
86
+
87
+ # Setting initial parameters, akin to model.compile for keras models
88
+ set_initial_params(model)
89
+
90
+ return FlowerClient(model, X_train, X_test, y_train, y_test).to_client()
91
+
92
+
93
+ # Flower ClientApp
94
+ app = ClientApp(client_fn=client_fn)
@@ -0,0 +1,17 @@
1
+ """$project_name: A Flower / Scikit-Learn app."""
2
+
3
+ from flwr.server import ServerApp, ServerConfig
4
+ from flwr.server.strategy import FedAvg
5
+
6
+
7
+ strategy = FedAvg(
8
+ fraction_fit=1.0,
9
+ fraction_evaluate=1.0,
10
+ min_available_clients=2,
11
+ )
12
+
13
+ # Create ServerApp
14
+ app = ServerApp(
15
+ config=ServerConfig(num_rounds=3),
16
+ strategy=strategy,
17
+ )
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "$project_name"
7
+ version = "1.0.0"
8
+ description = ""
9
+ authors = [
10
+ { name = "The Flower Authors", email = "hello@flower.ai" },
11
+ ]
12
+ license = {text = "Apache License (2.0)"}
13
+ dependencies = [
14
+ "flwr[simulation]>=1.8.0,<2.0",
15
+ "flwr-datasets[vision]>=0.0.2,<1.0.0",
16
+ "scikit-learn>=1.1.1",
17
+ ]
18
+
19
+ [tool.hatch.build.targets.wheel]
20
+ packages = ["."]
21
+
22
+ [flower.components]
23
+ serverapp = "$project_name.server:app"
24
+ clientapp = "$project_name.client:app"
@@ -22,6 +22,8 @@ from pathlib import Path
22
22
  from queue import Queue
23
23
  from typing import Callable, Iterator, Optional, Tuple, Union, cast
24
24
 
25
+ from cryptography.hazmat.primitives.asymmetric import ec
26
+
25
27
  from flwr.common import (
26
28
  DEFAULT_TTL,
27
29
  GRPC_MAX_MESSAGE_LENGTH,
@@ -56,12 +58,15 @@ def on_channel_state_change(channel_connectivity: str) -> None:
56
58
 
57
59
 
58
60
  @contextmanager
59
- def grpc_connection( # pylint: disable=R0915
61
+ def grpc_connection( # pylint: disable=R0913, R0915
60
62
  server_address: str,
61
63
  insecure: bool,
62
64
  retry_invoker: RetryInvoker, # pylint: disable=unused-argument
63
65
  max_message_length: int = GRPC_MAX_MESSAGE_LENGTH,
64
66
  root_certificates: Optional[Union[bytes, str]] = None,
67
+ authentication_keys: Optional[ # pylint: disable=unused-argument
68
+ Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
69
+ ] = None,
65
70
  ) -> Iterator[
66
71
  Tuple[
67
72
  Callable[[], Optional[Message]],
@@ -0,0 +1,150 @@
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 client interceptor."""
16
+
17
+
18
+ import base64
19
+ import collections
20
+ from typing import Any, Callable, Optional, Sequence, Tuple, Union
21
+
22
+ import grpc
23
+ from cryptography.hazmat.primitives.asymmetric import ec
24
+
25
+ from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
26
+ bytes_to_public_key,
27
+ compute_hmac,
28
+ generate_shared_key,
29
+ public_key_to_bytes,
30
+ )
31
+ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
32
+ CreateNodeRequest,
33
+ DeleteNodeRequest,
34
+ GetRunRequest,
35
+ PullTaskInsRequest,
36
+ PushTaskResRequest,
37
+ )
38
+
39
+ _PUBLIC_KEY_HEADER = "public-key"
40
+ _AUTH_TOKEN_HEADER = "auth-token"
41
+
42
+ Request = Union[
43
+ CreateNodeRequest,
44
+ DeleteNodeRequest,
45
+ PullTaskInsRequest,
46
+ PushTaskResRequest,
47
+ GetRunRequest,
48
+ ]
49
+
50
+
51
+ def _get_value_from_tuples(
52
+ key_string: str, tuples: Sequence[Tuple[str, Union[str, bytes]]]
53
+ ) -> bytes:
54
+ value = next((value for key, value in tuples if key == key_string), "")
55
+ if isinstance(value, str):
56
+ return value.encode()
57
+
58
+ return value
59
+
60
+
61
+ class _ClientCallDetails(
62
+ collections.namedtuple(
63
+ "_ClientCallDetails", ("method", "timeout", "metadata", "credentials")
64
+ ),
65
+ grpc.ClientCallDetails, # type: ignore
66
+ ):
67
+ """Details for each client call.
68
+
69
+ The class will be passed on as the first argument in continuation function.
70
+ In our case, `AuthenticateClientInterceptor` adds new metadata to the construct.
71
+ """
72
+
73
+
74
+ class AuthenticateClientInterceptor(grpc.UnaryUnaryClientInterceptor): # type: ignore
75
+ """Client interceptor for client authentication."""
76
+
77
+ def __init__(
78
+ self,
79
+ private_key: ec.EllipticCurvePrivateKey,
80
+ public_key: ec.EllipticCurvePublicKey,
81
+ ):
82
+ self.private_key = private_key
83
+ self.public_key = public_key
84
+ self.shared_secret: Optional[bytes] = None
85
+ self.server_public_key: Optional[ec.EllipticCurvePublicKey] = None
86
+ self.encoded_public_key = base64.urlsafe_b64encode(
87
+ public_key_to_bytes(self.public_key)
88
+ )
89
+
90
+ def intercept_unary_unary(
91
+ self,
92
+ continuation: Callable[[Any, Any], Any],
93
+ client_call_details: grpc.ClientCallDetails,
94
+ request: Request,
95
+ ) -> grpc.Call:
96
+ """Flower client interceptor.
97
+
98
+ Intercept unary call from client and add necessary authentication header in the
99
+ RPC metadata.
100
+ """
101
+ metadata = []
102
+ postprocess = False
103
+ if client_call_details.metadata is not None:
104
+ metadata = list(client_call_details.metadata)
105
+
106
+ # Always add the public key header
107
+ metadata.append(
108
+ (
109
+ _PUBLIC_KEY_HEADER,
110
+ self.encoded_public_key,
111
+ )
112
+ )
113
+
114
+ if isinstance(request, CreateNodeRequest):
115
+ postprocess = True
116
+ elif isinstance(
117
+ request,
118
+ (DeleteNodeRequest, PullTaskInsRequest, PushTaskResRequest, GetRunRequest),
119
+ ):
120
+ if self.shared_secret is None:
121
+ raise RuntimeError("Failure to compute hmac")
122
+
123
+ metadata.append(
124
+ (
125
+ _AUTH_TOKEN_HEADER,
126
+ base64.urlsafe_b64encode(
127
+ compute_hmac(
128
+ self.shared_secret, request.SerializeToString(True)
129
+ )
130
+ ),
131
+ )
132
+ )
133
+
134
+ client_call_details = _ClientCallDetails(
135
+ client_call_details.method,
136
+ client_call_details.timeout,
137
+ metadata,
138
+ client_call_details.credentials,
139
+ )
140
+
141
+ response = continuation(client_call_details, request)
142
+ if postprocess:
143
+ server_public_key_bytes = base64.urlsafe_b64decode(
144
+ _get_value_from_tuples(_PUBLIC_KEY_HEADER, response.initial_metadata())
145
+ )
146
+ self.server_public_key = bytes_to_public_key(server_public_key_bytes)
147
+ self.shared_secret = generate_shared_key(
148
+ self.private_key, self.server_public_key
149
+ )
150
+ return response
@@ -21,7 +21,10 @@ from contextlib import contextmanager
21
21
  from copy import copy
22
22
  from logging import DEBUG, ERROR
23
23
  from pathlib import Path
24
- from typing import Callable, Iterator, Optional, Tuple, Union, cast
24
+ from typing import Callable, Iterator, Optional, Sequence, Tuple, Union, cast
25
+
26
+ import grpc
27
+ from cryptography.hazmat.primitives.asymmetric import ec
25
28
 
26
29
  from flwr.client.heartbeat import start_ping_loop
27
30
  from flwr.client.message_handler.message_handler import validate_out_message
@@ -52,6 +55,8 @@ from flwr.proto.fleet_pb2_grpc import FleetStub # pylint: disable=E0611
52
55
  from flwr.proto.node_pb2 import Node # pylint: disable=E0611
53
56
  from flwr.proto.task_pb2 import TaskIns # pylint: disable=E0611
54
57
 
58
+ from .client_interceptor import AuthenticateClientInterceptor
59
+
55
60
 
56
61
  def on_channel_state_change(channel_connectivity: str) -> None:
57
62
  """Log channel connectivity."""
@@ -59,12 +64,15 @@ def on_channel_state_change(channel_connectivity: str) -> None:
59
64
 
60
65
 
61
66
  @contextmanager
62
- def grpc_request_response( # pylint: disable=R0914, R0915
67
+ def grpc_request_response( # pylint: disable=R0913, R0914, R0915
63
68
  server_address: str,
64
69
  insecure: bool,
65
70
  retry_invoker: RetryInvoker,
66
71
  max_message_length: int = GRPC_MAX_MESSAGE_LENGTH, # pylint: disable=W0613
67
72
  root_certificates: Optional[Union[bytes, str]] = None,
73
+ authentication_keys: Optional[
74
+ Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
75
+ ] = None,
68
76
  ) -> Iterator[
69
77
  Tuple[
70
78
  Callable[[], Optional[Message]],
@@ -109,11 +117,18 @@ def grpc_request_response( # pylint: disable=R0914, R0915
109
117
  if isinstance(root_certificates, str):
110
118
  root_certificates = Path(root_certificates).read_bytes()
111
119
 
120
+ interceptors: Optional[Sequence[grpc.UnaryUnaryClientInterceptor]] = None
121
+ if authentication_keys is not None:
122
+ interceptors = AuthenticateClientInterceptor(
123
+ authentication_keys[0], authentication_keys[1]
124
+ )
125
+
112
126
  channel = create_channel(
113
127
  server_address=server_address,
114
128
  insecure=insecure,
115
129
  root_certificates=root_certificates,
116
130
  max_message_length=max_message_length,
131
+ interceptors=interceptors,
117
132
  )
118
133
  channel.subscribe(on_channel_state_change)
119
134
 
@@ -23,6 +23,7 @@ from copy import copy
23
23
  from logging import ERROR, INFO, WARN
24
24
  from typing import Callable, Iterator, Optional, Tuple, Type, TypeVar, Union
25
25
 
26
+ from cryptography.hazmat.primitives.asymmetric import ec
26
27
  from google.protobuf.message import Message as GrpcMessage
27
28
 
28
29
  from flwr.client.heartbeat import start_ping_loop
@@ -74,7 +75,7 @@ T = TypeVar("T", bound=GrpcMessage)
74
75
 
75
76
 
76
77
  @contextmanager
77
- def http_request_response( # pylint: disable=R0914, R0915
78
+ def http_request_response( # pylint: disable=,R0913, R0914, R0915
78
79
  server_address: str,
79
80
  insecure: bool, # pylint: disable=unused-argument
80
81
  retry_invoker: RetryInvoker,
@@ -82,6 +83,9 @@ def http_request_response( # pylint: disable=R0914, R0915
82
83
  root_certificates: Optional[
83
84
  Union[bytes, str]
84
85
  ] = None, # pylint: disable=unused-argument
86
+ authentication_keys: Optional[ # pylint: disable=unused-argument
87
+ Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
88
+ ] = None,
85
89
  ) -> Iterator[
86
90
  Tuple[
87
91
  Callable[[], Optional[Message]],
@@ -16,7 +16,7 @@
16
16
 
17
17
 
18
18
  from logging import DEBUG
19
- from typing import Optional
19
+ from typing import Optional, Sequence
20
20
 
21
21
  import grpc
22
22
 
@@ -30,6 +30,7 @@ def create_channel(
30
30
  insecure: bool,
31
31
  root_certificates: Optional[bytes] = None,
32
32
  max_message_length: int = GRPC_MAX_MESSAGE_LENGTH,
33
+ interceptors: Optional[Sequence[grpc.UnaryUnaryClientInterceptor]] = None,
33
34
  ) -> grpc.Channel:
34
35
  """Create a gRPC channel, either secure or insecure."""
35
36
  # Check for conflicting parameters
@@ -57,4 +58,7 @@ def create_channel(
57
58
  )
58
59
  log(DEBUG, "Opened secure gRPC connection using certificates")
59
60
 
61
+ if interceptors is not None:
62
+ channel = grpc.intercept_channel(channel, interceptors)
63
+
60
64
  return channel
@@ -18,8 +18,9 @@
18
18
  import base64
19
19
  from typing import Tuple, cast
20
20
 
21
+ from cryptography.exceptions import InvalidSignature
21
22
  from cryptography.fernet import Fernet
22
- from cryptography.hazmat.primitives import hashes, serialization
23
+ from cryptography.hazmat.primitives import hashes, hmac, serialization
23
24
  from cryptography.hazmat.primitives.asymmetric import ec
24
25
  from cryptography.hazmat.primitives.kdf.hkdf import HKDF
25
26
 
@@ -98,3 +99,21 @@ def decrypt(key: bytes, ciphertext: bytes) -> bytes:
98
99
  # The input key must be url safe
99
100
  fernet = Fernet(key)
100
101
  return fernet.decrypt(ciphertext)
102
+
103
+
104
+ def compute_hmac(key: bytes, message: bytes) -> bytes:
105
+ """Compute hmac of a message using key as hash."""
106
+ computed_hmac = hmac.HMAC(key, hashes.SHA256())
107
+ computed_hmac.update(message)
108
+ return computed_hmac.finalize()
109
+
110
+
111
+ def verify_hmac(key: bytes, message: bytes, hmac_value: bytes) -> bool:
112
+ """Verify hmac of a message using key as hash."""
113
+ computed_hmac = hmac.HMAC(key, hashes.SHA256())
114
+ computed_hmac.update(message)
115
+ try:
116
+ computed_hmac.verify(hmac_value)
117
+ return True
118
+ except InvalidSignature:
119
+ return False
@@ -64,7 +64,7 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
64
64
  """Create run ID."""
65
65
  log(INFO, "DriverServicer.CreateRun")
66
66
  state: State = self.state_factory.state()
67
- run_id = state.create_run("None/None", "None")
67
+ run_id = state.create_run(request.fab_id, request.fab_version)
68
68
  return CreateRunResponse(run_id=run_id)
69
69
 
70
70
  def PushTaskIns(
@@ -30,7 +30,7 @@ from flwr.server.utils import validate_task_ins_or_res
30
30
  from .utils import make_node_unavailable_taskres
31
31
 
32
32
 
33
- class InMemoryState(State):
33
+ class InMemoryState(State): # pylint: disable=R0902
34
34
  """In-memory State implementation."""
35
35
 
36
36
  def __init__(self) -> None:
@@ -40,6 +40,9 @@ class InMemoryState(State):
40
40
  self.run_ids: Dict[int, Tuple[str, str]] = {}
41
41
  self.task_ins_store: Dict[UUID, TaskIns] = {}
42
42
  self.task_res_store: Dict[UUID, TaskRes] = {}
43
+ self.client_public_keys: Set[bytes] = set()
44
+ self.server_public_key: Optional[bytes] = None
45
+ self.server_private_key: Optional[bytes] = None
43
46
  self.lock = threading.Lock()
44
47
 
45
48
  def store_task_ins(self, task_ins: TaskIns) -> Optional[UUID]:
@@ -251,6 +254,39 @@ class InMemoryState(State):
251
254
  log(ERROR, "Unexpected run creation failure.")
252
255
  return 0
253
256
 
257
+ def store_server_public_private_key(
258
+ self, public_key: bytes, private_key: bytes
259
+ ) -> None:
260
+ """Store `server_public_key` and `server_private_key` in state."""
261
+ with self.lock:
262
+ if self.server_private_key is None and self.server_public_key is None:
263
+ self.server_private_key = private_key
264
+ self.server_public_key = public_key
265
+ else:
266
+ raise RuntimeError("Server public and private key already set")
267
+
268
+ def get_server_private_key(self) -> Optional[bytes]:
269
+ """Retrieve `server_private_key` in urlsafe bytes."""
270
+ return self.server_private_key
271
+
272
+ def get_server_public_key(self) -> Optional[bytes]:
273
+ """Retrieve `server_public_key` in urlsafe bytes."""
274
+ return self.server_public_key
275
+
276
+ def store_client_public_keys(self, public_keys: Set[bytes]) -> None:
277
+ """Store a set of `client_public_keys` in state."""
278
+ with self.lock:
279
+ self.client_public_keys = public_keys
280
+
281
+ def store_client_public_key(self, public_key: bytes) -> None:
282
+ """Store a `client_public_key` in state."""
283
+ with self.lock:
284
+ self.client_public_keys.add(public_key)
285
+
286
+ def get_client_public_keys(self) -> Set[bytes]:
287
+ """Retrieve all currently stored `client_public_keys` as a set."""
288
+ return self.client_public_keys
289
+
254
290
  def get_run(self, run_id: int) -> Tuple[int, str, str]:
255
291
  """Retrieve information about the run with the specified `run_id`."""
256
292
  with self.lock:
@@ -20,7 +20,7 @@ import re
20
20
  import sqlite3
21
21
  import time
22
22
  from logging import DEBUG, ERROR
23
- from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast
23
+ from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Union, cast
24
24
  from uuid import UUID, uuid4
25
25
 
26
26
  from flwr.common import log, now
@@ -40,6 +40,19 @@ CREATE TABLE IF NOT EXISTS node(
40
40
  );
41
41
  """
42
42
 
43
+ SQL_CREATE_TABLE_CREDENTIAL = """
44
+ CREATE TABLE IF NOT EXISTS credential(
45
+ public_key BLOB PRIMARY KEY,
46
+ private_key BLOB
47
+ );
48
+ """
49
+
50
+ SQL_CREATE_TABLE_PUBLIC_KEY = """
51
+ CREATE TABLE IF NOT EXISTS public_key(
52
+ public_key BLOB UNIQUE
53
+ );
54
+ """
55
+
43
56
  SQL_CREATE_INDEX_ONLINE_UNTIL = """
44
57
  CREATE INDEX IF NOT EXISTS idx_online_until ON node (online_until);
45
58
  """
@@ -72,7 +85,6 @@ CREATE TABLE IF NOT EXISTS task_ins(
72
85
  );
73
86
  """
74
87
 
75
-
76
88
  SQL_CREATE_TABLE_TASK_RES = """
77
89
  CREATE TABLE IF NOT EXISTS task_res(
78
90
  task_id TEXT UNIQUE,
@@ -96,7 +108,7 @@ CREATE TABLE IF NOT EXISTS task_res(
96
108
  DictOrTuple = Union[Tuple[Any, ...], Dict[str, Any]]
97
109
 
98
110
 
99
- class SqliteState(State):
111
+ class SqliteState(State): # pylint: disable=R0904
100
112
  """SQLite-based state implementation."""
101
113
 
102
114
  def __init__(
@@ -134,6 +146,8 @@ class SqliteState(State):
134
146
  cur.execute(SQL_CREATE_TABLE_TASK_INS)
135
147
  cur.execute(SQL_CREATE_TABLE_TASK_RES)
136
148
  cur.execute(SQL_CREATE_TABLE_NODE)
149
+ cur.execute(SQL_CREATE_TABLE_CREDENTIAL)
150
+ cur.execute(SQL_CREATE_TABLE_PUBLIC_KEY)
137
151
  cur.execute(SQL_CREATE_INDEX_ONLINE_UNTIL)
138
152
  res = cur.execute("SELECT name FROM sqlite_schema;")
139
153
 
@@ -142,7 +156,7 @@ class SqliteState(State):
142
156
  def query(
143
157
  self,
144
158
  query: str,
145
- data: Optional[Union[List[DictOrTuple], DictOrTuple]] = None,
159
+ data: Optional[Union[Sequence[DictOrTuple], DictOrTuple]] = None,
146
160
  ) -> List[Dict[str, Any]]:
147
161
  """Execute a SQL query."""
148
162
  if self.conn is None:
@@ -575,6 +589,59 @@ class SqliteState(State):
575
589
  log(ERROR, "Unexpected run creation failure.")
576
590
  return 0
577
591
 
592
+ def store_server_public_private_key(
593
+ self, public_key: bytes, private_key: bytes
594
+ ) -> None:
595
+ """Store `server_public_key` and `server_private_key` in state."""
596
+ query = "SELECT COUNT(*) FROM credential"
597
+ count = self.query(query)[0]["COUNT(*)"]
598
+ if count < 1:
599
+ query = (
600
+ "INSERT OR REPLACE INTO credential (public_key, private_key) "
601
+ "VALUES (:public_key, :private_key)"
602
+ )
603
+ self.query(query, {"public_key": public_key, "private_key": private_key})
604
+ else:
605
+ raise RuntimeError("Server public and private key already set")
606
+
607
+ def get_server_private_key(self) -> Optional[bytes]:
608
+ """Retrieve `server_private_key` in urlsafe bytes."""
609
+ query = "SELECT private_key FROM credential"
610
+ rows = self.query(query)
611
+ try:
612
+ private_key: Optional[bytes] = rows[0]["private_key"]
613
+ except IndexError:
614
+ private_key = None
615
+ return private_key
616
+
617
+ def get_server_public_key(self) -> Optional[bytes]:
618
+ """Retrieve `server_public_key` in urlsafe bytes."""
619
+ query = "SELECT public_key FROM credential"
620
+ rows = self.query(query)
621
+ try:
622
+ public_key: Optional[bytes] = rows[0]["public_key"]
623
+ except IndexError:
624
+ public_key = None
625
+ return public_key
626
+
627
+ def store_client_public_keys(self, public_keys: Set[bytes]) -> None:
628
+ """Store a set of `client_public_keys` in state."""
629
+ query = "INSERT INTO public_key (public_key) VALUES (?)"
630
+ data = [(key,) for key in public_keys]
631
+ self.query(query, data)
632
+
633
+ def store_client_public_key(self, public_key: bytes) -> None:
634
+ """Store a `client_public_key` in state."""
635
+ query = "INSERT INTO public_key (public_key) VALUES (:public_key)"
636
+ self.query(query, {"public_key": public_key})
637
+
638
+ def get_client_public_keys(self) -> Set[bytes]:
639
+ """Retrieve all currently stored `client_public_keys` as a set."""
640
+ query = "SELECT public_key FROM public_key"
641
+ rows = self.query(query)
642
+ result: Set[bytes] = {row["public_key"] for row in rows}
643
+ return result
644
+
578
645
  def get_run(self, run_id: int) -> Tuple[int, str, str]:
579
646
  """Retrieve information about the run with the specified `run_id`."""
580
647
  query = "SELECT * FROM run WHERE run_id = ?;"