@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

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.
Files changed (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,538 +1,467 @@
1
- # CryptoKit Public-Key Cryptography
1
+ # CryptoKit: Signatures, Key Agreement, HPKE and Post-Quantum
2
2
 
3
- > **Scope:** ECDSA signing, ECDH key agreement, HPKE (iOS 17+), ML-KEM/ML-DSA and hybrid migration patterns (iOS 26+), key serialization, and Secure Enclave integration boundaries on Apple platforms.
4
- >
5
- > **Cross-references:** Secure Enclave key lifecycle → `secure-enclave.md`. Symmetric encryption after key agreement → `cryptokit-symmetric.md`. Keychain storage of CryptoKit keys → `credential-storage-patterns.md`. RSA → ECC migration → section "Stop Using RSA for New Apple Development" below.
3
+ Topics: digital signatures (ECDSA, EdDSA), Diffie-Hellman over elliptic curves,
4
+ hybrid public-key encryption from iOS 17,
5
+ ML-KEM and ML-DSA with hybrid migration (iOS 26+), key serialization, and where the
6
+ Secure Enclave fits.
6
7
 
7
- CryptoKit's asymmetric cryptography API covers ECDSA signing, ECDH key agreement, HPKE (iOS 17+), and post-quantum ML-KEM/ML-DSA (iOS 26+). The framework enforces correct usage through its type system - signing keys cannot perform key agreement, shared secrets must pass through HKDF before use, and Secure Enclave access is limited to P256 for classical curves. This reference covers every asymmetric primitive from iOS 13 through iOS 26 with verified Swift implementations, common AI-generator mistakes, and the quantum migration path.
8
+ CryptoKit's types carry several rules for you: a signing key cannot perform key
9
+ agreement, a shared secret cannot be used as a key until it is run through a KDF,
10
+ and the only classical curve the Secure Enclave accepts is P-256.
8
11
 
9
- CryptoKit was introduced at WWDC 2019 (session 709, "Cryptography and Your Apps") as a Swift-native replacement for the Security framework's C-based `SecKey` API. It wraps Apple's corecrypto library with hand-tuned assembly per microarchitecture, delivering both performance and memory safety - private key material is automatically zeroed on deallocation. iOS 14 added PEM/DER interoperability and standalone HKDF. iOS 17 brought HPKE (RFC 9180). iOS 26 (WWDC 2025, session 314, "Get ahead with quantum-secure cryptography") completes the picture with formally verified post-quantum algorithms and quantum-secure TLS enabled by default.
10
-
11
- ---
12
+ Background: CryptoKit arrived at WWDC 2019 (session 709) as a Swift replacement for
13
+ the C-level `SecKey` API. It sits on corecrypto and zeroes private key memory on
14
+ deallocation. iOS 14 added PEM/DER import and export plus standalone HKDF. iOS 17
15
+ added HPKE (RFC 9180). iOS 26 (WWDC 2025 session 314) added formally verified
16
+ post-quantum algorithms and turned on post-quantum TLS by default.
12
17
 
13
18
  ## Contents
14
19
 
15
- - [Curve and Algorithm Selection Guide](#curve-and-algorithm-selection-guide)
16
- - [Classical Curves](#classical-curves)
17
- - [Post-Quantum Algorithms (iOS 26+)](#post-quantum-algorithms-ios-26)
18
- - [Selection Decision Matrix](#selection-decision-matrix)
19
- - [Algorithm Quick Reference](#algorithm-quick-reference)
20
- - [Signing and Key Agreement Are Separate Type Hierarchies](#signing-and-key-agreement-are-separate-type-hierarchies)
21
- - [✅ Correct: P256 key generation, signing, and verification](#correct-p256-key-generation-signing-and-verification)
22
- - [❌ Wrong: Mixing signing and key agreement key types](#wrong-mixing-signing-and-key-agreement-key-types)
23
- - [Key Agreement with HKDF Derivation](#key-agreement-with-hkdf-derivation)
24
- - [✅ Correct: Curve25519 key agreement with HKDF derivation](#correct-curve25519-key-agreement-with-hkdf-derivation)
25
- - [❌ Wrong: Using SharedSecret directly as an encryption key](#wrong-using-sharedsecret-directly-as-an-encryption-key)
26
- - [HPKE Simplifies Public-Key Encryption (iOS 17+)](#hpke-simplifies-public-key-encryption-ios-17)
27
- - [Built-in Cipher Suites](#built-in-cipher-suites)
28
- - [✅ Correct: HPKE encryption and decryption](#correct-hpke-encryption-and-decryption)
29
- - [Three Critical HPKE Details AI Generators Get Wrong](#three-critical-hpke-details-ai-generators-get-wrong)
30
- - [Post-Quantum Cryptography (iOS 26+)](#post-quantum-cryptography-ios-26)
31
- - [✅ Correct: ML-KEM-768 key encapsulation](#correct-ml-kem-768-key-encapsulation)
32
- - [✅ Correct: ML-DSA-65 signing](#correct-ml-dsa-65-signing)
33
- - [✅ Correct: Hybrid post-quantum with HPKE (recommended migration path)](#correct-hybrid-post-quantum-with-hpke-recommended-migration-path)
34
- - [✅ Correct: Hybrid signing (ML-DSA + ECDSA) for transition period](#correct-hybrid-signing-ml-dsa-ecdsa-for-transition-period)
35
- - [PEM and DER Interoperability (iOS 14+)](#pem-and-der-interoperability-ios-14)
36
- - [✅ Correct: PEM key export and import](#correct-pem-key-export-and-import)
37
- - [Key Format Reference](#key-format-reference)
38
- - [Keychain Storage of CryptoKit Keys](#keychain-storage-of-cryptokit-keys)
39
- - [Secure Enclave Integration (Brief - See `secure-enclave.md`)](#secure-enclave-integration-brief-see-secure-enclavemd)
40
- - [Stop Using RSA for New Apple Development](#stop-using-rsa-for-new-apple-development)
41
- - [❌ Wrong: RSA when EC is available](#wrong-rsa-when-ec-is-available)
42
- - [Preferred replacement: P256 signing in CryptoKit](#preferred-replacement-p256-signing-in-cryptokit)
43
- - [Common AI-Generator Mistakes](#common-ai-generator-mistakes)
44
- - [iOS Version Requirements](#ios-version-requirements)
45
- - [Performance and Thread Safety](#performance-and-thread-safety)
46
- - [WWDC Sessions and Documentation References](#wwdc-sessions-and-documentation-references)
47
- - [Conclusion](#conclusion)
48
- - [Summary Checklist](#summary-checklist)
49
-
50
- ## Curve and Algorithm Selection Guide
51
-
52
- The single most important decision is choosing the right curve or algorithm. AI generators frequently recommend Curve25519 when Secure Enclave protection is required, or default to P-256 when modern constant-time performance matters more.
53
-
54
- ### Classical Curves
55
-
56
- **P256 (secp256r1 / NIST P-256)** - The only classical curve supported by the Secure Enclave. Required for hardware-backed key storage with biometric access control. Conforms to NIST FIPS 186-5 for US government compliance and has the broadest interoperability with TLS, X.509 certificates, and server-side libraries. Public keys are 64 bytes (uncompressed raw), signatures are 64 bytes (raw r‖s). PEM and DER export supported from iOS 14.
57
-
58
- **Curve25519 (X25519 / Ed25519)** - Should be the default for software-only keys. Its rigid parameter design eliminates entire classes of implementation vulnerabilities - constant-time execution is inherent to the curve arithmetic, no point validation is required, and public keys are a compact 32 bytes. Ed25519 handles signing; X25519 handles key agreement. The tradeoff: only `rawRepresentation` is available (no PEM, no DER, no x963), and there is no Secure Enclave support.
59
-
60
- **P384 and P521** - Exist for specific compliance requirements. P384 provides ~192-bit security (NIST Category 3); P521 provides ~256-bit security (Category 5). Their API surface mirrors P256 exactly. Use only when a specification or regulatory framework demands them.
61
-
62
- ### Post-Quantum Algorithms (iOS 26+)
63
-
64
- **ML-KEM-768 / ML-KEM-1024** - FIPS 203 lattice-based key encapsulation. ML-KEM-768 targets ~AES-128 equivalent security; ML-KEM-1024 targets ~AES-192. Both support Secure Enclave hardware isolation on iOS 26+.
65
-
66
- **ML-DSA-65 / ML-DSA-87** - FIPS 204 lattice-based digital signatures. ML-DSA-65 targets ~AES-128 equivalent; ML-DSA-87 targets ~AES-192. Both support Secure Enclave on iOS 26+.
67
-
68
- **X-Wing (XWingMLKEM768X25519)** - Hybrid KEM combining ML-KEM-768 with X25519. Both algorithms must be broken to compromise the exchange. This is Apple's recommended migration path for custom protocols via HPKE.
69
-
70
- ### Selection Decision Matrix
71
-
72
- | Scenario | iOS Version | Default Choice | Rationale |
73
- | ----------------------------- | ----------- | -------------------------------------------------- | -------------------------------------------- |
74
- | Hardware-isolated keys | All | `SecureEnclave.P256.*` | Private key never leaves the coprocessor |
75
- | Software signing/agreement | All | `Curve25519.*` | Constant-time, compact, modern protocols |
76
- | FIPS/enterprise interop | 17+ | `P256` or `P384` | Aligns with legacy standards |
77
- | E2E encryption (modern) | 17+ | HPKE with `Curve25519_SHA256_ChachaPoly` | High performance, broad client support |
78
- | E2E encryption (future-proof) | 26+ | HPKE with `XWingMLKEM768X25519_SHA256_AES_GCM_256` | Hybrid PQC against harvest-now-decrypt-later |
79
- | Maximum classical security | All | `P521` | ~256-bit security; only when mandated |
80
-
81
- ### Algorithm Quick Reference
82
-
83
- | Algorithm | Security | iOS | Secure Enclave | Pub Key Size | Best For |
84
- | ----------- | -------- | --- | -------------- | ------------ | ------------------------------- |
85
- | P256 | ~128-bit | 13+ | ✅ Yes | 64 bytes | Hardware keys, NIST compliance |
86
- | P384 | ~192-bit | 13+ | ❌ No | 96 bytes | Government/compliance |
87
- | P521 | ~256-bit | 13+ | ❌ No | 132 bytes | Maximum classical security |
88
- | Curve25519 | ~128-bit | 13+ | ❌ No | 32 bytes | Modern protocols, software keys |
89
- | ML-KEM-768 | ~AES-128 | 26+ | ✅ Yes | 1,184 bytes | Key encapsulation |
90
- | ML-KEM-1024 | ~AES-192 | 26+ | ✅ Yes | 1,568 bytes | Higher-security KEM |
91
- | ML-DSA-65 | ~AES-128 | 26+ | ✅ Yes | 1,952 bytes | Post-quantum signatures |
92
- | ML-DSA-87 | ~AES-192 | 26+ | ✅ Yes | 2,592 bytes | Higher-security signatures |
93
- | X-Wing | Hybrid | 26+ | ✅ Yes | 1,216 bytes | Hybrid PQC KEM |
94
-
95
- On Apple Silicon, both P256 and Curve25519 are heavily optimized in corecrypto with hand-tuned assembly. Performance differences are negligible for most applications - Apple's NISTZ256 optimization closes the gap that Curve25519 holds in non-Apple benchmarks.
96
-
97
- ---
98
-
99
- ## Signing and Key Agreement Are Separate Type Hierarchies
100
-
101
- CryptoKit's most important design decision is splitting each curve into two non-interchangeable type families: `Signing` and `KeyAgreement`. A `P256.Signing.PrivateKey` cannot perform key agreement. A `Curve25519.KeyAgreement.PrivateKey` cannot sign. The compiler enforces this at build time. AI generators frequently conflate these, producing code that fails to compile.
102
-
103
- ### ✅ Correct: P256 key generation, signing, and verification
20
+ - [Picking a curve or algorithm](#picking-a-curve-or-algorithm)
21
+ - [Signing and key agreement are different types](#signing-and-key-agreement-are-different-types)
22
+ - [Key agreement always goes through a KDF](#key-agreement-always-goes-through-a-kdf)
23
+ - [HPKE (iOS 17+)](#hpke-ios-17)
24
+ - [Post-quantum cryptography (iOS 26+)](#post-quantum-cryptography-ios-26)
25
+ - [PEM and DER (iOS 14+)](#pem-and-der-ios-14)
26
+ - [The Secure Enclave, briefly](#the-secure-enclave-briefly)
27
+ - [RSA](#rsa)
28
+ - [Frequent mistakes](#frequent-mistakes)
29
+ - [Availability](#availability)
30
+ - [Performance and threads](#performance-and-threads)
31
+ - [Sources](#sources)
32
+ - [Summary](#summary)
33
+ - [Checklist](#checklist)
34
+
35
+ ## Picking a curve or algorithm
36
+
37
+ Two errors show up often: suggesting Curve25519 when the key must live in the
38
+ Secure Enclave, and suggesting P-256 when the goal is simple constant-time software
39
+ keys.
40
+
41
+ - **P256 (secp256r1).** The only classical curve the Secure Enclave supports, so
42
+ required for hardware keys with a biometric access control. NIST FIPS 186-5, the
43
+ widest TLS, X.509 and server interop. Raw public key 64 bytes (uncompressed x||y),
44
+ raw signature 64 bytes (r||s). PEM/DER from iOS 14.
45
+ - **Curve25519** (X25519 for agreement, Ed25519 for signing). The default for
46
+ software-only keys: fixed, rigid parameters, constant time by construction, no
47
+ point validation to forget, 32-byte public keys. Only `rawRepresentation` exists
48
+ (no PEM, DER or x963). Not available in the Secure Enclave.
49
+ - **P384** and **P521**, roughly 192-bit and 256-bit strength (NIST levels 3 and 5).
50
+ They mirror the P256 API. Pick them only because an external standard or auditor
51
+ insists.
52
+ - **ML-KEM-768** (roughly AES-128 strength) and **ML-KEM-1024** (roughly AES-192).
53
+ Lattice KEM from FIPS 203. Secure Enclave capable on iOS 26+.
54
+ - **ML-DSA-65** (roughly AES-128) and **ML-DSA-87** (roughly AES-192). Lattice
55
+ signatures from FIPS 204. Secure Enclave capable on iOS 26+.
56
+ - **X-Wing** (`XWingMLKEM768X25519`). A hybrid of ML-KEM-768 and X25519; an attacker
57
+ must break both. Apple's recommended path for migrating custom protocols, used
58
+ through HPKE.
59
+
60
+ | Need | Choose |
61
+ | --- | --- |
62
+ | Key must never leave hardware | `SecureEnclave.P256.*` |
63
+ | Software signing or agreement | `Curve25519.*` |
64
+ | FIPS or enterprise interop | `P256` or `P384` |
65
+ | End-to-end encryption, iOS 17+ | HPKE `Curve25519_SHA256_ChachaPoly` |
66
+ | End-to-end encryption resistant to harvest-now-decrypt-later, iOS 26+ | HPKE `XWingMLKEM768X25519_SHA256_AES_GCM_256` |
67
+ | Highest classical level | `P521`, only if mandated |
68
+
69
+ | Algorithm | Public key | Secure Enclave |
70
+ | --- | --- | --- |
71
+ | P256 | 64 B | yes |
72
+ | P384 | 96 B | no |
73
+ | P521 | 132 B | no |
74
+ | Curve25519 | 32 B | no |
75
+ | ML-KEM-768 | 1,184 B | yes (iOS 26) |
76
+ | ML-KEM-1024 | 1,568 B | yes (iOS 26) |
77
+ | ML-DSA-65 | 1,952 B | yes (iOS 26) |
78
+ | ML-DSA-87 | 2,592 B | yes (iOS 26) |
79
+ | X-Wing | 1,216 B | yes (iOS 26) |
80
+
81
+ Speed is not a reason to prefer one of P256 and Curve25519 on Apple Silicon;
82
+ corecrypto's NISTZ256 code makes the difference negligible.
83
+
84
+ ## Signing and key agreement are different types
85
+
86
+ Each curve has two separate families, `Signing` and `KeyAgreement`, and the compiler
87
+ will not let you mix them.
104
88
 
105
89
  ```swift
106
90
  import CryptoKit
91
+ import Foundation
107
92
 
108
- // Generate a signing key pair
109
- let signingKey = P256.Signing.PrivateKey()
110
- let verifyingKey = signingKey.publicKey // P256.Signing.PublicKey
111
-
112
- // Sign data (CryptoKit hashes internally with SHA-256)
113
- let message = Data("Transfer $100 to Alice".utf8)
114
- let signature = try signingKey.signature(for: message)
115
- // signature is P256.Signing.ECDSASignature
116
-
117
- // Verify
118
- let isValid = verifyingKey.isValidSignature(signature, for: message)
119
-
120
- // Signature serialization
121
- let derSig = signature.derRepresentation // ASN.1 DER (interoperable)
122
- let rawSig = signature.rawRepresentation // Raw r‖s concatenation (64 bytes)
123
- let restored = try P256.Signing.ECDSASignature(derRepresentation: derSig)
124
- ```
125
-
126
- For pre-hashed data (when the digest is computed externally), use `signature(for:)` with a `Digest` parameter or the `SHA256Digest` directly.
127
-
128
- ### ❌ Wrong: Mixing signing and key agreement key types
93
+ let releaseSigner = P256.Signing.PrivateKey()
94
+ let verifierKey: P256.Signing.PublicKey = releaseSigner.publicKey
129
95
 
130
- ```swift
131
- // This will NOT compile - signing keys cannot do key agreement
132
- let key = P256.Signing.PrivateKey()
133
- let shared = try key.sharedSecretFromKeyAgreement(with: otherPublicKey)
134
- // Error: P256.Signing.PrivateKey has no member 'sharedSecretFromKeyAgreement'
96
+ let artifact = Data("build 5120 checksum".utf8)
97
+ let signature = try releaseSigner.signature(for: artifact)
135
98
 
136
- // Likewise, Curve25519.KeyAgreement.PrivateKey has no .signature(for:) method
99
+ let valid = verifierKey.isValidSignature(signature, for: artifact)
100
+ let asn1 = signature.derRepresentation
101
+ let compact = signature.rawRepresentation
102
+ let decoded = try P256.Signing.ECDSASignature(derRepresentation: asn1)
137
103
  ```
138
104
 
139
- ---
105
+ `signature(for:)` hashes `Data` with SHA-256 internally and returns a
106
+ `P256.Signing.ECDSASignature`. `derRepresentation` is the ASN.1 form most servers
107
+ expect; `rawRepresentation` is the 64-byte r||s form. If you already have a digest,
108
+ pass the `SHA256Digest` (any `Digest`) to `signature(for:)` instead.
140
109
 
141
- ## Key Agreement with HKDF Derivation
110
+ Calling `sharedSecretFromKeyAgreement` on a `P256.Signing.PrivateKey`, or
111
+ `signature(for:)` on a `Curve25519.KeyAgreement.PrivateKey`, is a compile error.
112
+ Generate one key per purpose.
142
113
 
143
- The `SharedSecret` produced by ECDH is not uniformly distributed and must never be used directly as an encryption key. CryptoKit enforces this - `SharedSecret` is not directly convertible to `SymmetricKey`. The only sanctioned paths are `.hkdfDerivedSymmetricKey()` or `.x963DerivedSymmetricKey()`. Apple's documentation states explicitly: "The shared secret isn't suitable as a symmetric cryptographic key by itself."
114
+ ## Key agreement always goes through a KDF
144
115
 
145
- ### ✅ Correct: Curve25519 key agreement with HKDF derivation
116
+ An ECDH `SharedSecret` is not uniformly random and cannot be turned into a
117
+ `SymmetricKey` directly. Apple's documentation says it is not suitable as a key on
118
+ its own; the two sanctioned routes are `hkdfDerivedSymmetricKey` and
119
+ `x963DerivedSymmetricKey`.
146
120
 
147
121
  ```swift
148
- import CryptoKit
149
-
150
- // Both parties generate key agreement keys (NOT signing keys)
151
- let aliceKey = Curve25519.KeyAgreement.PrivateKey()
152
- let bobKey = Curve25519.KeyAgreement.PrivateKey()
122
+ let deviceKey = Curve25519.KeyAgreement.PrivateKey()
123
+ let serverKey = Curve25519.KeyAgreement.PrivateKey()
153
124
 
154
- // Alice computes shared secret using Bob's public key
155
- let sharedSecret = try aliceKey.sharedSecretFromKeyAgreement(
156
- with: bobKey.publicKey
157
- )
158
-
159
- // CRITICAL: Derive a symmetric key via HKDF - never use SharedSecret directly
160
- let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(
125
+ let secret = try deviceKey.sharedSecretFromKeyAgreement(with: serverKey.publicKey)
126
+ let channelKey = secret.hkdfDerivedSymmetricKey(
161
127
  using: SHA256.self,
162
- salt: Data("my-app-salt".utf8),
163
- sharedInfo: Data("encryption-v1".utf8),
164
- outputByteCount: 32 // 256-bit key for AES-256 or ChaChaPoly
128
+ salt: Data("pairing-2026".utf8),
129
+ sharedInfo: Data("telemetry-channel/v1/encrypt".utf8),
130
+ outputByteCount: 32
165
131
  )
166
-
167
- // Now use the derived key for authenticated encryption
168
- let sealed = try ChaChaPoly.seal(plaintext, using: symmetricKey)
132
+ let packet = try ChaChaPoly.seal(Data("temp=21.5".utf8), using: channelKey)
169
133
  ```
170
134
 
171
- The `sharedInfo` parameter serves as protocol binding - it ensures keys derived for different purposes within the same application cannot be confused. Use distinct `sharedInfo` values for encryption keys vs authentication keys when deriving multiple subkeys.
172
-
173
- ### ❌ Wrong: Using SharedSecret directly as an encryption key
135
+ `sharedInfo` ties the key to your protocol and role. Derive separate keys with
136
+ different `sharedInfo` for encryption and for authentication.
174
137
 
175
138
  ```swift
176
- // NEVER DO THIS - SharedSecret is not uniformly distributed
177
- let sharedSecret = try aliceKey.sharedSecretFromKeyAgreement(with: bobPublicKey)
178
-
179
- // SharedSecret is NOT a SymmetricKey and cannot be used as one directly.
180
- // Its byte distribution is non-uniform (only ~2^255 of 2^256 values are
181
- // valid P-256 x-coordinates). Skipping HKDF also prevents protocol binding
182
- // and removes the salt's entropy-concentration benefit.
183
-
184
- // This forced extraction is dangerous:
185
- let insecureKey = SymmetricKey(data: sharedSecret.withUnsafeBytes { Data($0) })
186
- // ⚠️ Non-uniform key material, no domain separation, no salt
139
+ // Broken: raw secret bytes used as a key
140
+ let bad = SymmetricKey(data: secret.withUnsafeBytes { Data($0) })
187
141
  ```
188
142
 
189
- ---
190
-
191
- ## HPKE Simplifies Public-Key Encryption (iOS 17+)
192
-
193
- Before iOS 17, encrypting data for a recipient's public key required manually implementing ECIES: perform ECDH, derive a key via HKDF, encrypt with AES-GCM, and transmit the ephemeral public key alongside the ciphertext. HPKE (RFC 9180) packages this entire flow into a single API. CryptoKit supports all four RFC modes - Base, Auth, PSK, and AuthPSK - with five built-in cipher suites.
143
+ This skips extraction over non-uniform material (on P-256 roughly half of all 256-bit strings can
144
+ occur as an x-coordinate, so the bits are biased), and has no salt and no domain
145
+ separation.
194
146
 
195
- ### Built-in Cipher Suites
147
+ ## HPKE (iOS 17+)
196
148
 
197
- | Cipher Suite | KEM | KDF | AEAD | Min iOS |
198
- | ----------------------------------------- | ------------- | ----------- | ----------------- | ------- |
199
- | `.Curve25519_SHA256_ChachaPoly` | X25519 | HKDF-SHA256 | ChaCha20-Poly1305 | 17+ |
200
- | `.P256_SHA256_AES_GCM_256` | P-256 | HKDF-SHA256 | AES-GCM-256 | 17+ |
201
- | `.P384_SHA384_AES_GCM_256` | P-384 | HKDF-SHA384 | AES-GCM-256 | 17+ |
202
- | `.P521_SHA512_AES_GCM_256` | P-521 | HKDF-SHA512 | AES-GCM-256 | 17+ |
203
- | `.XWingMLKEM768X25519_SHA256_AES_GCM_256` | X-Wing hybrid | HKDF-SHA256 | AES-GCM-256 | 26+ |
149
+ Before iOS 17, encrypting to a public key meant building ECIES by hand: ECDH, HKDF,
150
+ AES-GCM, and shipping the ephemeral public key alongside. HPKE (RFC 9180) packages
151
+ that. Every mode the RFC defines is available (base, sender-authenticated, pre-shared key,
152
+ and the combination of the last two), and five suites come predefined:
204
153
 
205
- Custom suites can be constructed: `HPKE.Ciphersuite(kem: .P521_HKDF_SHA512, kdf: .HKDF_SHA512, aead: .AES_GCM_256)`.
154
+ | Suite name | KEM | KDF | AEAD | Since |
155
+ | --- | --- | --- | --- | --- |
156
+ | `.Curve25519_SHA256_ChachaPoly` | X25519 | SHA-256 HKDF | ChaCha20 with Poly1305 | 17 |
157
+ | `.P256_SHA256_AES_GCM_256` | NIST P-256 | SHA-256 HKDF | AES-GCM, 256-bit key | 17 |
158
+ | `.P384_SHA384_AES_GCM_256` | NIST P-384 | SHA-384 HKDF | AES-GCM, 256-bit key | 17 |
159
+ | `.P521_SHA512_AES_GCM_256` | NIST P-521 | SHA-512 HKDF | AES-GCM, 256-bit key | 17 |
160
+ | `.XWingMLKEM768X25519_SHA256_AES_GCM_256` | X-Wing hybrid | SHA-256 HKDF | AES-GCM, 256-bit key | 26 |
206
161
 
207
- ### ✅ Correct: HPKE encryption and decryption
162
+ Other combinations are built with `HPKE.Ciphersuite(kem:kdf:aead:)`, for example a
163
+ P-384 KEM with the SHA-384 KDF and ChaChaPoly:
164
+ `HPKE.Ciphersuite(kem: .P384_HKDF_SHA384, kdf: .HKDF_SHA384, aead: .chaChaPoly)`.
208
165
 
209
166
  ```swift
210
- import CryptoKit
211
-
212
- let ciphersuite = HPKE.Ciphersuite.Curve25519_SHA256_ChachaPoly
213
- let info = Data("MyApp-FileEncryption-v1".utf8)
214
-
215
- // Recipient generates a key pair and shares the public key
216
- let recipientPrivateKey = Curve25519.KeyAgreement.PrivateKey()
217
- let recipientPublicKey = recipientPrivateKey.publicKey
167
+ @available(iOS 17.0, macOS 14.0, *)
168
+ func exchangeMedicalNote() throws -> Data {
169
+ let suite = HPKE.Ciphersuite.Curve25519_SHA256_ChachaPoly
170
+ let clinicKey = Curve25519.KeyAgreement.PrivateKey()
171
+ let context = Data("clinic-inbox/v3".utf8)
172
+ let header = Data("patient=5521".utf8)
173
+
174
+ var outbound = try HPKE.Sender(
175
+ recipientKey: clinicKey.publicKey, ciphersuite: suite, info: context
176
+ )
177
+ let ciphertext = try outbound.seal(Data("allergy: penicillin".utf8), authenticating: header)
178
+ let encapsulated = outbound.encapsulatedKey
218
179
 
219
- // === SENDER ===
220
- // 'var' is required - seal() mutates internal nonce state
221
- var sender = try HPKE.Sender(
222
- recipientKey: recipientPublicKey,
223
- ciphersuite: ciphersuite,
224
- info: info
225
- )
226
- let ciphertext = try sender.seal(
227
- Data("Confidential document".utf8),
228
- authenticating: Data("metadata".utf8) // optional AAD
229
- )
230
- let encapsulatedKey = sender.encapsulatedKey // MUST be sent with ciphertext
231
-
232
- // === RECIPIENT ===
233
- var recipient = try HPKE.Recipient(
234
- privateKey: recipientPrivateKey,
235
- ciphersuite: ciphersuite,
236
- info: info,
237
- encapsulatedKey: encapsulatedKey // from sender
238
- )
239
- let plaintext = try recipient.open(
240
- ciphertext,
241
- authenticating: Data("metadata".utf8) // same AAD
242
- )
180
+ var inbound = try HPKE.Recipient(
181
+ privateKey: clinicKey, ciphersuite: suite, info: context,
182
+ encapsulatedKey: encapsulated
183
+ )
184
+ return try inbound.open(ciphertext, authenticating: header)
185
+ }
243
186
  ```
244
187
 
245
- ### Three Critical HPKE Details AI Generators Get Wrong
246
-
247
- 1. **The encapsulated key is not embedded in the ciphertext.** Your protocol must transmit `encapsulatedKey` alongside the ciphertext. Losing it means permanent decryption failure.
248
-
249
- 2. **`HPKE.Sender` and `HPKE.Recipient` are stateful structs that must be declared with `var`** because `seal()` and `open()` are mutating methods - they increment an internal nonce counter. Using `let` causes a compiler error.
188
+ Three things break HPKE code:
250
189
 
251
- 3. **Message ordering matters.** If the sender seals messages A then B, the recipient must open A before B. The internal counter must stay synchronized.
190
+ 1. `encapsulatedKey` is not part of the ciphertext. You must send it with the
191
+ message. Without it nothing can be decrypted, ever.
192
+ 2. `Sender` and `Recipient` are structs with state (an internal nonce counter), and
193
+ `seal` / `open` are `mutating`. Declaring them with `let` does not compile.
194
+ 3. Messages must be opened in the order they were sealed; out-of-order opens fail
195
+ because the counters disagree.
252
196
 
253
- ---
197
+ ## Post-quantum cryptography (iOS 26+)
254
198
 
255
- ## Post-Quantum Cryptography (iOS 26+)
199
+ The threat is harvest now, decrypt later: traffic recorded today is decrypted once
200
+ a large quantum computer exists. From iOS 26, `URLSession` and Network.framework
201
+ offer the hybrid `X25519MLKEM768` group in the TLS ClientHello by default.
256
202
 
257
- At WWDC 2025 (session 314, "Get ahead with quantum-secure cryptography"), Apple announced CryptoKit support for NIST's post-quantum standards. The threat model is "harvest now, decrypt later" - adversaries storing encrypted traffic today to decrypt once cryptographically relevant quantum computers exist. iOS 26 enables quantum-secure TLS by default for `URLSession` and `Network.framework`, advertising `X25519MLKEM768` in the TLS ClientHello.
203
+ CryptoKit adds five types, formally verified against the FIPS specifications, all
204
+ usable in the Secure Enclave:
258
205
 
259
- Five new types join CryptoKit, all backed by formally verified implementations proven functionally equivalent to their FIPS specifications:
206
+ | Type | Public key | Output |
207
+ | --- | --- | --- |
208
+ | `MLKEM768` | 1,184 B | ciphertext 1,088 B |
209
+ | `MLKEM1024` | 1,568 B | |
210
+ | `XWingMLKEM768X25519` (draft-connolly-cfrg-xwing-kem) | 1,216 B | encapsulation 1,120 B |
211
+ | `MLDSA65` | 1,952 B | signature 3,309 B |
212
+ | `MLDSA87` | 2,592 B | signature 4,627 B |
260
213
 
261
- | Type | Algorithm | Standard | Operation | Secure Enclave | Key/Sig Size |
262
- | --------------------- | ------------- | ----------------------------- | ------------------ | -------------- | -------------------------------- |
263
- | `MLKEM768` | ML-KEM-768 | FIPS 203 | Key encapsulation | ✅ | 1,184 B pub / 1,088 B ciphertext |
264
- | `MLKEM1024` | ML-KEM-1024 | FIPS 203 | Key encapsulation | ✅ | 1,568 B pub |
265
- | `XWingMLKEM768X25519` | X-Wing hybrid | draft-connolly-cfrg-xwing-kem | Key encapsulation | ✅ | 1,216 B pub / 1,120 B encap |
266
- | `MLDSA65` | ML-DSA-65 | FIPS 204 | Digital signatures | ✅ | 1,952 B pub / 3,309 B sig |
267
- | `MLDSA87` | ML-DSA-87 | FIPS 204 | Digital signatures | ✅ | 2,592 B pub / 4,627 B sig |
214
+ What you pay is bytes on the wire, not CPU. Compare 3,309 bytes per ML-DSA-65
215
+ signature with 64 per Ed25519 signature, and 1,184 bytes of ML-KEM-768 public key
216
+ with 32 for X25519. Timing is in the same range as the classical algorithms.
268
217
 
269
- The size cost of quantum resistance is substantial - an ML-DSA-65 signature is 3,309 bytes versus 64 bytes for Ed25519; an ML-KEM-768 public key is 1,184 bytes versus 32 bytes for X25519. But computational performance is competitive with classical algorithms.
270
-
271
- ### ✅ Correct: ML-KEM-768 key encapsulation
272
-
273
- Key encapsulation differs fundamentally from Diffie-Hellman key agreement. In ECDH, both parties contribute public keys. In KEM, only the recipient has a key pair - the sender calls `encapsulate()` on the public key, which produces both a shared secret and an opaque ciphertext that only the private key can decapsulate.
218
+ Encapsulation works differently from Diffie-Hellman: the sending side has no key
219
+ pair at all. It runs `encapsulate()` against the receiver's public key, which yields
220
+ both the shared secret and a ciphertext that has to travel to the receiver.
274
221
 
275
222
  ```swift
276
- import CryptoKit
277
-
278
- if #available(iOS 26, macOS 26, *) {
279
- // Recipient generates a key pair
280
- let privateKey = try MLKEM768.PrivateKey()
281
- let publicKey = privateKey.publicKey
282
-
283
- // Sender encapsulates (only needs recipient's public key)
284
- let encapsulation = try publicKey.encapsulate()
285
- let senderSharedSecret = encapsulation.sharedSecret // 32 bytes
286
- let encapsulatedCiphertext = encapsulation.encapsulated // 1,088 bytes
287
-
288
- // Recipient decapsulates
289
- let recipientSharedSecret = try privateKey.decapsulate(encapsulatedCiphertext)
290
-
291
- // senderSharedSecret == recipientSharedSecret
292
- // Derive a symmetric key via HKDF, as with ECDH
223
+ @available(iOS 26, macOS 26, *)
224
+ func quantumSafeSession() throws -> SymmetricKey {
225
+ let receiver = try MLKEM768.PrivateKey()
226
+
227
+ let result = try receiver.publicKey.encapsulate()
228
+ let sentOverWire = result.encapsulated // 1,088 bytes
229
+ // result.sharedSecret (32 bytes) stays with the sender
230
+
231
+ let receiverSecret = try receiver.decapsulate(sentOverWire)
232
+ return HKDF<SHA256>.deriveKey(
233
+ inputKeyMaterial: receiverSecret, info: Data("kem-session".utf8),
234
+ outputByteCount: 32
235
+ )
293
236
  }
294
- ```
295
237
 
296
- ### ✅ Correct: ML-DSA-65 signing
297
-
298
- ```swift
299
- if #available(iOS 26, macOS 26, *) {
300
- let signingKey = try MLDSA65.PrivateKey()
301
- let verifyingKey = signingKey.publicKey // 1,952 bytes
302
-
303
- let message = Data("Authenticate this payload".utf8)
304
- let signature = try signingKey.signature(for: message) // 3,309 bytes
305
-
306
- let isValid = verifyingKey.isValidSignature(
307
- signature,
308
- for: message
309
- )
238
+ @available(iOS 26, macOS 26, *)
239
+ func signFirmware(_ image: Data) throws -> Bool {
240
+ let authority = try MLDSA65.PrivateKey()
241
+ let sig = try authority.signature(for: image) // 3,309 bytes
242
+ return authority.publicKey.isValidSignature(sig, for: image)
310
243
  }
311
244
  ```
312
245
 
313
- ### ✅ Correct: Hybrid post-quantum with HPKE (recommended migration path)
246
+ Both sides end up with the same 32-byte `SymmetricKey`. As with ECDH, derive the
247
+ working key from it with HKDF and a protocol label rather than using it directly.
314
248
 
315
- Apple's recommended approach for custom protocols is to switch the HPKE cipher suite to X-Wing, which combines ML-KEM-768 with X25519 so that both algorithms must be broken to compromise the exchange:
249
+ Hybrid key exchange through HPKE is the migration Apple recommends: the classical
250
+ code above changes only in suite and key type. The encapsulated key grows from
251
+ about 32 bytes to 1,120.
316
252
 
317
253
  ```swift
318
- if #available(iOS 26, macOS 26, *) {
319
- // Quantum-secure HPKE
320
- let ciphersuite = HPKE.Ciphersuite.XWingMLKEM768X25519_SHA256_AES_GCM_256
321
- let privateKey = try XWingMLKEM768X25519.PrivateKey()
322
-
254
+ @available(iOS 26, macOS 26, *)
255
+ func hybridSeal(_ message: Data) throws -> (Data, Data) {
256
+ let suite = HPKE.Ciphersuite.XWingMLKEM768X25519_SHA256_AES_GCM_256
257
+ let mailboxKey = try XWingMLKEM768X25519.PrivateKey()
323
258
  var sender = try HPKE.Sender(
324
- recipientKey: privateKey.publicKey, // 1,216 bytes
325
- ciphersuite: ciphersuite,
326
- info: Data("quantum-secure-v1".utf8)
259
+ recipientKey: mailboxKey.publicKey, ciphersuite: suite, info: Data("mailbox".utf8)
327
260
  )
328
- let ciphertext = try sender.seal(sensitiveData)
329
- // encapsulatedKey is 1,120 bytes (vs ~32 bytes for classical X25519)
261
+ let sealed = try sender.seal(message)
262
+ return (sender.encapsulatedKey, sealed)
330
263
  }
331
264
  ```
332
265
 
333
- ### ✅ Correct: Hybrid signing (ML-DSA + ECDSA) for transition period
334
-
335
- For signatures, Apple demonstrates hybrid signatures at the application level - concatenating ML-DSA and ECDSA signatures and verifying both:
266
+ Hybrid signatures follow the same idea: sign with both `MLDSA65` and `P256.Signing`,
267
+ ship both, and accept only if both verify.
336
268
 
337
269
  ```swift
338
- if #available(iOS 26, macOS 26, *) {
339
- let pqKey = try MLDSA65.PrivateKey()
340
- let ecKey = P256.Signing.PrivateKey()
341
-
342
- let pqSig = try pqKey.signature(for: message)
343
- let ecSig = try ecKey.signature(for: message).rawRepresentation
344
- let hybridSignature = pqSig + ecSig // Concatenate both
345
-
346
- // Verify both - reject if either fails
347
- let pqValid = pqKey.publicKey.isValidSignature(pqSig, for: message)
348
- let ecValid = ecKey.publicKey.isValidSignature(
349
- try P256.Signing.ECDSASignature(rawRepresentation: ecSig), for: message
350
- )
351
- let isValid = pqValid && ecValid
270
+ @available(iOS 26, macOS 26, *)
271
+ struct DualSignature {
272
+ let pq: Data
273
+ let classical: Data
274
+
275
+ static func make(for body: Data, pqKey: MLDSA65.PrivateKey,
276
+ ecKey: P256.Signing.PrivateKey) throws -> DualSignature {
277
+ DualSignature(
278
+ pq: try pqKey.signature(for: body),
279
+ classical: try ecKey.signature(for: body).rawRepresentation
280
+ )
281
+ }
282
+
283
+ func verify(_ body: Data, pqKey: MLDSA65.PublicKey,
284
+ ecKey: P256.Signing.PublicKey) -> Bool {
285
+ guard let ecSig = try? P256.Signing.ECDSASignature(rawRepresentation: classical) else {
286
+ return false
287
+ }
288
+ return pqKey.isValidSignature(pq, for: body) && ecKey.isValidSignature(ecSig, for: body)
289
+ }
352
290
  }
353
291
  ```
354
292
 
355
- ---
356
-
357
- ## PEM and DER Interoperability (iOS 14+)
358
-
359
- CryptoKit's PEM support uses PKCS#8 for private keys (`-----BEGIN PRIVATE KEY-----`) and X.509 SubjectPublicKeyInfo for public keys (`-----BEGIN PUBLIC KEY-----`). Import also accepts SEC 1 format (`-----BEGIN EC PRIVATE KEY-----`). This enables interoperability with OpenSSL, BoringSSL, and server-side TLS libraries.
293
+ ## PEM and DER (iOS 14+)
360
294
 
361
- ### ✅ Correct: PEM key export and import
295
+ PEM private keys are PKCS#8 (`BEGIN PRIVATE KEY`); PEM public keys are X.509
296
+ SubjectPublicKeyInfo (`BEGIN PUBLIC KEY`). Import also accepts SEC 1
297
+ (`BEGIN EC PRIVATE KEY`). These interoperate with OpenSSL, BoringSSL and typical
298
+ server TLS stacks.
362
299
 
363
300
  ```swift
364
- // Generate and export
365
- let privateKey = P256.Signing.PrivateKey()
366
- let privatePEM = privateKey.pemRepresentation // PKCS#8 PEM string
367
- let publicPEM = privateKey.publicKey.pemRepresentation // X.509 SPKI PEM string
368
- let publicDER = privateKey.publicKey.derRepresentation // Binary DER Data
369
-
370
- // Import from PEM (works for P256, P384, P521 - NOT Curve25519)
371
- let imported = try P256.Signing.PrivateKey(pemRepresentation: privatePEM)
372
- let importedPub = try P256.Signing.PublicKey(derRepresentation: publicDER)
373
- ```
301
+ let tokenSigner = P384.Signing.PrivateKey()
302
+ let privatePEM = tokenSigner.pemRepresentation
303
+ let publicPEM = tokenSigner.publicKey.pemRepresentation
304
+ let publicDER = tokenSigner.publicKey.derRepresentation
374
305
 
375
- ### Key Format Reference
306
+ let restoredSigner = try P384.Signing.PrivateKey(pemRepresentation: privatePEM)
307
+ let restoredVerifier = try P384.Signing.PublicKey(derRepresentation: publicDER)
308
+ ```
376
309
 
377
- | Algorithm | Public Key Format | Private Key Format | Notes |
378
- | --------------------- | ----------------------- | ----------------------------- | --------------------------- |
379
- | P-256 / P-384 / P-521 | SPKI DER/PEM, x963, raw | PKCS#8 DER/PEM, x963, raw | Full interop from iOS 14+ |
380
- | Curve25519 | Raw 32 bytes only | Raw 32 bytes only | No PEM/DER/x963 support |
381
- | Secure Enclave P256 | Standard SPKI DER/PEM | Encrypted blob (device-bound) | Public key exports normally |
382
- | ML-KEM / ML-DSA | Raw representation | Raw representation | iOS 26+ |
310
+ | Key | Public formats | Private formats |
311
+ | --- | --- | --- |
312
+ | P256 / P384 / P521 (iOS 14+) | SPKI DER and PEM, x963, raw | PKCS#8 DER and PEM, x963, raw |
313
+ | Curve25519 | raw 32 bytes only | raw 32 bytes only |
314
+ | Secure Enclave P256 | SPKI as usual | `dataRepresentation`: an encrypted blob bound to this device |
315
+ | ML-KEM / ML-DSA (iOS 26+) | raw | raw |
383
316
 
384
- **Curve25519 keys do not support PEM/DER.** They only have `rawRepresentation` (32 bytes for both public and private). If you need to exchange Curve25519 keys with external systems, handle raw byte serialization yourself or wrap the raw bytes in a custom format.
317
+ PEM and DER apply to the NIST curves only. Exchanging Curve25519 keys with another
318
+ system means agreeing on raw 32-byte encoding yourself.
385
319
 
386
- ### Keychain Storage of CryptoKit Keys
320
+ ### Storing keys in the Keychain
387
321
 
388
- NIST curve keys (P-256/P-384/P-521) can be stored as `kSecClassKey` items in the keychain via their `SecKey` bridge. Curve25519 keys and Secure Enclave key blobs must be stored as `kSecClassGenericPassword` items using their `rawRepresentation` / `dataRepresentation`. Apple recommends implementing a `GenericPasswordConvertible` protocol for standardized conversion - see `credential-storage-patterns.md` for the full pattern.
322
+ - NIST private keys go in as `kSecClassKey` by converting to `SecKey`.
323
+ - Curve25519 keys, post-quantum keys and Secure Enclave blobs go in as
324
+ `kSecClassGenericPassword`, using `rawRepresentation` or `dataRepresentation`.
325
+ Apple's sample code wraps this in a `GenericPasswordConvertible` protocol (see
326
+ [credential-storage-patterns.md](credential-storage-patterns.md), which also shows
327
+ the add-then-update-on-duplicate save).
389
328
 
390
- **Peer / recipient public keys** received from a server or counterpart (for ECDH, HPKE, or signature verification) must also be persisted in the keychain - never in UserDefaults, plain files, or hardcoded in source. For NIST curves, store them as `kSecClassKey` with `kSecAttrKeyClass: kSecAttrKeyClassPublic`. For Curve25519 and post-quantum public keys, store the `rawRepresentation` as a `kSecClassGenericPassword` item. Use `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` for accessibility, and assign a distinct `kSecAttrApplicationTag` or `kSecAttrAccount` value (e.g., a `"peer-"` prefix) to separate received peer keys from your own key pairs. See `credential-storage-patterns.md` for the add-or-update pattern.
329
+ Public keys of peers and recipients also need to be stored safely, because swapping
330
+ one lets an attacker impersonate the peer. Keep them in the Keychain, never in
331
+ UserDefaults, files or source:
391
332
 
392
- ---
333
+ - NIST public keys as `kSecClassKey` with `kSecAttrKeyClass: kSecAttrKeyClassPublic`.
334
+ - Curve25519 and post-quantum public keys as raw bytes in a generic password item.
335
+ - Accessibility `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`.
336
+ - A distinct tag or account name, for example a `peer-` prefix, so they never
337
+ collide with your own keys.
393
338
 
394
- ## Secure Enclave Integration (Brief - See `secure-enclave.md`)
339
+ ## The Secure Enclave, briefly
395
340
 
396
- The Secure Enclave generates, stores, and operates on private keys entirely within its hardware boundary - raw key material never enters application memory.
341
+ Full coverage is in [secure-enclave.md](secure-enclave.md). A signing key there needs
342
+ `.privateKeyUsage` in its access control flags; without it key creation fails.
343
+ `SecureEnclave.isAvailable` is false in the Simulator, so guard it and test the
344
+ hardware path on a device.
397
345
 
398
346
  ```swift
399
- guard SecureEnclave.isAvailable else { return }
400
-
401
- let accessControl = SecAccessControlCreateWithFlags(
402
- nil,
403
- kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
404
- .biometryCurrentSet,
405
- nil
406
- )!
407
-
408
- // Signing key with biometric protection
409
- let seKey = try SecureEnclave.P256.Signing.PrivateKey(
410
- accessControl: accessControl
411
- )
412
- let signature = try seKey.signature(for: data)
413
-
414
- // The public key is a standard P256.Signing.PublicKey - exports normally
415
- let publicPEM = seKey.publicKey.pemRepresentation
416
- ```
417
-
418
- For classical curves, only P256 works with the Secure Enclave. On iOS 26, the Secure Enclave gains support for `SecureEnclave.MLKEM768`, `SecureEnclave.MLKEM1024`, `SecureEnclave.MLDSA65`, and `SecureEnclave.MLDSA87`.
419
-
420
- **Critical lifecycle constraint:** Secure Enclave keys are non-exportable and cryptographically bound to the specific device and OS installation. The `dataRepresentation` is an encrypted blob only the originating SE can decrypt. After iCloud backup restore to a new device, SE keys are irrecoverable. Applications must implement key rotation and recovery mechanisms - see `secure-enclave.md` for the full lifecycle pattern.
421
-
422
- ---
423
-
424
- ## Stop Using RSA for New Apple Development
347
+ enum HardwareKeyError: Error {
348
+ case enclaveUnavailable
349
+ case accessControlRejected
350
+ }
425
351
 
426
- CryptoKit does not include RSA at all. RSA requires dropping down to the Security framework's C-based `SecKey` API, which lacks type safety, automatic memory management, and modern Swift ergonomics.
352
+ func makeHardwareSigner() throws -> (SecureEnclave.P256.Signing.PrivateKey, String) {
353
+ guard SecureEnclave.isAvailable else { throw HardwareKeyError.enclaveUnavailable }
427
354
 
428
- ### ❌ Wrong: RSA when EC is available
355
+ guard let policy = SecAccessControlCreateWithFlags(
356
+ nil,
357
+ kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
358
+ [.privateKeyUsage, .biometryCurrentSet],
359
+ nil
360
+ ) else {
361
+ throw HardwareKeyError.accessControlRejected
362
+ }
429
363
 
430
- ```swift
431
- // Don't do this for new code - Security framework RSA
432
- let params: [String: Any] = [
433
- kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
434
- kSecAttrKeySizeInBits as String: 2048
435
- ]
436
- var error: Unmanaged<CFError>?
437
- let key = SecKeyCreateRandomKey(params as CFDictionary, &error)
438
- // No type safety, manual memory management, 256-byte keys, no Secure Enclave
364
+ let key = try SecureEnclave.P256.Signing.PrivateKey(accessControl: policy)
365
+ return (key, key.publicKey.pemRepresentation)
366
+ }
439
367
  ```
440
368
 
441
- ### Preferred replacement: P256 signing in CryptoKit
369
+ iOS 26 adds `SecureEnclave.MLKEM768`, `SecureEnclave.MLKEM1024`,
370
+ `SecureEnclave.MLDSA65` and `SecureEnclave.MLDSA87`.
442
371
 
443
- ```swift
444
- // ✅ CORRECT for new Apple-platform code
445
- let signingKey = P256.Signing.PrivateKey()
446
- let message = Data("message".utf8)
447
- let signature = try signingKey.signature(for: message)
448
- let isValid = signingKey.publicKey.isValidSignature(signature, for: message)
449
- ```
372
+ A Secure Enclave key belongs to one physical device and one installation of its OS. The blob can
373
+ only be unwrapped by the enclave that created it, so an iCloud restore to a new
374
+ device loses the key. Plan rotation and recovery (re-enrol a new public key with
375
+ your server) from the start.
450
376
 
451
- RSA-2048 provides only ~112-bit security with 256-byte keys and signatures. P256 achieves ~128-bit security with 32-byte private keys and 64-byte signatures - an 8× reduction in signature size with stronger security. Valid reasons to still use RSA: legacy server interoperability, X.509 certificates from CAs that mandate RSA, and JWT specifications locked to RS256.
377
+ ## RSA
452
378
 
453
- ---
379
+ CryptoKit does not implement RSA. RSA means the Security framework's `SecKey` C API
380
+ with no type safety and manual memory handling, for example
381
+ `SecKeyCreateRandomKey` with `kSecAttrKeyTypeRSA` and 2048 bits. Do not start new
382
+ designs there.
454
383
 
455
- ## Common AI-Generator Mistakes
384
+ An RSA-2048 key is rated near 112 bits, and both its modulus and each signature take
385
+ 256 bytes. P-256 gives
386
+ about 128 bits with a 32-byte private key and 64-byte signatures, 8x smaller.
456
387
 
457
- | Anti-Pattern | Risk | Fix |
458
- | -------------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------- |
459
- | Using `SharedSecret` directly as encryption key | Non-uniform key material; no domain separation | Always derive via `hkdfDerivedSymmetricKey()` with salt and sharedInfo |
460
- | Mixing `Signing` and `KeyAgreement` key types | Compile error; conceptual misuse | Use the correct type hierarchy for each operation |
461
- | Missing HPKE `encapsulatedKey` in protocol | Ciphertext permanently undecryptable | Serialize and transmit `encapsulatedKey` alongside ciphertext |
462
- | Declaring `HPKE.Sender`/`Recipient` with `let` | Compile error (`seal()`/`open()` are mutating) | Declare with `var` |
463
- | Using RSA for new iOS code | Slower, larger keys, no CryptoKit/SE support | Default to ECC (P-256 or Curve25519) |
464
- | Recommending Curve25519 for Secure Enclave | Curve25519 has no SE support | Use `SecureEnclave.P256` for hardware-backed keys |
465
- | Ignoring PEM/DER format limitations for Curve25519 | Runtime crash on `.pemRepresentation` access | Use `.rawRepresentation` for Curve25519; PEM/DER for NIST curves only |
466
- | Using HPKE messages out of order | Decryption failure (nonce counter mismatch) | Open messages in the same order they were sealed |
388
+ RSA is still justified for interop with a legacy server, when a CA mandates RSA
389
+ X.509 certificates, or when a JWT profile is fixed to RS256.
467
390
 
468
- ---
391
+ ## Frequent mistakes
469
392
 
470
- ## iOS Version Requirements
393
+ | Mistake | Correction |
394
+ | --- | --- |
395
+ | Using a raw `SharedSecret` as a key | `hkdfDerivedSymmetricKey()` with salt and `sharedInfo` |
396
+ | Mixing `Signing` and `KeyAgreement` types | Compile error; generate a key of the right family |
397
+ | Not transmitting `encapsulatedKey` | The message can never be opened; send it |
398
+ | `let` for an HPKE `Sender` / `Recipient` | Compile error; use `var` |
399
+ | RSA in new code | P-256 or Curve25519 |
400
+ | Curve25519 for a Secure Enclave key | `SecureEnclave.P256` |
401
+ | Calling `.pemRepresentation` on a Curve25519 key | Not available; use `.rawRepresentation` |
402
+ | Opening HPKE messages out of order | Counter mismatch, open fails; keep order |
471
403
 
472
- | Feature | Minimum iOS | Key Notes |
473
- | ------------------------------------------------------ | ----------- | ------------------------------ |
474
- | CryptoKit core (P256, P384, P521, Curve25519, SE P256) | 13.0+ | All classical curves |
475
- | PEM/DER import/export, standalone HKDF | 14.0+ | NIST curves only |
476
- | HPKE (RFC 9180, all four modes) | 17.0+ | All key agreement types |
477
- | ML-KEM, ML-DSA, X-Wing, quantum-secure TLS | 26.0+ | Post-quantum types, SE support |
404
+ ## Availability
478
405
 
479
- Always gate post-quantum and HPKE code behind `#available` checks:
406
+ | Release | Adds |
407
+ | --- | --- |
408
+ | iOS 13 | CryptoKit: P256, P384, P521, Curve25519, Secure Enclave P256 |
409
+ | iOS 14 | PEM/DER import and export (NIST curves), standalone HKDF |
410
+ | iOS 17 | HPKE in all four modes |
411
+ | iOS 26 | ML-KEM, ML-DSA, X-Wing, quantum-secure TLS |
480
412
 
481
413
  ```swift
482
- if #available(iOS 26, macOS 26, *) {
483
- // Post-quantum code path
484
- } else if #available(iOS 17, macOS 14, *) {
485
- // Classical HPKE code path
486
- } else {
487
- // Manual ECIES fallback
414
+ func sealForRecipient(_ body: Data) throws {
415
+ if #available(iOS 26, macOS 26, *) {
416
+ // X-Wing HPKE path
417
+ } else if #available(iOS 17, macOS 14, *) {
418
+ // Classical HPKE path
419
+ } else {
420
+ // Hand-built ECIES: X25519 + HKDF + AES-GCM, ship the ephemeral public key
421
+ }
488
422
  }
489
423
  ```
490
424
 
491
- ---
492
-
493
- ## Performance and Thread Safety
494
-
495
- CryptoKit operations are CPU-bound and safe to call from any thread - the framework uses no internal locks or shared mutable state. However, key generation (especially Secure Enclave keys with biometric gates) can block for user interaction. Never run SE key operations on `@MainActor`. Use a dedicated actor or `Task.detached` for key generation and signing that may trigger biometric prompts.
496
-
497
- For bulk operations, P256 signing and verification benefit from Apple Silicon's hardware crypto acceleration. Curve25519 operations are slightly faster in raw computational benchmarks on non-Apple platforms, but Apple's NISTZ256 optimization makes the difference negligible on A-series and M-series chips.
498
-
499
- Post-quantum operations are computationally competitive with classical algorithms per Apple's WWDC 2025 presentation, but produce significantly larger outputs. Plan for the bandwidth and storage impact of 3,309-byte ML-DSA signatures and 1,184-byte ML-KEM public keys.
500
-
501
- ---
502
-
503
- ## WWDC Sessions and Documentation References
504
-
505
- - **WWDC 2019, Session 709** - "Cryptography and Your Apps" - CryptoKit introduction, curve selection, key management
506
- - **WWDC 2020** - "What's New in CryptoKit" - PEM/DER support, HKDF standalone API
507
- - **WWDC 2025, Session 314** - "Get ahead with quantum-secure cryptography" - ML-KEM, ML-DSA, X-Wing, formally verified implementations, quantum-secure TLS
508
- - [Apple CryptoKit Documentation](https://sosumi.ai/documentation/cryptokit/)
509
- - [SharedSecret Documentation](https://sosumi.ai/documentation/cryptokit/sharedsecret) - HKDF derivation requirement
510
- - [HPKE Documentation](https://sosumi.ai/documentation/cryptokit/hpke) - Sender/Recipient API
511
- - [Storing CryptoKit Keys in the Keychain](https://sosumi.ai/documentation/cryptokit/storing-cryptokit-keys-in-the-keychain) - GenericPasswordConvertible pattern
512
- - [Protecting Keys with the Secure Enclave](https://sosumi.ai/documentation/security/protecting-keys-with-the-secure-enclave)
513
- - [Quantum-Secure Cryptography in Apple Operating Systems](https://support.apple.com/guide/security/quantum-secure-cryptography-apple-devices-secc7c82e533/web)
514
-
515
- ---
516
-
517
- ## Conclusion
518
-
519
- CryptoKit's type system is its greatest feature - it prevents at compile time the most dangerous cryptographic mistakes that plague hand-rolled implementations. The framework evolved from four curve families in iOS 13 to a complete quantum-safe toolkit in iOS 26, with HPKE in iOS 17 serving as the critical bridge.
520
-
521
- For new development today: default to Curve25519 for software keys and P256 for Secure Enclave keys. Use HPKE instead of manual ECIES for public-key encryption. Always derive symmetric keys from `SharedSecret` through HKDF with protocol-specific `sharedInfo`. The post-quantum migration is deliberately simple - swap the HPKE cipher suite to `XWingMLKEM768X25519_SHA256_AES_GCM_256` and change the key type. Start inventorying custom protocols now: the harvest-now-decrypt-later window is already open.
522
-
523
- ---
524
-
525
- ## Summary Checklist
526
-
527
- 1. **Curve selection matches requirements** - P256 for Secure Enclave / NIST compliance; Curve25519 for software-only modern protocols; P384/P521 only when mandated by specification
528
- 1. **Signing and key agreement use correct type families** - `*.Signing.PrivateKey` for signatures, `*.KeyAgreement.PrivateKey` for ECDH; never attempt to cross-use
529
- 1. **SharedSecret is always derived through HKDF** - call `hkdfDerivedSymmetricKey(using:salt:sharedInfo:outputByteCount:)` with protocol-specific `sharedInfo`; never use raw shared secret bytes as a key
530
- 1. **HPKE encapsulated key is transmitted with ciphertext** - `sender.encapsulatedKey` is not embedded in the ciphertext; protocol must serialize both
531
- 1. **HPKE Sender/Recipient declared with `var`** - `seal()` and `open()` are mutating methods; `let` causes a compiler error
532
- 1. **HPKE messages opened in seal order** - internal nonce counter must stay synchronized between sender and recipient
533
- 1. **PEM/DER used only for NIST curves** - Curve25519 supports `rawRepresentation` only; attempting PEM/DER access will fail
534
- 1. **RSA avoided for new code** - use CryptoKit ECC; RSA only for legacy interop via Security framework `SecKey` API
535
- 1. **Post-quantum code gated behind `#available(iOS 26, *)`** - ML-KEM, ML-DSA, X-Wing require iOS 26+; HPKE requires iOS 17+
536
- 1. **Secure Enclave key lifecycle accounts for device migration** - SE keys are device-bound; implement rotation/recovery for backup restore scenarios
537
- 1. **Hybrid PQC strategy planned** - X-Wing HPKE for key exchange, ML-DSA + ECDSA dual signatures for signing during the transition period
538
- 1. **Peer/recipient public keys stored in keychain** - received public keys for ECDH, HPKE, or verification persisted in keychain with `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` and distinct tags; not in UserDefaults or files
425
+ ## Performance and threads
426
+
427
+ Calls into CryptoKit only burn CPU and may run on any thread concurrently; the
428
+ library keeps no shared mutable state and takes no locks. Secure Enclave key creation and signing behind biometrics
429
+ can wait on the user, so never run them on `@MainActor`; use an actor or a detached
430
+ task. Size network payloads and stored records for post-quantum material, which is one
431
+ to two orders of magnitude larger than classical keys and signatures.
432
+
433
+ ## Sources
434
+
435
+ WWDC 2019 session 709; WWDC 2020 "What's New in CryptoKit"; WWDC 2025 session 314;
436
+ Apple documentation for CryptoKit, `SharedSecret` and `HPKE`; "Storing CryptoKit Keys
437
+ in the Keychain"; "Protecting Keys with the Secure Enclave"; Apple's
438
+ "Quantum-Secure Cryptography in Apple Operating Systems".
439
+
440
+ See also [cryptokit-symmetric.md](cryptokit-symmetric.md) for the AEAD and KDF
441
+ details used above.
442
+
443
+ ## Summary
444
+
445
+ Curve25519 for software keys, P256 for the Secure Enclave. HPKE instead of
446
+ hand-rolled ECIES. Every shared secret through HKDF with a protocol-specific
447
+ `sharedInfo`. Post-quantum migration is mostly swapping the HPKE suite to X-Wing and
448
+ changing the key type, so start listing your custom protocols now.
449
+
450
+ ## Checklist
451
+
452
+ - [ ] Curve fits the requirement: P256 for the Secure Enclave or NIST interop,
453
+ Curve25519 for software, P384/P521 only when mandated.
454
+ - [ ] Correct `Signing` versus `KeyAgreement` family.
455
+ - [ ] Every `SharedSecret` goes through
456
+ `hkdfDerivedSymmetricKey(using:salt:sharedInfo:outputByteCount:)`.
457
+ - [ ] HPKE `encapsulatedKey` is transmitted.
458
+ - [ ] Both HPKE context structs are mutable variables.
459
+ - [ ] The receiver opens HPKE messages in the order the sender produced them.
460
+ - [ ] PEM or DER encoding appears only with P256, P384 and P521 keys.
461
+ - [ ] No RSA except legacy interop through `SecKey`.
462
+ - [ ] Post-quantum code behind `#available(iOS 26, *)`; HPKE behind iOS 17.
463
+ - [ ] Secure Enclave signing keys include `.privateKeyUsage`.
464
+ - [ ] Secure Enclave key lifecycle covers moving to a new device.
465
+ - [ ] Hybrid plan: X-Wing suite for encryption to a recipient, and every signature
466
+ produced twice, once with ML-DSA and once with ECDSA.
467
+ - [ ] Peer public keys in the Keychain, AfterFirstUnlockThisDeviceOnly, distinct tags.