@mmerterden/multi-agent-pipeline 20.7.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 (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,602 +1,413 @@
1
- # CryptoKit Extended Patterns
1
+ # CryptoKit patterns
2
2
 
3
- Advanced patterns, key serialization, Keychain integration, legacy
4
- interop, and additional CryptoKit features beyond the core SKILL.md.
3
+ Detail that sits behind the main skill: how keys are serialized and stored,
4
+ less common primitives, sizes, compliance and migration.
5
5
 
6
6
  ## Contents
7
7
 
8
- - [Key Serialization](#key-serialization)
9
- - [Keychain Storage](#keychain-storage)
10
- - [AES Key Wrapping](#aes-key-wrapping)
11
- - [HKDF Key Derivation](#hkdf-key-derivation)
12
- - [HPKE (Hybrid Public Key Encryption)](#hpke-hybrid-public-key-encryption)
13
- - [Post-Quantum APIs](#post-quantum-apis)
14
- - [Insecure Module](#insecure-module)
15
- - [SealedBox Anatomy](#sealedbox-anatomy)
16
- - [Signing with Digest](#signing-with-digest)
17
- - [Encryption Export Compliance](#encryption-export-compliance)
18
- - [Performance Considerations](#performance-considerations)
19
- - [CommonCrypto Migration](#commoncrypto-migration)
20
-
21
- ## Key Serialization
22
-
23
- NIST curve keys (P256, P384, P521) support multiple serialization formats.
24
- Curve25519 keys use raw representation only.
25
-
26
- ### NIST key export and import
27
-
28
- ```swift
29
- let privateKey = P256.Signing.PrivateKey()
30
-
31
- // DER (binary, compact)
32
- let der = privateKey.derRepresentation
33
- let fromDER = try P256.Signing.PrivateKey(derRepresentation: der)
34
-
35
- // PEM (text, base64-encoded DER with header/footer)
36
- let pem = privateKey.pemRepresentation
37
- let fromPEM = try P256.Signing.PrivateKey(pemRepresentation: pem)
38
-
39
- // X9.63 (used by SecKey / Keychain interop)
40
- let x963 = privateKey.x963Representation
41
- let fromX963 = try P256.Signing.PrivateKey(x963Representation: x963)
42
-
43
- // Raw (scalar bytes only)
44
- let raw = privateKey.rawRepresentation
45
- let fromRaw = try P256.Signing.PrivateKey(rawRepresentation: raw)
46
- ```
47
-
48
- ### Public key serialization
49
-
50
- Public keys support the same formats plus compact and compressed
51
- representations:
8
+ - [Key serialization](#key-serialization)
9
+ - [Keychain storage](#keychain-storage)
10
+ - [AES key wrap](#aes-key-wrap)
11
+ - [HKDF on its own](#hkdf-on-its-own)
12
+ - [HPKE details](#hpke-details)
13
+ - [Post-quantum usage](#post-quantum-usage)
14
+ - [The Insecure namespace](#the-insecure-namespace)
15
+ - [Sealed box layout](#sealed-box-layout)
16
+ - [Signing a digest](#signing-a-digest)
17
+ - [Export compliance](#export-compliance)
18
+ - [Performance](#performance)
19
+ - [Moving from CommonCrypto](#moving-from-commoncrypto)
20
+
21
+ ## Key serialization
22
+
23
+ | Key | Property / initializer | Use |
24
+ |---|---|---|
25
+ | NIST private (P256/P384/P521) | `derRepresentation` / `init(derRepresentation:)` | exchange with non-Apple systems |
26
+ | | `pemRepresentation` / `init(pemRepresentation:)` | text formats, config files |
27
+ | | `x963Representation` / `init(x963Representation:)` | `SecKey` and Keychain interop |
28
+ | | `rawRepresentation` / `init(rawRepresentation:)` | the private scalar only |
29
+ | NIST public | all of the above, plus `compactRepresentation` (optional, can be `nil`) and `compressedRepresentation` | |
30
+ | Curve25519 private and public | `rawRepresentation` / `init(rawRepresentation:)` only | |
31
+ | ECDSA signature | `derRepresentation` (interop), `rawRepresentation` (r followed by s) | |
52
32
 
53
33
  ```swift
54
- let publicKey = privateKey.publicKey
55
-
56
- let der = publicKey.derRepresentation
57
- let pem = publicKey.pemRepresentation
58
- let x963 = publicKey.x963Representation
59
- let raw = publicKey.rawRepresentation
60
- let compact = publicKey.compactRepresentation // Optional; may be nil
61
- let compressed = publicKey.compressedRepresentation
34
+ import CryptoKit
35
+ import Foundation
36
+
37
+ func roundTrip() throws {
38
+ let issuer = P384.Signing.PrivateKey()
39
+ let asPEM = issuer.publicKey.pemRepresentation
40
+ let reloaded = try P384.Signing.PublicKey(pemRepresentation: asPEM)
41
+
42
+ let sig = try issuer.signature(for: Data("ticket-42".utf8))
43
+ let wire = sig.derRepresentation
44
+ let back = try P384.Signing.ECDSASignature(derRepresentation: wire)
45
+ let compact = try P384.Signing.ECDSASignature(rawRepresentation: sig.rawRepresentation)
46
+ _ = (reloaded.isValidSignature(back, for: Data("ticket-42".utf8)), compact)
47
+ }
62
48
  ```
63
49
 
64
- ### Curve25519 key serialization
65
-
66
- ```swift
67
- let key = Curve25519.Signing.PrivateKey()
50
+ Rule: DER when the other end is not CryptoKit; raw when both ends are CryptoKit
51
+ and size matters.
68
52
 
69
- // Only raw representation available
70
- let raw = key.rawRepresentation
71
- let restored = try Curve25519.Signing.PrivateKey(rawRepresentation: raw)
53
+ ## Keychain storage
72
54
 
73
- let pubRaw = key.publicKey.rawRepresentation
74
- let restoredPub = try Curve25519.Signing.PublicKey(rawRepresentation: pubRaw)
75
- ```
55
+ Two strategies, chosen by whether the key has an X9.63 form that `SecKey`
56
+ understands.
76
57
 
77
- ### ECDSA signature serialization
58
+ ### NIST keys as SecKey items
78
59
 
79
60
  ```swift
80
- let signature = try privateKey.signature(for: data)
81
-
82
- // DER-encoded (standard interop format)
83
- let derSig = signature.derRepresentation
84
-
85
- // Raw (r || s concatenation)
86
- let rawSig = signature.rawRepresentation
87
-
88
- // Restore
89
- let fromDER = try P256.Signing.ECDSASignature(derRepresentation: derSig)
90
- let fromRaw = try P256.Signing.ECDSASignature(rawRepresentation: rawSig)
91
- ```
92
-
93
- Use DER for interoperability with non-Apple systems. Use raw for compact
94
- storage where both sides are CryptoKit.
95
-
96
- ## Keychain Storage
97
-
98
- CryptoKit key types divide into two storage strategies based on whether
99
- they have a SecKey-compatible representation.
100
-
101
- ### NIST keys via SecKey
102
-
103
- P256, P384, and P521 private keys can be stored as native Keychain
104
- elliptic-curve keys using their X9.63 representation.
61
+ import CryptoKit
62
+ import Foundation
63
+ import Security
105
64
 
106
- ```swift
107
- protocol SecKeyConvertible: CustomStringConvertible {
108
- init<Bytes>(x963Representation: Bytes) throws where Bytes: ContiguousBytes
65
+ protocol SecKeyStorable {
66
+ init<Bytes: ContiguousBytes>(x963Representation: Bytes) throws
109
67
  var x963Representation: Data { get }
110
68
  }
111
69
 
112
- extension P256.Signing.PrivateKey: SecKeyConvertible {}
113
- extension P256.KeyAgreement.PrivateKey: SecKeyConvertible {}
114
- extension P384.Signing.PrivateKey: SecKeyConvertible {}
115
- extension P384.KeyAgreement.PrivateKey: SecKeyConvertible {}
116
- extension P521.Signing.PrivateKey: SecKeyConvertible {}
117
- extension P521.KeyAgreement.PrivateKey: SecKeyConvertible {}
118
- ```
119
-
120
- Store:
70
+ extension P256.Signing.PrivateKey: SecKeyStorable {}
71
+ extension P256.KeyAgreement.PrivateKey: SecKeyStorable {}
72
+ extension P384.Signing.PrivateKey: SecKeyStorable {}
73
+ extension P384.KeyAgreement.PrivateKey: SecKeyStorable {}
74
+ extension P521.Signing.PrivateKey: SecKeyStorable {}
75
+ extension P521.KeyAgreement.PrivateKey: SecKeyStorable {}
121
76
 
122
- ```swift
123
- func storeKey<T: SecKeyConvertible>(_ key: T, label: String) throws {
124
- let attributes: [String: Any] = [
125
- kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
126
- kSecAttrKeyClass as String: kSecAttrKeyClassPrivate
127
- ]
128
-
129
- guard let secKey = SecKeyCreateWithData(
130
- key.x963Representation as CFData,
131
- attributes as CFDictionary,
132
- nil
133
- ) else {
134
- throw KeyStoreError.unableToCreateSecKey
135
- }
77
+ enum VaultError: Error {
78
+ case conversion(String)
79
+ case status(OSStatus)
80
+ }
136
81
 
137
- let query: [String: Any] = [
138
- kSecClass as String: kSecClassKey,
139
- kSecAttrApplicationLabel as String: label,
140
- kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
141
- kSecUseDataProtectionKeychain as String: true,
142
- kSecValueRef as String: secKey
143
- ]
144
-
145
- let status = SecItemAdd(query as CFDictionary, nil)
146
- guard status == errSecSuccess else {
147
- throw KeyStoreError.saveFailed(status)
82
+ func storeECKey<K: SecKeyStorable>(_ key: K, label: String) throws {
83
+ let attributes = [
84
+ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
85
+ kSecAttrKeyClass: kSecAttrKeyClassPrivate
86
+ ] as [String: Any]
87
+ var cfError: Unmanaged<CFError>?
88
+ guard let keyRef = SecKeyCreateWithData(key.x963Representation as CFData, attributes as CFDictionary, &cfError) else {
89
+ throw VaultError.conversion(cfError.map { String(describing: $0.takeRetainedValue()) } ?? "unknown")
148
90
  }
91
+ let item = [
92
+ kSecClass: kSecClassKey,
93
+ kSecAttrApplicationLabel: label,
94
+ kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
95
+ kSecUseDataProtectionKeychain: true,
96
+ kSecValueRef: keyRef
97
+ ] as [String: Any]
98
+ let status = SecItemAdd(item as CFDictionary, nil)
99
+ guard status == errSecSuccess else { throw VaultError.status(status) }
149
100
  }
150
- ```
151
101
 
152
- Retrieve:
153
-
154
- ```swift
155
- func readKey<T: SecKeyConvertible>(label: String) throws -> T? {
156
- let query: [String: Any] = [
157
- kSecClass as String: kSecClassKey,
158
- kSecAttrApplicationLabel as String: label,
159
- kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
160
- kSecUseDataProtectionKeychain as String: true,
161
- kSecReturnRef as String: true
162
- ]
163
-
164
- var item: CFTypeRef?
165
- switch SecItemCopyMatching(query as CFDictionary, &item) {
102
+ func loadECKey<K: SecKeyStorable>(label: String) throws -> K? {
103
+ let lookup = [
104
+ kSecClass: kSecClassKey,
105
+ kSecAttrApplicationLabel: label,
106
+ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
107
+ kSecUseDataProtectionKeychain: true,
108
+ kSecReturnRef: true
109
+ ] as [String: Any]
110
+ var found: CFTypeRef?
111
+ switch SecItemCopyMatching(lookup as CFDictionary, &found) {
166
112
  case errSecSuccess:
167
- let secKey = item as! SecKey
168
- var error: Unmanaged<CFError>?
169
- guard let data = SecKeyCopyExternalRepresentation(secKey, &error) as Data? else {
170
- throw KeyStoreError.exportFailed
113
+ guard let ref = found, CFGetTypeID(ref) == SecKeyGetTypeID() else { return nil }
114
+ var failure: Unmanaged<CFError>?
115
+ guard let bytes = SecKeyCopyExternalRepresentation(ref as! SecKey, &failure) as Data? else {
116
+ throw VaultError.conversion("export failed")
171
117
  }
172
- return try T(x963Representation: data)
118
+ return try K(x963Representation: bytes)
173
119
  case errSecItemNotFound:
174
120
  return nil
175
- case let status:
176
- throw KeyStoreError.readFailed(status)
121
+ case let other:
122
+ throw VaultError.status(other)
177
123
  }
178
124
  }
179
125
  ```
180
126
 
181
- ### Non-NIST keys via generic password
127
+ The P256, P384 and P521 signing and key-agreement private keys all have the
128
+ X9.63 initializer and property, so they conform to the helper protocol with an
129
+ empty extension. Reading asks for `kSecReturnRef`, exports the `SecKey` with
130
+ `SecKeyCopyExternalRepresentation` and rebuilds the CryptoKit key; a missing
131
+ item returns `nil` and every other status throws.
182
132
 
183
- Curve25519 keys and SymmetricKey lack X9.63 representations. Store them
184
- as generic password Keychain items using their raw data.
133
+ ### Everything else as generic passwords
185
134
 
186
- ```swift
187
- protocol GenericPasswordConvertible: CustomStringConvertible {
188
- init<D>(genericKeyRepresentation data: D) throws where D: ContiguousBytes
189
- var genericKeyRepresentation: SymmetricKey { get }
190
- }
135
+ Curve25519 keys and `SymmetricKey` have no X9.63 form. Store their raw bytes as
136
+ `kSecClassGenericPassword` items.
191
137
 
192
- extension Curve25519.Signing.PrivateKey: GenericPasswordConvertible {
193
- init<D>(genericKeyRepresentation data: D) throws where D: ContiguousBytes {
194
- try self.init(rawRepresentation: data)
195
- }
138
+ ```swift
139
+ import CryptoKit
140
+ import Foundation
141
+ import Security
196
142
 
197
- var genericKeyRepresentation: SymmetricKey {
198
- rawRepresentation.withUnsafeBytes { SymmetricKey(data: $0) }
199
- }
143
+ protocol RawKeyStorable {
144
+ init<Bytes: ContiguousBytes>(rawKeyBytes: Bytes) throws
145
+ var rawKeyBytes: SymmetricKey { get }
200
146
  }
201
147
 
202
- extension Curve25519.KeyAgreement.PrivateKey: GenericPasswordConvertible {
203
- init<D>(genericKeyRepresentation data: D) throws where D: ContiguousBytes {
204
- try self.init(rawRepresentation: data)
205
- }
206
-
207
- var genericKeyRepresentation: SymmetricKey {
208
- rawRepresentation.withUnsafeBytes { SymmetricKey(data: $0) }
209
- }
148
+ extension Curve25519.Signing.PrivateKey: RawKeyStorable {
149
+ init<Bytes: ContiguousBytes>(rawKeyBytes: Bytes) throws { try self.init(rawRepresentation: rawKeyBytes) }
150
+ var rawKeyBytes: SymmetricKey { SymmetricKey(data: rawRepresentation) }
210
151
  }
211
152
 
212
- extension SymmetricKey: GenericPasswordConvertible {
213
- init<D>(genericKeyRepresentation data: D) throws where D: ContiguousBytes {
214
- self.init(data: data)
215
- }
216
-
217
- var genericKeyRepresentation: SymmetricKey { self }
153
+ extension Curve25519.KeyAgreement.PrivateKey: RawKeyStorable {
154
+ init<Bytes: ContiguousBytes>(rawKeyBytes: Bytes) throws { try self.init(rawRepresentation: rawKeyBytes) }
155
+ var rawKeyBytes: SymmetricKey { SymmetricKey(data: rawRepresentation) }
218
156
  }
219
- ```
220
157
 
221
- Store:
222
-
223
- ```swift
224
- func storeKey<T: GenericPasswordConvertible>(
225
- _ key: T, account: String
226
- ) throws {
227
- try key.genericKeyRepresentation.withUnsafeBytes { keyBytes in
228
- let query: [String: Any] = [
229
- kSecClass as String: kSecClassGenericPassword,
230
- kSecAttrAccount as String: account,
231
- kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
232
- kSecUseDataProtectionKeychain as String: true,
233
- kSecValueData as String: Data(keyBytes)
234
- ]
235
-
236
- let status = SecItemAdd(query as CFDictionary, nil)
237
- guard status == errSecSuccess else {
238
- throw KeyStoreError.saveFailed(status)
239
- }
240
- }
158
+ extension SymmetricKey: RawKeyStorable {
159
+ init<Bytes: ContiguousBytes>(rawKeyBytes: Bytes) throws { self.init(data: rawKeyBytes) }
160
+ var rawKeyBytes: SymmetricKey { self }
241
161
  }
242
- ```
243
-
244
- ### Secure Enclave keys in Keychain
245
-
246
- Secure Enclave keys export an encrypted `dataRepresentation` that only
247
- the same device's Secure Enclave can restore. Store this blob as a generic
248
- password:
249
162
 
250
- ```swift
251
- extension SecureEnclave.P256.Signing.PrivateKey: GenericPasswordConvertible {
252
- init<D>(genericKeyRepresentation data: D) throws where D: ContiguousBytes {
253
- try self.init(dataRepresentation: data.withUnsafeBytes { Data($0) })
254
- }
255
-
256
- var genericKeyRepresentation: SymmetricKey {
257
- SymmetricKey(data: dataRepresentation)
258
- }
163
+ func storeRawKey<K: RawKeyStorable>(_ key: K, account: String) throws {
164
+ let bytes = key.rawKeyBytes.withUnsafeBytes { Data($0) }
165
+ let item = [
166
+ kSecClass: kSecClassGenericPassword,
167
+ kSecAttrAccount: account,
168
+ kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
169
+ kSecUseDataProtectionKeychain: true,
170
+ kSecValueData: bytes
171
+ ] as [String: Any]
172
+ let status = SecItemAdd(item as CFDictionary, nil)
173
+ if status != errSecSuccess { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status)) }
259
174
  }
260
175
  ```
261
176
 
262
- ## AES Key Wrapping
177
+ Secure Enclave keys follow the same generic-password route: store the encrypted
178
+ `dataRepresentation` as the password data and rebuild the key with
179
+ `init(dataRepresentation:)` after reading it back.
263
180
 
264
- CryptoKit supports AES Key Wrap (RFC 3394) for securely wrapping one
265
- symmetric key with another.
266
-
267
- ```swift
268
- let kek = SymmetricKey(size: .bits256) // Key Encryption Key
269
- let dek = SymmetricKey(size: .bits256) // Data Encryption Key
181
+ ## AES key wrap
270
182
 
271
- // Wrap
272
- let wrappedData = try AES.KeyWrap.wrap(dek, using: kek)
273
-
274
- // Unwrap
275
- let unwrapped = try AES.KeyWrap.unwrap(wrappedData, using: kek)
276
- ```
277
-
278
- Use key wrapping when transmitting or storing keys encrypted under
279
- a master key.
280
-
281
- ## HKDF Key Derivation
282
-
283
- HKDF (RFC 5869) derives cryptographic keys from input key material.
284
- Available as a standalone operation outside of `SharedSecret`.
183
+ RFC 3394 key wrapping encrypts one key (the data key) under another (the key
184
+ encryption key). Use it to store or send keys protected by a master key.
285
185
 
286
186
  ```swift
287
- let inputKey = SymmetricKey(size: .bits256)
288
-
289
- // Derive with salt and info
290
- let derived = HKDF<SHA256>.deriveKey(
291
- inputKeyMaterial: inputKey,
292
- salt: Data("salt".utf8),
293
- info: Data("my-app-encryption-v1".utf8),
294
- outputByteCount: 32
295
- )
296
- ```
297
-
298
- ### Extract-then-expand (two-step)
187
+ import CryptoKit
188
+ import Foundation
299
189
 
300
- For protocols that need explicit control:
190
+ func wrapFileKey(_ fileKey: SymmetricKey, under master: SymmetricKey) throws -> Data {
191
+ try AES.KeyWrap.wrap(fileKey, using: master)
192
+ }
301
193
 
302
- ```swift
303
- // Extract: produce a pseudorandom key
304
- let prk = HKDF<SHA256>.extract(
305
- inputKeyMaterial: inputKey,
306
- salt: Data("salt".utf8)
307
- )
308
-
309
- // Expand: derive output key material
310
- let okm = HKDF<SHA256>.expand(
311
- pseudoRandomKey: prk,
312
- info: Data("context".utf8),
313
- outputByteCount: 32
314
- )
194
+ func unwrapFileKey(_ wrapped: Data, under master: SymmetricKey) throws -> SymmetricKey {
195
+ try AES.KeyWrap.unwrap(wrapped, using: master)
196
+ }
315
197
  ```
316
198
 
317
- ## HPKE (Hybrid Public Key Encryption)
318
-
319
- HPKE (RFC 9180) combines key encapsulation with authenticated encryption
320
- for public-key encryption workflows. It is available on iOS 17+; the X-Wing
321
- post-quantum hybrid ciphersuite requires iOS 26+.
322
-
323
- ### Sending an encrypted message
324
-
325
- ```swift
326
- let recipientKey = P256.KeyAgreement.PrivateKey()
327
-
328
- var sender = try HPKE.Sender(
329
- recipientKey: recipientKey.publicKey,
330
- ciphersuite: .P256_SHA256_AES_GCM_256,
331
- info: Data("my-protocol-v1".utf8)
332
- )
333
-
334
- let ciphertext = try sender.seal(Data("secret message".utf8))
335
- let encapsulatedKey = sender.encapsulatedKey
336
- // Send ciphertext + encapsulatedKey to recipient
337
- ```
199
+ ## HKDF on its own
338
200
 
339
- ### Receiving
201
+ HKDF (RFC 5869) is also available directly, for key material that did not come
202
+ from ECDH.
340
203
 
341
204
  ```swift
342
- var recipient = try HPKE.Recipient(
343
- privateKey: recipientKey,
344
- ciphersuite: .P256_SHA256_AES_GCM_256,
345
- info: Data("my-protocol-v1".utf8),
346
- encapsulatedKey: encapsulatedKey
347
- )
348
-
349
- let plaintext = try recipient.open(ciphertext)
205
+ import CryptoKit
206
+ import Foundation
207
+
208
+ func deriveSubkeys(from material: SymmetricKey) -> (SymmetricKey, SymmetricKey) {
209
+ let direct = HKDF<SHA256>.deriveKey(
210
+ inputKeyMaterial: material,
211
+ salt: Data("vault-salt".utf8),
212
+ info: Data("vault index key".utf8),
213
+ outputByteCount: 32
214
+ )
215
+ let pseudoKey = HKDF<SHA256>.extract(inputKeyMaterial: material, salt: Data("vault-salt".utf8))
216
+ let expanded = HKDF<SHA256>.expand(pseudoRandomKey: pseudoKey, info: Data("vault blob key".utf8), outputByteCount: 32)
217
+ return (direct, expanded)
218
+ }
350
219
  ```
351
220
 
352
- ### Available ciphersuites
353
-
354
- | Ciphersuite | KEM | KDF | AEAD | Availability |
355
- |---|---|---|---|---|
356
- | `.P256_SHA256_AES_GCM_256` | P256 | HKDF-SHA256 | AES-GCM-256 | iOS 17+ |
357
- | `.P384_SHA384_AES_GCM_256` | P384 | HKDF-SHA384 | AES-GCM-256 | iOS 17+ |
358
- | `.P521_SHA512_AES_GCM_256` | P521 | HKDF-SHA512 | AES-GCM-256 | iOS 17+ |
359
- | `.Curve25519_SHA256_ChachaPoly` | X25519 | HKDF-SHA256 | ChaCha20Poly1305 | iOS 17+ |
360
- | `.XWingMLKEM768X25519_SHA256_AES_GCM_256` | X-Wing hybrid | HKDF-SHA256 | AES-GCM-256 | iOS 26+ |
221
+ `deriveKey` does both steps at once; `extract` then `expand` gives the
222
+ pseudorandom key in between.
361
223
 
362
- ## Post-Quantum APIs
224
+ ## HPKE details
363
225
 
364
- iOS 26+ adds ML-KEM key encapsulation, ML-DSA signatures, and the X-Wing
365
- hybrid HPKE KEM. Guard these APIs with availability checks unless the
366
- deployment target is iOS 26+.
367
-
368
- ### ML-KEM encapsulation
226
+ HPKE is RFC 9180. It is available from iOS 17; the X-Wing hybrid suite needs
227
+ iOS 26.
369
228
 
370
229
  ```swift
371
- if #available(iOS 26.0, *) {
372
- let privateKey = try MLKEM768.PrivateKey()
373
- let result = try privateKey.publicKey.encapsulate()
230
+ import CryptoKit
231
+ import Foundation
374
232
 
375
- let sharedKey = result.sharedSecret
376
- let encapsulated = result.encapsulated
377
- let recovered = try privateKey.decapsulate(encapsulated)
233
+ func sendToServer(_ report: Data, serverKey: P256.KeyAgreement.PublicKey) throws -> (ciphertext: Data, encapsulated: Data) {
234
+ var hpkeSender = try HPKE.Sender(recipientKey: serverKey, ciphersuite: .P256_SHA256_AES_GCM_256,
235
+ info: Data("crash-report v1".utf8))
236
+ return (try hpkeSender.seal(report), hpkeSender.encapsulatedKey)
378
237
  }
379
- ```
380
-
381
- `encapsulated` is what the sender transmits. `sharedSecret` and the decapsulated
382
- result are `SymmetricKey` values.
383
238
 
384
- ### ML-DSA signatures
385
-
386
- ```swift
387
- if #available(iOS 26.0, *) {
388
- let privateKey = try MLDSA65.PrivateKey()
389
- let signature = try privateKey.signature(for: message)
390
- let isValid = privateKey.publicKey.isValidSignature(signature, for: message)
239
+ func receiveOnServer(_ ciphertext: Data, encapsulated: Data, key: P256.KeyAgreement.PrivateKey) throws -> Data {
240
+ var hpkeRecipient = try HPKE.Recipient(privateKey: key, ciphersuite: .P256_SHA256_AES_GCM_256,
241
+ info: Data("crash-report v1".utf8), encapsulatedKey: encapsulated)
242
+ return try hpkeRecipient.open(ciphertext)
391
243
  }
392
244
  ```
393
245
 
394
- Secure Enclave variants exist for `SecureEnclave.MLKEM768`,
395
- `SecureEnclave.MLKEM1024`, `SecureEnclave.MLDSA65`, and
396
- `SecureEnclave.MLDSA87` on supported hardware.
397
-
398
- Sources: [CryptoKit](https://sosumi.ai/documentation/cryptokit),
399
- [HPKE](https://sosumi.ai/documentation/cryptokit/hpke), and
400
- [quantum-secure workflows](https://sosumi.ai/documentation/cryptokit/enhancing-your-app-s-privacy-and-security-with-quantum-secure-workflows).
246
+ | Ciphersuite | Minimum iOS | Key encapsulation | Key derivation | Authenticated cipher |
247
+ |---|---|---|---|---|
248
+ | `.P256_SHA256_AES_GCM_256` | 17 | NIST P-256 | SHA-256 HKDF | 256-bit AES-GCM |
249
+ | `.P384_SHA384_AES_GCM_256` | 17 | NIST P-384 | SHA-384 HKDF | 256-bit AES-GCM |
250
+ | `.P521_SHA512_AES_GCM_256` | 17 | NIST P-521 | SHA-512 HKDF | 256-bit AES-GCM |
251
+ | `.Curve25519_SHA256_ChachaPoly` | 17 | X25519 | SHA-256 HKDF | ChaCha20-Poly1305 |
252
+ | `.XWingMLKEM768X25519_SHA256_AES_GCM_256` | 26 | X-Wing hybrid (ML-KEM-768 with X25519) | SHA-256 HKDF | 256-bit AES-GCM |
401
253
 
402
- ## Insecure Module
254
+ ## Post-quantum usage
403
255
 
404
- The `Insecure` enum provides MD5 and SHA1 for legacy compatibility ONLY.
256
+ Guard ML-KEM, ML-DSA and X-Wing with an iOS 26 availability check unless the
257
+ deployment target is 26 or later.
405
258
 
406
259
  ```swift
407
260
  import CryptoKit
261
+ import Foundation
262
+
263
+ @available(iOS 26.0, *)
264
+ func kemHandshake() throws -> Bool {
265
+ let receiverKey = try MLKEM768.PrivateKey()
266
+ let result = try receiverKey.publicKey.encapsulate()
267
+ let transmitted = result.encapsulated
268
+ let recovered = try receiverKey.decapsulate(transmitted)
269
+ return recovered == result.sharedSecret
270
+ }
408
271
 
409
- // Legacy checksum verification
410
- let md5 = Insecure.MD5.hash(data: fileData)
411
- let sha1 = Insecure.SHA1.hash(data: fileData)
272
+ @available(iOS 26.0, *)
273
+ func quantumSafeSignature(_ firmware: Data) throws -> Bool {
274
+ let signer = try MLDSA65.PrivateKey()
275
+ let sig = try signer.signature(for: firmware)
276
+ return signer.publicKey.isValidSignature(sig, for: firmware)
277
+ }
412
278
  ```
413
279
 
414
- Valid uses:
415
- - Verifying checksums from legacy systems
416
- - Computing ETags or content hashes for caching
417
- - Protocol interop requiring MD5/SHA1
418
-
419
- Invalid uses:
420
- - Password hashing
421
- - Data integrity for security
422
- - Digital signatures
423
- - HMAC for authentication
280
+ - The sender runs `encapsulate()` on the receiver's public key and transmits
281
+ `encapsulated`. The receiver calls `decapsulate(_:)`.
282
+ - Both the sender's `sharedSecret` and the receiver's decapsulated value are a
283
+ `SymmetricKey`, and they are equal.
284
+ - The Secure Enclave variants listed in the main skill exist on supported
285
+ hardware.
424
286
 
425
- The `Insecure` namespace makes insecure usage explicit at the call site.
287
+ ## The Insecure namespace
426
288
 
427
- ## SealedBox Anatomy
289
+ `Insecure.MD5` and `Insecure.SHA1` live in the `Insecure` enum so that every
290
+ use is visibly flagged at the call site.
428
291
 
429
- Both AES-GCM and ChaChaPoly produce a sealed box with three components:
430
-
431
- | Component | AES-GCM | ChaChaPoly |
432
- |---|---|---|
433
- | Nonce | 12 bytes | 12 bytes |
434
- | Ciphertext | Same length as plaintext | Same length as plaintext |
435
- | Tag | 16 bytes | 16 bytes |
436
-
437
- ### Combined representation
292
+ | Fine | Never |
293
+ |---|---|
294
+ | verifying a legacy checksum | hashing passwords |
295
+ | cache keys, ETags, content hashes | integrity that security depends on |
296
+ | a protocol that requires MD5 or SHA-1 | digital signatures |
297
+ | | HMAC authentication |
438
298
 
439
299
  ```swift
440
- let sealedBox = try AES.GCM.seal(plaintext, using: key)
441
-
442
- // Combined: nonce (12) + ciphertext (N) + tag (16)
443
- let combined = sealedBox.combined // Optional for AES-GCM, non-optional for ChaChaPoly
444
-
445
- // Individual components
446
- let nonce = sealedBox.nonce
447
- let ciphertext = sealedBox.ciphertext
448
- let tag = sealedBox.tag
449
- ```
450
-
451
- ### Reconstructing from components
452
-
453
- When receiving nonce, ciphertext, and tag separately:
300
+ import CryptoKit
301
+ import Foundation
454
302
 
455
- ```swift
456
- let box = try AES.GCM.SealedBox(
457
- nonce: AES.GCM.Nonce(data: nonceData),
458
- ciphertext: ciphertextData,
459
- tag: tagData
460
- )
461
- let plaintext = try AES.GCM.open(box, using: key)
303
+ func legacyETag(for body: Data) -> String {
304
+ Insecure.MD5.hash(data: body).reduce(into: "") { $0 += String(format: "%02x", $1) }
305
+ }
462
306
  ```
463
307
 
464
- ### Reconstructing from combined
308
+ ## Sealed box layout
465
309
 
466
- ```swift
467
- let box = try AES.GCM.SealedBox(combined: combinedData)
468
- let plaintext = try AES.GCM.open(box, using: key)
469
- ```
310
+ For both AES-GCM and ChaChaPoly:
470
311
 
471
- ## Signing with Digest
312
+ | Part | Size |
313
+ |---|---|
314
+ | nonce | 12 bytes |
315
+ | ciphertext | same length as the plaintext |
316
+ | tag | 16 bytes |
472
317
 
473
- For P256/P384/P521, sign a pre-computed digest instead of raw data:
318
+ `combined` is nonce, then ciphertext, then tag. The parts are also exposed as
319
+ `.nonce`, `.ciphertext` and `.tag`.
474
320
 
475
321
  ```swift
476
- let digest = SHA256.hash(data: data)
477
- let signature = try privateKey.signature(for: digest)
478
- let isValid = publicKey.isValidSignature(signature, for: digest)
479
- ```
480
-
481
- This avoids hashing the data twice when the digest is already available.
482
-
483
- ## Encryption Export Compliance
484
-
485
- Apps that use encryption must declare compliance in App Store Connect.
486
-
487
- ### ITSAppUsesNonExemptEncryption
488
-
489
- Set in Info.plist:
322
+ import CryptoKit
323
+ import Foundation
490
324
 
491
- ```xml
492
- <key>ITSAppUsesNonExemptEncryption</key>
493
- <false/>
325
+ func reassemble(nonce: Data, body: Data, tag: Data, key: SymmetricKey) throws -> Data {
326
+ let sealed = try AES.GCM.SealedBox(nonce: AES.GCM.Nonce(data: nonce), ciphertext: body, tag: tag)
327
+ return try AES.GCM.open(sealed, using: key)
328
+ }
494
329
  ```
495
330
 
496
- Set to `false` if the app uses ONLY:
497
- - Apple-provided encryption (HTTPS via URLSession, CryptoKit for
498
- data protection on-device only)
499
- - Standard authentication (OAuth, SAML, biometrics)
500
-
501
- Set to `true` if the app:
502
- - Implements custom encryption protocols
503
- - Communicates with non-standard encrypted services
504
- - Encrypts data sent to third-party servers
505
-
506
- When `true`, an export compliance review or proper classification is
507
- required. See Apple's [Complying with Encryption Export Regulations](https://sosumi.ai/documentation/security/complying-with-encryption-export-regulations)
508
- documentation.
509
-
510
- ## Performance Considerations
511
-
512
- ### AES-GCM vs ChaChaPoly
513
-
514
- On Apple silicon devices, AES-GCM is hardware-accelerated and generally
515
- faster. ChaChaPoly performs better on devices without AES hardware
516
- acceleration (rare on modern Apple hardware). For most iOS apps, prefer
517
- AES-GCM.
331
+ When the parts arrive already concatenated, use `SealedBox(combined:)` instead.
518
332
 
519
- ### Hashing large data
333
+ ## Signing a digest
520
334
 
521
- Use incremental hashing for large files to avoid loading everything
522
- into memory:
335
+ The NIST curves can sign and verify a digest you already computed, which avoids
336
+ hashing the data twice.
523
337
 
524
338
  ```swift
525
- func hashFile(at url: URL) throws -> SHA256.Digest {
526
- let handle = try FileHandle(forReadingFrom: url)
527
- var hasher = SHA256()
528
-
529
- while autoreleasepool(invoking: {
530
- let chunk = handle.readData(ofLength: 1024 * 1024) // 1 MB
531
- guard !chunk.isEmpty else { return false }
532
- hasher.update(data: chunk)
533
- return true
534
- }) {}
339
+ import CryptoKit
340
+ import Foundation
535
341
 
536
- return hasher.finalize()
342
+ func signPrehashed(_ file: Data, key: P521.Signing.PrivateKey) throws -> Bool {
343
+ let digest = SHA512.hash(data: file)
344
+ let signature = try key.signature(for: digest)
345
+ return key.publicKey.isValidSignature(signature, for: digest)
537
346
  }
538
347
  ```
539
348
 
540
- ### Key generation costs
349
+ ## Export compliance
541
350
 
542
- | Operation | Relative Cost |
543
- |---|---|
544
- | `SymmetricKey(size:)` | Very fast (CSPRNG) |
545
- | `P256.Signing.PrivateKey()` | Fast |
546
- | `P384.Signing.PrivateKey()` | Moderate |
547
- | `P521.Signing.PrivateKey()` | Slower |
548
- | `SecureEnclave.P256.*.PrivateKey()` | Slowest (hardware round-trip) |
351
+ Apps that use encryption declare it in App Store Connect and set the Boolean
352
+ Info.plist key `ITSAppUsesNonExemptEncryption`.
549
353
 
550
- Generate keys once and store them. Do not regenerate per-operation.
354
+ - `false` when the app only uses encryption that Apple's platforms provide (HTTPS
355
+ through `URLSession`, CryptoKit protecting data on the device) plus standard
356
+ authentication such as OAuth, SAML or biometrics.
357
+ - `true` when it implements its own encryption protocol, offers a non-standard
358
+ encrypted service, or encrypts data it sends to third-party servers. In that
359
+ case the app needs an export classification (or a compliance review) first.
360
+ Apple's guide on this lives at
361
+ <https://developer.apple.com/documentation/security/complying-with-encryption-export-regulations>.
551
362
 
552
- ## CommonCrypto Migration
363
+ ## Performance
553
364
 
554
- ### Hashing
365
+ - AES-GCM runs in hardware on Apple silicon and is usually faster.
366
+ ChaChaPoly only wins where AES acceleration is missing, which is rare on
367
+ current Apple devices. Default to AES-GCM.
368
+ - Hash big files in pieces instead of loading them whole:
555
369
 
556
370
  ```swift
557
- // CommonCrypto (old)
558
- import CommonCrypto
559
- var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
560
- data.withUnsafeBytes { CC_SHA256($0.baseAddress, CC_LONG(data.count), &digest) }
561
-
562
- // CryptoKit (new)
563
371
  import CryptoKit
564
- let digest = SHA256.hash(data: data)
565
- ```
372
+ import Foundation
566
373
 
567
- ### HMAC
568
-
569
- ```swift
570
- // CommonCrypto (old)
571
- var hmac = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
572
- keyData.withUnsafeBytes { keyPtr in
573
- data.withUnsafeBytes { dataPtr in
574
- CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256),
575
- keyPtr.baseAddress, keyData.count,
576
- dataPtr.baseAddress, data.count,
577
- &hmac)
374
+ func sha256OfFile(_ fileURL: URL) throws -> SHA256.Digest {
375
+ let reader = try FileHandle(forReadingFrom: fileURL)
376
+ defer { try? reader.close() }
377
+ var hasher = SHA256()
378
+ var finished = false
379
+ while !finished {
380
+ try autoreleasepool {
381
+ if let piece = try reader.read(upToCount: 1 << 20), !piece.isEmpty {
382
+ hasher.update(data: piece)
383
+ } else {
384
+ finished = true
385
+ }
386
+ }
578
387
  }
388
+ return hasher.finalize()
579
389
  }
580
-
581
- // CryptoKit (new)
582
- let mac = HMAC<SHA256>.authenticationCode(for: data, using: key)
583
390
  ```
584
391
 
585
- ### AES encryption
392
+ - Relative cost of key generation, cheapest first: `SymmetricKey(size:)`
393
+ (straight from the system random generator), P256, P384, P521, and
394
+ `SecureEnclave.P256.*.PrivateKey()` (a trip to the hardware).
395
+ - Generate a key once and keep it; never create one per operation.
586
396
 
587
- ```swift
588
- // CommonCrypto (old) -- error-prone, manual IV/padding management
589
- // ~30 lines of CCCrypt with buffer allocation
590
-
591
- // CryptoKit (new) -- authenticated encryption in one call
592
- let sealedBox = try AES.GCM.seal(data, using: key)
593
- let decrypted = try AES.GCM.open(sealedBox, using: key)
594
- ```
397
+ ## Moving from CommonCrypto
595
398
 
596
- CryptoKit advantages over CommonCrypto:
597
- - Authenticated encryption by default (no unauthenticated CBC mode)
598
- - Type-safe keys and nonces
599
- - Automatic nonce generation
600
- - No manual buffer management
601
- - Constant-time comparisons built in
602
- - Sendable types for concurrency safety
399
+ | CommonCrypto | CryptoKit |
400
+ |---|---|
401
+ | `CC_SHA256` into a manually sized buffer | `SHA256.hash(data:)` |
402
+ | `CCHmac(kCCHmacAlgSHA256, ...)` | `HMAC<SHA256>.authenticationCode(for:using:)` |
403
+ | `CCCrypt` with AES, a hand-managed IV and padding (dozens of lines) | `AES.GCM.seal` / `AES.GCM.open` |
404
+
405
+ What changes for the better:
406
+
407
+ - Encryption is authenticated by default; there is no unauthenticated CBC mode
408
+ to reach for by accident.
409
+ - Keys and nonces have their own types.
410
+ - Nonces are generated for you.
411
+ - No manual buffer sizing or pointer handling.
412
+ - Comparisons of MACs and signatures are constant-time.
413
+ - The types are `Sendable`.