@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1

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 (284) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +285 -285
  5. package/package.json +3 -3
  6. package/pipeline/lib/redact.mjs +3 -2
  7. package/pipeline/scripts/_notices.mjs +1 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +13 -1
  9. package/pipeline/scripts/pre-commit-check.sh +4 -0
  10. package/pipeline/skills/.skill-manifest.json +69 -69
  11. package/pipeline/skills/shared/README.md +70 -70
  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/app-clips/SKILL.md +260 -160
  16. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  17. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  18. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  19. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  20. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  21. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  22. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  23. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
  24. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  25. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
  26. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
  27. package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
  28. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  29. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  30. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  31. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
  32. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  34. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  35. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  37. package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
  38. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  39. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
  40. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  41. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  42. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  43. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  44. package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
  45. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  46. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
  47. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  48. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  49. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  50. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  51. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  52. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  53. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  54. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  55. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  56. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
  57. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  58. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  59. package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
  60. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  61. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  62. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  63. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  64. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  65. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  66. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  67. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  68. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  69. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  70. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  71. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  72. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  73. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  74. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  75. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  76. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  77. package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
  78. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  79. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  80. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  81. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  82. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  83. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  84. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  85. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  86. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  87. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  88. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  89. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  90. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  91. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  92. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  93. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  94. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  95. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  96. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  97. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  98. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  99. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  100. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  101. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  102. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  103. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  104. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  105. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  106. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  107. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  108. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  109. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  111. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  112. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  113. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  114. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
  115. package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
  116. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
  117. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
  118. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
  119. package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
  120. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
  121. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
  122. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
  123. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
  124. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
  125. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
  126. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
  127. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
  128. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
  129. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
  130. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
  131. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  132. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  133. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  134. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  135. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  136. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  137. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  138. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  139. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  140. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  141. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  142. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  143. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  144. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  145. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  146. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  147. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  148. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  149. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  150. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  151. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  152. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  153. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  154. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  155. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  156. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  157. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  158. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  159. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  160. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  161. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  162. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  163. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  164. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  165. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  166. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  167. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  168. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  169. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  170. package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
  171. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  172. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  173. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  174. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  175. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  176. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  177. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
  178. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  179. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  180. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  181. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  182. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  183. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  184. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  185. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  186. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  187. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  188. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  189. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  191. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
  193. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  194. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  195. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  196. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  197. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  198. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  199. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  200. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  201. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  202. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  203. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  204. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  205. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  206. package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
  207. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  208. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  209. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
  210. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  211. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  212. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  213. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  214. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  215. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  216. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
  217. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  218. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  219. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  220. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
  221. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  222. package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
  223. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  224. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
  225. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  226. package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
  227. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  228. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  229. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  230. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  231. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  232. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  233. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  234. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  235. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  236. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  237. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  238. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  239. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  240. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  241. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  242. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  243. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  244. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  245. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  246. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  247. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  248. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  249. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  250. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  251. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
  252. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  253. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
  254. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  255. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
  256. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  257. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  258. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  259. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  260. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  261. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  262. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  263. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  264. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  265. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  266. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  267. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  268. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  269. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  270. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  271. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  272. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  273. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  274. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  275. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  276. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  277. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  278. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  279. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  280. package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
  281. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  282. package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
  283. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
  284. 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`.