ox 1.2.0 → 1.3.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 (187) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/core/AbiFunction.d.ts +1 -1
  3. package/dist/core/AbiFunction.d.ts.map +1 -1
  4. package/dist/core/AbiFunction.js +6 -2
  5. package/dist/core/AbiFunction.js.map +1 -1
  6. package/dist/core/AbiParameters.d.ts +1 -1
  7. package/dist/core/AbiParameters.d.ts.map +1 -1
  8. package/dist/core/AbiParameters.js +1 -13
  9. package/dist/core/AbiParameters.js.map +1 -1
  10. package/dist/core/AesGcm.d.ts +36 -1
  11. package/dist/core/AesGcm.d.ts.map +1 -1
  12. package/dist/core/AesGcm.js +44 -0
  13. package/dist/core/AesGcm.js.map +1 -1
  14. package/dist/core/Ed25519.d.ts +46 -1
  15. package/dist/core/Ed25519.d.ts.map +1 -1
  16. package/dist/core/Ed25519.js +43 -0
  17. package/dist/core/Ed25519.js.map +1 -1
  18. package/dist/core/Engine.d.ts +1 -1
  19. package/dist/core/Engine.d.ts.map +1 -1
  20. package/dist/core/Engine.js.map +1 -1
  21. package/dist/core/Hash.d.ts +164 -1
  22. package/dist/core/Hash.d.ts.map +1 -1
  23. package/dist/core/Hash.js +172 -0
  24. package/dist/core/Hash.js.map +1 -1
  25. package/dist/core/Hex.d.ts.map +1 -1
  26. package/dist/core/Hex.js +1 -4
  27. package/dist/core/Hex.js.map +1 -1
  28. package/dist/core/Rlp.d.ts +32 -0
  29. package/dist/core/Rlp.d.ts.map +1 -1
  30. package/dist/core/Rlp.js +146 -0
  31. package/dist/core/Rlp.js.map +1 -1
  32. package/dist/core/Secp256k1.d.ts +46 -1
  33. package/dist/core/Secp256k1.d.ts.map +1 -1
  34. package/dist/core/Secp256k1.js +48 -0
  35. package/dist/core/Secp256k1.js.map +1 -1
  36. package/dist/core/WebAuthn.d.ts +224 -0
  37. package/dist/core/WebAuthn.d.ts.map +1 -0
  38. package/dist/core/WebAuthn.js +343 -0
  39. package/dist/core/WebAuthn.js.map +1 -0
  40. package/dist/core/WebAuthnP256.d.ts +46 -50
  41. package/dist/core/WebAuthnP256.d.ts.map +1 -1
  42. package/dist/core/WebAuthnP256.js +44 -50
  43. package/dist/core/WebAuthnP256.js.map +1 -1
  44. package/dist/core/internal/abiParameters.d.ts +7 -87
  45. package/dist/core/internal/abiParameters.d.ts.map +1 -1
  46. package/dist/core/internal/abiParameters.js +339 -194
  47. package/dist/core/internal/abiParameters.js.map +1 -1
  48. package/dist/core/internal/engine.d.ts +35 -2
  49. package/dist/core/internal/engine.d.ts.map +1 -1
  50. package/dist/core/internal/engine.js +12 -1
  51. package/dist/core/internal/engine.js.map +1 -1
  52. package/dist/core/internal/hash.d.ts +10 -0
  53. package/dist/core/internal/hash.d.ts.map +1 -1
  54. package/dist/core/internal/hash.js +26 -1
  55. package/dist/core/internal/hash.js.map +1 -1
  56. package/dist/index.d.ts +23 -14
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +23 -14
  59. package/dist/index.js.map +1 -1
  60. package/dist/node/Engine.d.ts +1 -1
  61. package/dist/node/Engine.d.ts.map +1 -1
  62. package/dist/node/Engine.js.map +1 -1
  63. package/dist/node/Hash.d.ts +6 -4
  64. package/dist/node/Hash.d.ts.map +1 -1
  65. package/dist/node/Hash.js +35 -3
  66. package/dist/node/Hash.js.map +1 -1
  67. package/dist/tempo/AuthorizationTempo.d.ts +6 -6
  68. package/dist/tempo/AuthorizationTempo.js +6 -6
  69. package/dist/tempo/KeyAuthorization.d.ts +3 -8
  70. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  71. package/dist/tempo/KeyAuthorization.js +3 -8
  72. package/dist/tempo/KeyAuthorization.js.map +1 -1
  73. package/dist/tempo/SignatureEnvelope.d.ts +8 -8
  74. package/dist/tempo/SignatureEnvelope.js +8 -8
  75. package/dist/wasm/Engine.d.ts +1 -1
  76. package/dist/wasm/Engine.d.ts.map +1 -1
  77. package/dist/wasm/Engine.js.map +1 -1
  78. package/dist/wasm/Hash.d.ts +1 -1
  79. package/dist/wasm/Hash.d.ts.map +1 -1
  80. package/dist/wasm/Hash.js +5 -0
  81. package/dist/wasm/Hash.js.map +1 -1
  82. package/dist/wasm/internal/blake3.d.ts +10 -1
  83. package/dist/wasm/internal/blake3.d.ts.map +1 -1
  84. package/dist/wasm/internal/blake3.js +12 -1
  85. package/dist/wasm/internal/blake3.js.map +1 -1
  86. package/dist/wasm/internal/blake3.wasm.d.ts +3 -1
  87. package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -1
  88. package/dist/wasm/internal/blake3.wasm.js +3 -1
  89. package/dist/wasm/internal/blake3.wasm.js.map +1 -1
  90. package/dist/wasm/internal/hash.d.ts +9 -0
  91. package/dist/wasm/internal/hash.d.ts.map +1 -1
  92. package/dist/wasm/internal/hash.js +13 -1
  93. package/dist/wasm/internal/hash.js.map +1 -1
  94. package/dist/wasm/internal/hashState.d.ts +25 -0
  95. package/dist/wasm/internal/hashState.d.ts.map +1 -0
  96. package/dist/wasm/internal/hashState.js +105 -0
  97. package/dist/wasm/internal/hashState.js.map +1 -0
  98. package/dist/wasm/internal/hashes.d.ts +12 -1
  99. package/dist/wasm/internal/hashes.d.ts.map +1 -1
  100. package/dist/wasm/internal/hashes.js +18 -1
  101. package/dist/wasm/internal/hashes.js.map +1 -1
  102. package/dist/wasm/internal/hashes.wasm.d.ts +11 -3
  103. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
  104. package/dist/wasm/internal/hashes.wasm.js +11 -3
  105. package/dist/wasm/internal/hashes.wasm.js.map +1 -1
  106. package/dist/webauthn/Authentication.d.ts +2 -0
  107. package/dist/webauthn/Authentication.d.ts.map +1 -1
  108. package/dist/webauthn/Authentication.js +2 -1
  109. package/dist/webauthn/Authentication.js.map +1 -1
  110. package/dist/webauthn/Registration.d.ts.map +1 -1
  111. package/dist/webauthn/Registration.js +2 -1
  112. package/dist/webauthn/Registration.js.map +1 -1
  113. package/dist/webauthn/Types.d.ts +27 -6
  114. package/dist/webauthn/Types.d.ts.map +1 -1
  115. package/dist/webauthn/internal/utils.d.ts.map +1 -1
  116. package/dist/webauthn/internal/utils.js +35 -9
  117. package/dist/webauthn/internal/utils.js.map +1 -1
  118. package/dist/zod/TypedData.d.ts +2 -2
  119. package/package.json +9 -1
  120. package/src/benchmarks/Ox.bench.ts +6 -0
  121. package/src/benchmarks/OxNode.bench.ts +8 -0
  122. package/src/benchmarks/OxV0.bench.ts +4 -0
  123. package/src/benchmarks/OxWasm.bench.ts +22 -0
  124. package/src/core/AbiFunction.ts +5 -5
  125. package/src/core/AbiParameters.ts +8 -20
  126. package/src/core/AesGcm.ts +86 -1
  127. package/src/core/Ed25519.ts +87 -1
  128. package/src/core/Engine.ts +1 -0
  129. package/src/core/Hash.ts +262 -1
  130. package/src/core/Hex.ts +1 -4
  131. package/src/core/Rlp.ts +172 -5
  132. package/src/core/Secp256k1.ts +92 -1
  133. package/src/core/WebAuthn.ts +579 -0
  134. package/src/core/WebAuthnP256.ts +47 -50
  135. package/src/core/_test/AbiFunction.test.ts +9 -0
  136. package/src/core/_test/AbiParameters.differential.fuzz.ts +156 -0
  137. package/src/core/_test/AbiParameters.encode.test.ts +22 -0
  138. package/src/core/_test/AbiParameters.fuzz.ts +4 -0
  139. package/src/core/_test/AesGcm.test.ts +76 -0
  140. package/src/core/_test/Ed25519.test-d.ts +13 -1
  141. package/src/core/_test/Ed25519.test.ts +120 -1
  142. package/src/core/_test/Engine.test-d.ts +9 -0
  143. package/src/core/_test/Engine.test.ts +1 -1
  144. package/src/core/_test/Hash.test-d.ts +23 -0
  145. package/src/core/_test/Hash.test.ts +179 -1
  146. package/src/core/_test/Hex.test.ts +2 -0
  147. package/src/core/_test/Rlp.test-d.ts +18 -0
  148. package/src/core/_test/Rlp.test.ts +109 -0
  149. package/src/core/_test/Secp256k1.test-d.ts +14 -0
  150. package/src/core/_test/Secp256k1.test.ts +91 -1
  151. package/src/core/_test/WebAuthn.test-d.ts +142 -0
  152. package/src/core/_test/WebAuthn.test.ts +766 -0
  153. package/src/core/_test/index.test.ts +1 -0
  154. package/src/core/internal/abiParameters.ts +466 -326
  155. package/src/core/internal/engine.ts +47 -2
  156. package/src/core/internal/hash.ts +53 -1
  157. package/src/index.ts +24 -14
  158. package/src/node/Engine.ts +1 -0
  159. package/src/node/Hash.ts +43 -6
  160. package/src/node/_test/Engine.test-d.ts +1 -0
  161. package/src/node/_test/Engine.test.ts +2 -0
  162. package/src/node/_test/Hash.test-d.ts +10 -0
  163. package/src/node/_test/Hash.test.ts +46 -0
  164. package/src/tempo/AuthorizationTempo.ts +6 -6
  165. package/src/tempo/KeyAuthorization.ts +3 -8
  166. package/src/tempo/SignatureEnvelope.ts +8 -8
  167. package/src/version.ts +1 -1
  168. package/src/wasm/Engine.ts +1 -0
  169. package/src/wasm/Hash.ts +10 -0
  170. package/src/wasm/_test/Engine.test-d.ts +1 -0
  171. package/src/wasm/_test/Engine.test.ts +5 -0
  172. package/src/wasm/_test/Hash.browser.test.ts +28 -0
  173. package/src/wasm/_test/Hash.test-d.ts +16 -0
  174. package/src/wasm/_test/Hash.test.ts +250 -1
  175. package/src/wasm/internal/blake3.ts +23 -2
  176. package/src/wasm/internal/blake3.wasm.ts +4 -1
  177. package/src/wasm/internal/hash.ts +27 -1
  178. package/src/wasm/internal/hashState.ts +154 -0
  179. package/src/wasm/internal/hashes.ts +56 -15
  180. package/src/wasm/internal/hashes.wasm.ts +15 -3
  181. package/src/webauthn/Authentication.ts +4 -0
  182. package/src/webauthn/Registration.ts +2 -0
  183. package/src/webauthn/Types.ts +32 -2
  184. package/src/webauthn/_test/Authentication.test.ts +123 -1
  185. package/src/webauthn/_test/Registration.test.ts +26 -6
  186. package/src/webauthn/_test/WebAuthn.browser.test.ts +28 -0
  187. package/src/webauthn/internal/utils.ts +41 -8
@@ -0,0 +1,154 @@
1
+ import type * as Engine from '../../core/Engine.js'
2
+ import type { Module } from './instantiate.js'
3
+ import { MemoryError } from './instantiate.js'
4
+
5
+ /** Exports required by every incremental hash state. @internal */
6
+ export type Exports = {
7
+ zero(ptr: number, length: number): void
8
+ }
9
+
10
+ /** Parameters for creating a host-owned incremental hash state. @internal */
11
+ export type Options<exports extends Exports> = {
12
+ digestSize: number
13
+ finalize: (exports: exports, state: number, out: number) => void
14
+ init: (
15
+ exports: exports,
16
+ state: number,
17
+ input: number,
18
+ inputLength: number,
19
+ ) => void
20
+ input?: Uint8Array | undefined
21
+ stateSize: number
22
+ update: (
23
+ exports: exports,
24
+ state: number,
25
+ input: number,
26
+ inputLength: number,
27
+ ) => void
28
+ }
29
+
30
+ const alignment = 8
31
+ const wasm32Size = 0x1_0000_0000
32
+
33
+ function align(value: number) {
34
+ return Math.ceil(value / alignment) * alignment
35
+ }
36
+
37
+ function reserve<exports extends Exports>(
38
+ module: Module<exports>,
39
+ end: number,
40
+ ) {
41
+ if (!Number.isSafeInteger(end) || end > wasm32Size)
42
+ throw new MemoryError({
43
+ bytes: end,
44
+ cause: new RangeError('Hash workspace exceeds wasm32 memory.'),
45
+ })
46
+ module.reserve(end - module.heapBase)
47
+ }
48
+
49
+ /**
50
+ * Creates a hash state whose authoritative bytes live in host memory.
51
+ *
52
+ * The shared WASM instance only holds a state during one synchronous call.
53
+ * Every workspace is cleared before control returns to the caller.
54
+ *
55
+ * @internal
56
+ */
57
+ export function create<exports extends Exports>(
58
+ module: Module<exports>,
59
+ options: Options<exports>,
60
+ ): Engine.HashState {
61
+ const { digestSize, finalize, init, stateSize, update } = options
62
+ const initial = options.input ?? new Uint8Array()
63
+ const inputPtr = module.heapBase
64
+ const statePtr = align(inputPtr + initial.length)
65
+ const end = statePtr + stateSize
66
+ reserve(module, end)
67
+
68
+ let state: Uint8Array
69
+ try {
70
+ module.exports.zero(module.heapBase, end - module.heapBase)
71
+ const view = module.view()
72
+ view.set(initial, inputPtr)
73
+ init(module.exports, statePtr, inputPtr, initial.length)
74
+ state = module.view().slice(statePtr, end)
75
+ } finally {
76
+ module.exports.zero(module.heapBase, end - module.heapBase)
77
+ }
78
+
79
+ return fromSnapshot(module, state, {
80
+ digestSize,
81
+ finalize,
82
+ stateSize,
83
+ update,
84
+ })
85
+ }
86
+
87
+ type SnapshotOptions<exports extends Exports> = Pick<
88
+ Options<exports>,
89
+ 'digestSize' | 'finalize' | 'stateSize' | 'update'
90
+ >
91
+
92
+ function fromSnapshot<exports extends Exports>(
93
+ module: Module<exports>,
94
+ state: Uint8Array,
95
+ options: SnapshotOptions<exports>,
96
+ ): Engine.HashState {
97
+ const { digestSize, finalize, stateSize, update } = options
98
+ let active = true
99
+
100
+ const assertActive = () => {
101
+ if (!active) throw new Error('Hash state has been destroyed.')
102
+ }
103
+
104
+ const hashState: Engine.HashState = {
105
+ clone() {
106
+ assertActive()
107
+ return fromSnapshot(module, state.slice(), options)
108
+ },
109
+ destroy() {
110
+ if (!active) return
111
+ active = false
112
+ state.fill(0)
113
+ },
114
+ digestInto(output) {
115
+ assertActive()
116
+ if (output.length < digestSize)
117
+ throw new RangeError(
118
+ `Digest output requires at least ${digestSize} bytes.`,
119
+ )
120
+
121
+ const statePtr = align(module.heapBase)
122
+ const outPtr = statePtr + stateSize
123
+ const end = outPtr + digestSize
124
+ reserve(module, end)
125
+ active = false
126
+ try {
127
+ module.view().set(state, statePtr)
128
+ finalize(module.exports, statePtr, outPtr)
129
+ output.set(module.view().subarray(outPtr, end))
130
+ } finally {
131
+ state.fill(0)
132
+ module.exports.zero(module.heapBase, end - module.heapBase)
133
+ }
134
+ },
135
+ update(input) {
136
+ assertActive()
137
+ const inputPtr = module.heapBase
138
+ const statePtr = align(inputPtr + input.length)
139
+ const end = statePtr + stateSize
140
+ reserve(module, end)
141
+ try {
142
+ const view = module.view()
143
+ view.set(input, inputPtr)
144
+ view.set(state, statePtr)
145
+ update(module.exports, statePtr, inputPtr, input.length)
146
+ state.set(module.view().subarray(statePtr, end))
147
+ } finally {
148
+ module.exports.zero(module.heapBase, end - module.heapBase)
149
+ }
150
+ },
151
+ }
152
+
153
+ return hashState
154
+ }
@@ -1,22 +1,51 @@
1
1
  import * as hash from './hash.js'
2
- import { wasmBase64 } from './hashes.wasm.js'
2
+ import {
3
+ keccak256StateSize,
4
+ ripemd160StateSize,
5
+ sha256StateSize,
6
+ wasmBase64,
7
+ } from './hashes.wasm.js'
8
+ import * as hashState from './hashState.js'
3
9
  import * as internal from './instantiate.js'
4
10
 
11
+ type Algorithm = 'keccak256' | 'ripemd160' | 'sha256'
12
+
13
+ type StateExports = {
14
+ [key in `${Algorithm}_init`]: (state: number) => void
15
+ } & {
16
+ [key in `${Algorithm}_update`]: (
17
+ state: number,
18
+ input: number,
19
+ inputLength: number,
20
+ ) => void
21
+ } & {
22
+ [key in `${Algorithm}_finalize`]: (state: number, out: number) => void
23
+ }
24
+
5
25
  /** Exports shared by the Hash and Keystore providers. @internal */
6
- export type Exports = hash.Exports & {
7
- keccak256(input: number, length: number, out: number): void
8
- pbkdf2_sha256(
9
- password: number,
10
- passwordLength: number,
11
- salt: number,
12
- saltLength: number,
13
- iterations: number,
14
- out: number,
15
- outLength: number,
16
- scratch: number,
17
- ): void
18
- ripemd160(input: number, length: number, out: number): void
19
- sha256(input: number, length: number, out: number): void
26
+ export type Exports = hash.Exports &
27
+ hash.StateExports &
28
+ StateExports & {
29
+ keccak256(input: number, length: number, out: number): void
30
+ pbkdf2_sha256(
31
+ password: number,
32
+ passwordLength: number,
33
+ salt: number,
34
+ saltLength: number,
35
+ iterations: number,
36
+ out: number,
37
+ outLength: number,
38
+ scratch: number,
39
+ ): void
40
+ ripemd160(input: number, length: number, out: number): void
41
+ sha256(input: number, length: number, out: number): void
42
+ }
43
+
44
+ const digestSize = { keccak256: 32, ripemd160: 20, sha256: 32 }
45
+ const stateSize = {
46
+ keccak256: keccak256StateSize,
47
+ ripemd160: ripemd160StateSize,
48
+ sha256: sha256StateSize,
20
49
  }
21
50
 
22
51
  const instantiate = /*#__PURE__*/ internal.memoize(() =>
@@ -27,3 +56,15 @@ const instantiate = /*#__PURE__*/ internal.memoize(() =>
27
56
  export function load() {
28
57
  return instantiate()
29
58
  }
59
+
60
+ /** Creates an incremental state for one of the shared hash primitives. @internal */
61
+ export function create(module: internal.Module<Exports>, hash: Algorithm) {
62
+ return hashState.create(module, {
63
+ digestSize: digestSize[hash],
64
+ finalize: (exports, state, out) => exports[`${hash}_finalize`](state, out),
65
+ init: (exports, state) => exports[`${hash}_init`](state),
66
+ stateSize: stateSize[hash],
67
+ update: (exports, state, input, inputLength) =>
68
+ exports[`${hash}_update`](state, input, inputLength),
69
+ })
70
+ }
@@ -8,10 +8,22 @@
8
8
 
9
9
  /** Base64-encoded WASM binary. */
10
10
  export const wasmBase64 =
11
- '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dnM6ACkgByAHLQAqIDBzOgAqIAcgBCAHLQArczoAKyAHIActACwgHHM6ACwgByAHLQAtIAhBEHZzOgAtIAcgBy0ALiAxczoALiAHIAggBy0AL3M6AC8gByAHLQAwIB1zOgAwIAcgBy0AMSALQRB2czoAMSAHIActADIgMnM6ADIgByALIActADNzOgAzIAcgBy0ANCAeczoANCAHIActADUgCUEQdnM6ADUgByAHLQA2IDNzOgA2IAcgCSAHLQA3czoANyAHIActADggH3M6ADggByAHLQA5IA1BEHZzOgA5IAcgBy0AOiA0czoAOiAHIA0gBy0AO3M6ADsgByAHLQA8ICBzOgA8IAcgBy0APSAKQRB2czoAPSAHIActAD4gNXM6AD4gByAKIActAD9zOgA/IABBAWsiAA0ACwtBICAGIA5rIgEgAUEgTxshAAJAIAYgDkYNAEEBIAAgAEEBTRsiA0EDcSEIQQAhBCABQQRPBEAgBSAOaiELIANBPHEhCQNAIAQgC2oiASAEIAdqIgNBIGotAAA6AAAgAUEBaiADQSFqLQAAOgAAIAFBAmogA0Eiai0AADoAACABQQNqIANBI2otAAA6AAAgCSAEQQRqIgRHDQALCyAIRQ0AQQAgCGshASAEICFqIQMgBSAEIA5qaiEEA0AgBCADLQAAOgAAIANBAWohAyAEQQFqIQQgAUEBaiIBDQALCyAMQQFqIQwgACAOaiIOIAZJDQALC0EAIQMDQCADIAdqIgBBADoAACAAQQFqQQA6AAAgAEECakEAOgAAIABBA2pBADoAACAAQQRqQQA6AAAgAEEFakEAOgAAIABBBmpBADoAACAAQQdqQQA6AAAgAEEIakEAOgAAIABBCWpBADoAACAAQQpqQQA6AAAgAEELakEAOgAAIABBDGpBADoAACAAQQ1qQQA6AAAgAEEOakEAOgAAIABBD2pBADoAACADQRBqIgNBoARHDQALC78IARJ/IAIgASgAACIDQRh0IANBgP4DcUEIdHIgA0EIdkGA/gNxIANBGHZycjYCACACIAEoAAQiA0EYdCADQYD+A3FBCHRyIANBCHZBgP4DcSADQRh2cnI2AgQgAiABKAAIIgNBGHQgA0GA/gNxQQh0ciADQQh2QYD+A3EgA0EYdnJyNgIIIAIgASgADCIDQRh0IANBgP4DcUEIdHIg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'
11
+ 'AGFzbQEAAAABLgdgA39/fwBgAn9/AGABfwBgBn9/f39/fwBgCH9/f39/f39/AGACf38Bf2AAAX8DHRwDAAABAQEAAAIAAQICBAUAAgABAQACAAEBAgAGBQMBABAGCAF/AUHQjgQLB8wCFQZtZW1vcnkCAAxrZWNjYWtfZjE2MDAADA5rZWNjYWsyNTZfaW5pdAAIEGtlY2NhazI1Nl91cGRhdGUACRJrZWNjYWsyNTZfZmluYWxpemUACglrZWNjYWsyNTYABwtzaGEyNTZfaW5pdAAZDXNoYTI1Nl91cGRhdGUAAg9zaGEyNTZfZmluYWxpemUAGAZzaGEyNTYAFBBobWFjX3NoYTI1Nl9pbml0AAYSaG1hY19zaGEyNTZfdXBkYXRlAAIUaG1hY19zaGEyNTZfZmluYWxpemUABQtobWFjX3NoYTI1NgAADXBia2RmMl9zaGEyNTYADQ5yaXBlbWQxNjBfaW5pdAAQEHJpcGVtZDE2MF91cGRhdGUAERJyaXBlbWQxNjBfZmluYWxpemUAEglyaXBlbWQxNjAADwR6ZXJvAAQJaGVhcF9iYXNlABsKwlMcHwAgBSAAIAEQASAFIAIgAxAWIAUgBBADIAVBkAEQBAuTBAEDfyMAQbABayIDJAAgA0IANwOoASADQgA3A6ABIANCADcDmAEgA0IANwOQASADQgA3A4gBIANCADcDgAEgA0IANwN4IANCADcDcAJAIAJBwABNBEAgAkUNASACQQNxIQUgAkEETwRAIAJB/ABxIQIDQCADQfAAaiAEaiABIARqKAAANgIAIAIgBEEEaiIERw0ACwsgBUUNASABIARqIQEgA0HwAGogBGohBANAIAQgAS0AADoAACABQQFqIQEgBEEBaiEEIAVBAWsiBQ0ACwwBCyADEBUgAyABIAIQFiADIANB8ABqEBcgA0HwABAECyAAEBVBACEBA0AgA0HwAGoiBCABaiICIAItAABBNnM6AAAgAkEBaiIFIAUtAABBNnM6AAAgAkECaiIFIAUtAABBNnM6AAAgAkEDaiICIAItAABBNnM6AAAgAUEEaiIBQcAARw0ACyAAIARBwAAQFiADEBVBACEBA0AgA0HwAGoiBCABaiICIAItAABB6gBzOgAAIAJBAWoiBSAFLQAAQeoAczoAACACQQJqIgUgBS0AAEHqAHM6AAAgAkEDaiICIAItAABB6gBzOgAAIAFBBGoiAUHAAEcNAAsgAyAEQcAAEBYgACADKQMINwJwIAAgAykDEDcCeCAAIAMpAxg3AoABIAAgAykDIDcCiAEgA0HwABAEIARBwAAQBCADQbABaiQACwoAIAAgASACEBYLtgMBAn8jAEGQAWsiAiQAIAAgAkHwAGoiAxAXIAIQFSACQsAANwMAIAIgACkCcDcDCCACIAApAng3AxAgAiAAKQKAATcDGCACIAApAogBNwMgIAIgA0EgEBYgAiAAQSxqEBcgAkHwABAEIANBIBAEIAEgAC0ALDoAACABIAAtAC06AAEgASAALQAuOgACIAEgAC0ALzoAAyABIAAtADA6AAQgASAALQAxOgAFIAEgAC0AMjoABiABIAAtADM6AAcgASAALQA0OgAIIAEgAC0ANToACSABIAAtADY6AAogASAALQA3OgALIAEgAC0AODoADCABIAAtADk6AA0gASAALQA6OgAOIAEgAC0AOzoADyABIAAtADw6ABAgASAALQA9OgARIAEgAC0APjoAEiABIAAtAD86ABMgASAALQBAOgAUIAEgAC0AQToAFSABIAAtAEI6ABYgASAALQBDOgAXIAEgAC0ARDoAGCABIAAtAEU6ABkgASAALQBGOgAaIAEgAC0ARzoAGyABIAAtAEg6ABwgASAALQBJOgAdIAEgAC0ASjoAHiABIAAtAEs6AB8gAkGQAWokAAuTAQECfwJAIAFFDQACQCABQQdxIgNFBEAgASECDAELIAFBeHEhAgNAIABBADoAACAAQQFqIQAgA0EBayIDDQALCyABQQhJDQADQCAAQQA6AAAgAEEAOgABIABBADoAAiAAQQA6AAMgAEEAOgAEIABBADoABSAAQQA6AAYgAEEAOgAHIABBCGohACACQQhrIgINAAsLCwgAIAAgARADCwoAIAAgASACEAELLQECfyMAQeACayIDJAAgA0EIaiIEEAggBCAAIAEQCSAEIAIQCiADQeACaiQAC+IBAQF/IABBADYCyAEgAEIANwPAASAAQgA3A7gBIABCADcDsAEgAEIANwOoASAAQgA3A6ABIABCADcDmAEgAEIANwOQASAAQgA3A4gBIABCADcDgAEgAEIANwN4IABCADcDcCAAQgA3A2ggAEIANwNgIABCADcDWCAAQgA3A1AgAEIANwNIIABCADcDQCAAQgA3AzggAEIANwMwIABCADcDKCAAQgA3AyAgAEIANwMYIABCADcDECAAQgA3AwggAEIANwMAA0AgACABakHMAWpCADcAACABQQhqIgFBiAFHDQALC5UJAQd/AkAgACgCyAEiAwRAQYgBIANrIgcgAiACIAdLGyIEBEAgBEEDcSEFQQAhAyAEQQRPBEAgBEF8cSEIA0AgACADIAAoAsgBampBzAFqIAEgA2oiBi0AADoAACAAIAMgACgCyAFqakHNAWogBkEBai0AADoAACAAIAMgACgCyAFqakHOAWogBkECai0AADoAACAAIAMgACgCyAFqakHPAWogBkEDai0AADoAACAIIANBBGoiA0cNAAsLIAUEQCABIANqIQYgACADakHMAWohAwNAIAMgACgCyAFqIAYtAAA6AAAgBkEBaiEGIANBAWohAyAFQQFrIgUNAAsLIAAoAsgBIQMLIAAgAyAEaiIDNgLIASADQYgBRgRAIAAgACkDACAAKQDMAYU3AwAgACAAKQMIIAApANQBhTcDCCAAIAApAxAgACkA3AGFNwMQIAAgACkDGCAAKQDkAYU3AxggACAAKQMgIAApAOwBhTcDICAAIAApAyggACkA9AGFNwMoIAAgACkDMCAAKQD8AYU3AzAgACAAKQM4IAApAIQChTcDOCAAIAApA0AgACkAjAKFNwNAIAAgACkDSCAAKQCUAoU3A0ggACAAKQNQIAApAJwChTcDUCAAIAApA1ggACkApAKFNwNYIAAgACkDYCAAKQCsAoU3A2AgACAAKQNoIAApALQChTcDaCAAIAApA3AgACkAvAKFNwNwIAAgACkDeCAAKQDEAoU3A3ggACAAKQOAASAAKQDMAoU3A4ABIAAQCyAAQQA2AsgBCyACIAdNDQELIAIgBGsiBUGIAU8EQANAIAAgACkDACABIARqIgIpAACFNwMAIAAgACkDCCACKQAIhTcDCCAAIAApAxAgAkEQaikAAIU3AxAgACAAKQMYIAJBGGopAACFNwMYIAAgACkDICACQSBqKQAAhTcDICAAIAApAyggAkEoaikAAIU3AyggACAAKQMwIAJBMGopAACFNwMwIAAgACkDOCACQThqKQAAhTcDOCAAIAApA0AgAkFAaykAAIU3A0AgACAAKQNIIAJByABqKQAAhTcD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AgAiDSEJIAAoAgQiDiEBIAAoAggiDyEFIAAoAgwiECEMIAAoAhwiESEKIAAoAhgiEiEIIAAoAhQiEyEDIAAoAhAiFCEGA0AgBSEEIAEhBSACIAtqKAIAIAtBwAlqKAIAIAogBiIHQRp3IAdBFXdzIAdBB3dzaiAHQX9zIAhxIAMgB3FyampqIgYgCSIBQR53IAFBE3dzIAFBCndzIAEgBCAFc3EgBCAFcXNqaiEJIAYgDGohBiAEIQwgCCEKIAMhCCAHIQMgC0EEaiILQYACRw0ACyAAIAogEWo2AhwgACAIIBJqNgIYIAAgAyATajYCFCAAIAYgFGo2AhAgACAEIBBqNgIMIAAgBSAPajYCCCAAIAEgDmo2AgQgACAJIA1qNgIACyUBAX9BwA4tAAAiAARAQdCOBEEAIAAbDwtBwA5BAToAAEHQjgQLC7kGAwBBgAgLpAQBAAAAAAAAAIKAAAAAAAAAioAAAAAAAIAAgACAAAAAgIuAAAAAAAAAAQAAgAAAAACBgACAAAAAgAmAAAAAAACAigAAAAAAAACIAAAAAAAAAAmAAIAAAAAACgAAgAAAAACLgACAAAAAAIsAAAAAAACAiYAAAAAAAIADgAAAAAAAgAKAAAAAAACAgAAAAAAAAIAKgAAAAAAAAAoAAIAAAACAgYAAgAAAAICAgAAAAAAAgAEAAIAAAAAACIAAgAAAAICYL4pCkUQ3cc/7wLWl27XpW8JWOfER8Vmkgj+S1V4cq5iqB9gBW4MSvoUxJMN9DFV0Xb5y/rHegKcG3Jt08ZvBwWmb5IZHvu/GncEPzKEMJG8s6S2qhHRK3KmwXNqI+XZSUT6YbcYxqMgnA7DHf1m/8wvgxkeRp9VRY8oGZykpFIUKtyc4IRsu/G0sTRMNOFNUcwpluwpqdi7JwoGFLHKSoei/oktmGqhwi0vCo1FsxxnoktEkBpnWhTUO9HCgahAWwaQZCGw3Hkx3SCe1vLA0swwcOUqq2E5Pypxb828uaO6Cj3RvY6V4FHjIhAgCx4z6/76Q62xQpPej+b7yeHHGAAECAwQFBgcICQoLDA0ODwcEDQEKBg8DDAAJBQIOCwgDCg4ECQ8IAQIHAAYNCwUMAQkLCgAIDAQNAwcPDgUGAgQABQkHDAIKDgEDCAsGDw0AAAAAmXmCWqHr2W7cvBuPTv1TqQBBsAwLsAELDg8MBQgHCQsNDg8GBwkIBwYIDQsJBw8HDA8JCwcNDAsNBgcOCQ0PDggNBgUMBwULDA4PDg8JCAkOBQYIBgUMCQ8FCwYIDQwFDA0OCwgFBgUOBwAJAgsEDQYPCAEKAwwGCwMHAA0FCg4PCAwECQECDwUBAwcOBgkLCAwCCgAEDQgGBAEDCw8ABQwCDQkHCg4MDwoEAQUIBwYCDQ4AAwkL5ouiUCTRTVzzPnBt6XZtegBB8A0LUAgJCQsNDw8FBwcICw4ODAYJDQ8HDAgJCwcHDAcGDw0LCQcPCwgGBg4MDQUODQ0HBQ8FCAsODgYOBgkMCQwFDwgIBQwJDAUOBggNBgUPDQsL'
12
12
 
13
13
  /** Constant shared with the module's C source. */
14
- export const hmacSha256ScratchSize = 544
14
+ export const hmacSha256ScratchSize = 144
15
15
 
16
16
  /** Constant shared with the module's C source. */
17
- export const pbkdf2Sha256ScratchSize = 544
17
+ export const hmacSha256StateSize = 144
18
+
19
+ /** Constant shared with the module's C source. */
20
+ export const keccak256StateSize = 344
21
+
22
+ /** Constant shared with the module's C source. */
23
+ export const pbkdf2Sha256ScratchSize = 352
24
+
25
+ /** Constant shared with the module's C source. */
26
+ export const ripemd160StateSize = 96
27
+
28
+ /** Constant shared with the module's C source. */
29
+ export const sha256StateSize = 112
@@ -175,6 +175,7 @@ export function getOptions(
175
175
  challenge,
176
176
  extensions,
177
177
  rpId = window.location.hostname,
178
+ timeout,
178
179
  userVerification = 'required',
179
180
  } = options
180
181
  return {
@@ -197,6 +198,7 @@ export function getOptions(
197
198
  challenge: Bytes.fromHex(challenge),
198
199
  ...(extensions && { extensions }),
199
200
  rpId,
201
+ ...(timeout !== undefined && { timeout }),
200
202
  userVerification,
201
203
  },
202
204
  }
@@ -214,6 +216,8 @@ export declare namespace getOptions {
214
216
  | undefined
215
217
  /** The relying party identifier to use. */
216
218
  rpId?: Types.PublicKeyCredentialRequestOptions['rpId'] | undefined
219
+ /** Time, in milliseconds, that the caller is willing to wait for the operation. */
220
+ timeout?: Types.PublicKeyCredentialRequestOptions['timeout'] | undefined
217
221
  /** The user verification requirement. */
218
222
  userVerification?:
219
223
  | Types.PublicKeyCredentialRequestOptions['userVerification']
@@ -160,6 +160,7 @@ export function getOptions(
160
160
  id: window.location.hostname,
161
161
  name: window.document.title,
162
162
  },
163
+ timeout,
163
164
  user,
164
165
  } = options
165
166
  const name = (user?.name ?? name_)!
@@ -184,6 +185,7 @@ export function getOptions(
184
185
  },
185
186
  ],
186
187
  rp,
188
+ ...(timeout !== undefined && { timeout }),
187
189
  user: {
188
190
  id: user?.id ?? Hash.keccak256(Bytes.fromString(name), { as: 'Bytes' }),
189
191
  name,
@@ -38,7 +38,29 @@ export type LargeBlobSupport = {
38
38
 
39
39
  export type BufferSource = ArrayBufferView | ArrayBuffer
40
40
 
41
- export type PrfExtension = Record<'eval', Record<'first', Uint8Array>>
41
+ /** Inputs or outputs for a WebAuthn PRF evaluation. */
42
+ export type PrfValues<serialized extends boolean = false> = {
43
+ /** First PRF input or output. */
44
+ first: serialized extends true ? string : BufferSource
45
+ /** Optional second PRF input or output. */
46
+ second?: (serialized extends true ? string : BufferSource) | undefined
47
+ }
48
+
49
+ /** Inputs for the WebAuthn PRF extension. */
50
+ export type PrfExtension<serialized extends boolean = false> = {
51
+ /** PRF inputs for the selected credential. */
52
+ eval?: PrfValues<serialized> | undefined
53
+ /** PRF inputs keyed by base64url-encoded credential ID. */
54
+ evalByCredential?: Record<string, PrfValues<serialized>> | undefined
55
+ }
56
+
57
+ /** Outputs from the WebAuthn PRF extension. */
58
+ export type PrfExtensionOutput = {
59
+ /** Whether the created credential supports PRF evaluation. */
60
+ enabled?: boolean | undefined
61
+ /** PRF evaluation results. */
62
+ results?: PrfValues | undefined
63
+ }
42
64
 
43
65
  export interface AuthenticationExtensionsClientInputs<
44
66
  serialized extends boolean = false,
@@ -47,10 +69,18 @@ export interface AuthenticationExtensionsClientInputs<
47
69
  credProps?: boolean
48
70
  hmacCreateSecret?: boolean
49
71
  minPinLength?: boolean
50
- prf?: serialized extends true ? { eval: { first: string } } : PrfExtension
72
+ prf?: PrfExtension<serialized> | undefined
51
73
  largeBlob?: LargeBlobSupport
52
74
  }
53
75
 
76
+ /** Outputs from WebAuthn client extension processing. */
77
+ export type AuthenticationExtensionsClientOutputs = ReturnType<
78
+ globalThis.PublicKeyCredential['getClientExtensionResults']
79
+ > & {
80
+ /** WebAuthn PRF extension output. */
81
+ prf?: PrfExtensionOutput | undefined
82
+ }
83
+
54
84
  export interface AuthenticatorSelectionCriteria {
55
85
  authenticatorAttachment?: AuthenticatorAttachment
56
86
  requireResidentKey?: boolean
@@ -1,3 +1,4 @@
1
+ import { runInNewContext } from 'node:vm'
1
2
  import { afterAll, beforeAll, describe, expect, test, vi } from 'vp/test'
2
3
  import * as Bytes from '../../core/Bytes.js'
3
4
  import * as Hash from '../../core/Hash.js'
@@ -5,7 +6,7 @@ import * as P256 from '../../core/P256.js'
5
6
  import * as PublicKey from '../../core/PublicKey.js'
6
7
  import * as Signature from '../../core/Signature.js'
7
8
  import * as WebCryptoP256 from '../../core/WebCryptoP256.js'
8
- import { Authentication } from '../index.js'
9
+ import { Authentication, type Types } from '../index.js'
9
10
 
10
11
  beforeAll(() => {
11
12
  vi.stubGlobal('window', {
@@ -73,6 +74,16 @@ describe('getOptions', () => {
73
74
  `)
74
75
  })
75
76
 
77
+ test('options: timeout', () => {
78
+ const options = Authentication.getOptions({
79
+ challenge:
80
+ '0xf631058a3ba1116acce12396fad0a125b5041c43f8e15723709f81aa8d5f4ccf',
81
+ timeout: 30_000,
82
+ })
83
+
84
+ expect(options.publicKey?.timeout).toMatchInlineSnapshot(`30000`)
85
+ })
86
+
76
87
  test('options: credentialId', () => {
77
88
  expect(
78
89
  Authentication.getOptions({
@@ -200,6 +211,61 @@ describe('serializeOptions', () => {
200
211
  expect(() => JSON.stringify(serialized)).not.toThrow()
201
212
  })
202
213
 
214
+ test('with extensions (prf.evalByCredential)', () => {
215
+ const first = runInNewContext(
216
+ 'Uint8Array.from([4, 5, 6]).buffer',
217
+ ) as ArrayBuffer
218
+ const options: Types.CredentialRequestOptions = {
219
+ publicKey: {
220
+ challenge: new Uint8Array([1, 2, 3]),
221
+ extensions: {
222
+ prf: {
223
+ evalByCredential: {
224
+ credential: {
225
+ first,
226
+ second: new Uint8Array(),
227
+ },
228
+ },
229
+ },
230
+ },
231
+ },
232
+ }
233
+ const serialized = Authentication.serializeOptions(options)
234
+
235
+ expect(first).not.toBeInstanceOf(ArrayBuffer)
236
+ expect(serialized.publicKey!.extensions).toMatchInlineSnapshot(`
237
+ {
238
+ "prf": {
239
+ "evalByCredential": {
240
+ "credential": {
241
+ "first": "BAUG",
242
+ "second": "",
243
+ },
244
+ },
245
+ },
246
+ }
247
+ `)
248
+ expect(() => JSON.stringify(serialized)).not.toThrow()
249
+ })
250
+
251
+ test('with extensions (empty prf)', () => {
252
+ const options: Types.CredentialRequestOptions = {
253
+ publicKey: {
254
+ challenge: new Uint8Array([1, 2, 3]),
255
+ extensions: {
256
+ prf: {},
257
+ },
258
+ },
259
+ }
260
+ const serialized = Authentication.serializeOptions(options)
261
+
262
+ expect(serialized.publicKey!.extensions).toMatchInlineSnapshot(`
263
+ {
264
+ "prf": {},
265
+ }
266
+ `)
267
+ })
268
+
203
269
  test('empty publicKey', () => {
204
270
  const serialized = Authentication.serializeOptions({})
205
271
  expect(serialized).toEqual({})
@@ -241,6 +307,62 @@ describe('deserializeOptions', () => {
241
307
  )
242
308
  })
243
309
 
310
+ test('with extensions (prf.evalByCredential)', () => {
311
+ const options: Types.CredentialRequestOptions = {
312
+ publicKey: {
313
+ challenge: new Uint8Array([1, 2, 3]),
314
+ extensions: {
315
+ prf: {
316
+ evalByCredential: {
317
+ credential: {
318
+ first: new Uint8Array([4, 5, 6]),
319
+ second: new Uint8Array(),
320
+ },
321
+ },
322
+ },
323
+ },
324
+ },
325
+ }
326
+ const serialized = Authentication.serializeOptions(options)
327
+ const deserialized = Authentication.deserializeOptions(serialized)
328
+
329
+ expect(deserialized.publicKey!.extensions).toMatchInlineSnapshot(`
330
+ {
331
+ "prf": {
332
+ "evalByCredential": {
333
+ "credential": {
334
+ "first": Uint8Array [
335
+ 4,
336
+ 5,
337
+ 6,
338
+ ],
339
+ "second": Uint8Array [],
340
+ },
341
+ },
342
+ },
343
+ }
344
+ `)
345
+ })
346
+
347
+ test('with extensions (empty prf)', () => {
348
+ const options: Types.CredentialRequestOptions = {
349
+ publicKey: {
350
+ challenge: new Uint8Array([1, 2, 3]),
351
+ extensions: {
352
+ prf: {},
353
+ },
354
+ },
355
+ }
356
+ const serialized = Authentication.serializeOptions(options)
357
+ const deserialized = Authentication.deserializeOptions(serialized)
358
+
359
+ expect(deserialized.publicKey!.extensions).toMatchInlineSnapshot(`
360
+ {
361
+ "prf": {},
362
+ }
363
+ `)
364
+ })
365
+
244
366
  test('empty publicKey', () => {
245
367
  const deserialized = Authentication.deserializeOptions({})
246
368
  expect(deserialized).toEqual({})
@@ -1,3 +1,4 @@
1
+ import { runInNewContext } from 'node:vm'
1
2
  import { afterAll, beforeAll, describe, expect, test, vi } from 'vp/test'
2
3
  import * as Base64 from '../../core/Base64.js'
3
4
  import * as Bytes from '../../core/Bytes.js'
@@ -329,6 +330,15 @@ describe('getOptions', () => {
329
330
  `)
330
331
  })
331
332
 
333
+ test('options: timeout', () => {
334
+ const options = Registration.getOptions({
335
+ name: 'Foo',
336
+ timeout: 30_000,
337
+ })
338
+
339
+ expect(options.publicKey?.timeout).toMatchInlineSnapshot(`30000`)
340
+ })
341
+
332
342
  test('args: excludeCredentialIds', () => {
333
343
  expect(
334
344
  Registration.getOptions({
@@ -594,6 +604,9 @@ describe('serializeOptions', () => {
594
604
  })
595
605
 
596
606
  test('with extensions (prf)', () => {
607
+ const first = runInNewContext(
608
+ 'Uint8Array.from([7, 8, 9]).buffer',
609
+ ) as ArrayBuffer
597
610
  const options: Types.CredentialCreationOptions = {
598
611
  publicKey: {
599
612
  challenge: new Uint8Array([1, 2, 3]),
@@ -607,7 +620,8 @@ describe('serializeOptions', () => {
607
620
  extensions: {
608
621
  prf: {
609
622
  eval: {
610
- first: new Uint8Array([7, 8, 9]),
623
+ first,
624
+ second: new Uint8Array(),
611
625
  },
612
626
  },
613
627
  },
@@ -615,9 +629,11 @@ describe('serializeOptions', () => {
615
629
  }
616
630
  const serialized = Registration.serializeOptions(options)
617
631
 
618
- expect(typeof serialized.publicKey!.extensions!.prf!.eval.first).toBe(
619
- 'string',
620
- )
632
+ expect(first).not.toBeInstanceOf(ArrayBuffer)
633
+ expect(
634
+ serialized.publicKey!.extensions!.prf!.eval!.first,
635
+ ).toMatchInlineSnapshot(`"BwgJ"`)
636
+ expect(serialized.publicKey!.extensions!.prf!.eval!.second).toBe('')
621
637
  expect(() => JSON.stringify(serialized)).not.toThrow()
622
638
  })
623
639
 
@@ -674,6 +690,7 @@ describe('deserializeOptions', () => {
674
690
  prf: {
675
691
  eval: {
676
692
  first: new Uint8Array([7, 8, 9]),
693
+ second: new Uint8Array(),
677
694
  },
678
695
  },
679
696
  },
@@ -682,12 +699,15 @@ describe('deserializeOptions', () => {
682
699
  const serialized = Registration.serializeOptions(options)
683
700
  const deserialized = Registration.deserializeOptions(serialized)
684
701
 
685
- expect(deserialized.publicKey!.extensions!.prf!.eval.first).toBeInstanceOf(
702
+ expect(deserialized.publicKey!.extensions!.prf!.eval!.first).toBeInstanceOf(
686
703
  Uint8Array,
687
704
  )
688
- expect(deserialized.publicKey!.extensions!.prf!.eval.first).toEqual(
705
+ expect(deserialized.publicKey!.extensions!.prf!.eval!.first).toEqual(
689
706
  new Uint8Array([7, 8, 9]),
690
707
  )
708
+ expect(deserialized.publicKey!.extensions!.prf!.eval!.second).toEqual(
709
+ new Uint8Array(),
710
+ )
691
711
  })
692
712
 
693
713
  test('empty publicKey', () => {