ox 1.1.2 → 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.
- package/CHANGELOG.md +61 -0
- package/dist/core/AbiFunction.d.ts +1 -1
- package/dist/core/AbiFunction.d.ts.map +1 -1
- package/dist/core/AbiFunction.js +6 -2
- package/dist/core/AbiFunction.js.map +1 -1
- package/dist/core/AbiParameters.d.ts +1 -1
- package/dist/core/AbiParameters.d.ts.map +1 -1
- package/dist/core/AbiParameters.js +1 -13
- package/dist/core/AbiParameters.js.map +1 -1
- package/dist/core/AesGcm.d.ts +36 -1
- package/dist/core/AesGcm.d.ts.map +1 -1
- package/dist/core/AesGcm.js +44 -0
- package/dist/core/AesGcm.js.map +1 -1
- package/dist/core/Ed25519.d.ts +46 -1
- package/dist/core/Ed25519.d.ts.map +1 -1
- package/dist/core/Ed25519.js +43 -0
- package/dist/core/Ed25519.js.map +1 -1
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Hash.d.ts +200 -1
- package/dist/core/Hash.d.ts.map +1 -1
- package/dist/core/Hash.js +207 -0
- package/dist/core/Hash.js.map +1 -1
- package/dist/core/Hex.d.ts.map +1 -1
- package/dist/core/Hex.js +1 -4
- package/dist/core/Hex.js.map +1 -1
- package/dist/core/Rlp.d.ts +32 -0
- package/dist/core/Rlp.d.ts.map +1 -1
- package/dist/core/Rlp.js +146 -0
- package/dist/core/Rlp.js.map +1 -1
- package/dist/core/Secp256k1.d.ts +46 -1
- package/dist/core/Secp256k1.d.ts.map +1 -1
- package/dist/core/Secp256k1.js +48 -0
- package/dist/core/Secp256k1.js.map +1 -1
- package/dist/core/WebAuthn.d.ts +224 -0
- package/dist/core/WebAuthn.d.ts.map +1 -0
- package/dist/core/WebAuthn.js +343 -0
- package/dist/core/WebAuthn.js.map +1 -0
- package/dist/core/WebAuthnP256.d.ts +46 -50
- package/dist/core/WebAuthnP256.d.ts.map +1 -1
- package/dist/core/WebAuthnP256.js +44 -50
- package/dist/core/WebAuthnP256.js.map +1 -1
- package/dist/core/internal/abiParameters.d.ts +7 -87
- package/dist/core/internal/abiParameters.d.ts.map +1 -1
- package/dist/core/internal/abiParameters.js +339 -194
- package/dist/core/internal/abiParameters.js.map +1 -1
- package/dist/core/internal/engine.d.ts +35 -2
- package/dist/core/internal/engine.d.ts.map +1 -1
- package/dist/core/internal/engine.js +12 -1
- package/dist/core/internal/engine.js.map +1 -1
- package/dist/core/internal/hash.d.ts +10 -0
- package/dist/core/internal/hash.d.ts.map +1 -1
- package/dist/core/internal/hash.js +26 -1
- package/dist/core/internal/hash.js.map +1 -1
- package/dist/index.d.ts +23 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -14
- package/dist/index.js.map +1 -1
- package/dist/node/Engine.d.ts +1 -1
- package/dist/node/Engine.d.ts.map +1 -1
- package/dist/node/Engine.js.map +1 -1
- package/dist/node/Hash.d.ts +6 -4
- package/dist/node/Hash.d.ts.map +1 -1
- package/dist/node/Hash.js +35 -3
- package/dist/node/Hash.js.map +1 -1
- package/dist/tempo/AuthorizationTempo.d.ts +6 -6
- package/dist/tempo/AuthorizationTempo.js +6 -6
- package/dist/tempo/KeyAuthorization.d.ts +3 -8
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +3 -8
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +8 -8
- package/dist/tempo/SignatureEnvelope.js +8 -8
- package/dist/trusted-setups/Paths.d.ts +1 -0
- package/dist/trusted-setups/Paths.d.ts.map +1 -1
- package/dist/trusted-setups/Paths.js +1 -0
- package/dist/trusted-setups/Paths.js.map +1 -1
- package/dist/trusted-setups/Setups.d.ts +35 -0
- package/dist/trusted-setups/Setups.d.ts.map +1 -0
- package/dist/trusted-setups/Setups.js +29 -0
- package/dist/trusted-setups/Setups.js.map +1 -0
- package/dist/trusted-setups/index.d.ts +20 -0
- package/dist/trusted-setups/index.d.ts.map +1 -1
- package/dist/trusted-setups/index.js +20 -0
- package/dist/trusted-setups/index.js.map +1 -1
- package/dist/trusted-setups/internal/paths.d.ts.map +1 -1
- package/dist/trusted-setups/internal/paths.js +1 -1
- package/dist/trusted-setups/internal/paths.js.map +1 -1
- package/dist/trusted-setups/internal/setups/mainnet.d.ts +7 -0
- package/dist/trusted-setups/internal/setups/mainnet.d.ts.map +1 -0
- package/dist/trusted-setups/internal/setups/mainnet.js +11 -0
- package/dist/trusted-setups/internal/setups/mainnet.js.map +1 -0
- package/dist/wasm/Engine.d.ts +4 -3
- package/dist/wasm/Engine.d.ts.map +1 -1
- package/dist/wasm/Engine.js +5 -5
- package/dist/wasm/Engine.js.map +1 -1
- package/dist/wasm/Hash.d.ts +1 -1
- package/dist/wasm/Hash.d.ts.map +1 -1
- package/dist/wasm/Hash.js +5 -0
- package/dist/wasm/Hash.js.map +1 -1
- package/dist/wasm/Keystore.d.ts +23 -9
- package/dist/wasm/Keystore.d.ts.map +1 -1
- package/dist/wasm/Keystore.js +30 -13
- package/dist/wasm/Keystore.js.map +1 -1
- package/dist/wasm/Kzg.d.ts +112 -0
- package/dist/wasm/Kzg.d.ts.map +1 -0
- package/dist/wasm/Kzg.js +333 -0
- package/dist/wasm/Kzg.js.map +1 -0
- package/dist/wasm/Secp256k1.d.ts +55 -0
- package/dist/wasm/Secp256k1.d.ts.map +1 -0
- package/dist/wasm/Secp256k1.js +181 -0
- package/dist/wasm/Secp256k1.js.map +1 -0
- package/dist/wasm/index.d.ts +44 -1
- package/dist/wasm/index.d.ts.map +1 -1
- package/dist/wasm/index.js +44 -1
- package/dist/wasm/index.js.map +1 -1
- package/dist/wasm/internal/blake3.d.ts +10 -1
- package/dist/wasm/internal/blake3.d.ts.map +1 -1
- package/dist/wasm/internal/blake3.js +12 -1
- package/dist/wasm/internal/blake3.js.map +1 -1
- package/dist/wasm/internal/blake3.wasm.d.ts +3 -1
- package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/blake3.wasm.js +3 -1
- package/dist/wasm/internal/blake3.wasm.js.map +1 -1
- package/dist/wasm/internal/hash.d.ts +9 -0
- package/dist/wasm/internal/hash.d.ts.map +1 -1
- package/dist/wasm/internal/hash.js +13 -1
- package/dist/wasm/internal/hash.js.map +1 -1
- package/dist/wasm/internal/hashState.d.ts +25 -0
- package/dist/wasm/internal/hashState.d.ts.map +1 -0
- package/dist/wasm/internal/hashState.js +105 -0
- package/dist/wasm/internal/hashState.js.map +1 -0
- package/dist/wasm/internal/hashes.d.ts +12 -1
- package/dist/wasm/internal/hashes.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.js +18 -1
- package/dist/wasm/internal/hashes.js.map +1 -1
- package/dist/wasm/internal/hashes.wasm.d.ts +11 -3
- package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.wasm.js +11 -3
- package/dist/wasm/internal/hashes.wasm.js.map +1 -1
- package/dist/wasm/internal/instantiate.d.ts +12 -0
- package/dist/wasm/internal/instantiate.d.ts.map +1 -1
- package/dist/wasm/internal/instantiate.js +23 -7
- package/dist/wasm/internal/instantiate.js.map +1 -1
- package/dist/wasm/internal/keystore.d.ts +10 -0
- package/dist/wasm/internal/keystore.d.ts.map +1 -0
- package/dist/wasm/internal/keystore.js +10 -0
- package/dist/wasm/internal/keystore.js.map +1 -0
- package/dist/wasm/internal/kzg.d.ts +17 -0
- package/dist/wasm/internal/kzg.d.ts.map +1 -0
- package/dist/wasm/internal/kzg.js +8 -0
- package/dist/wasm/internal/kzg.js.map +1 -0
- package/dist/wasm/internal/kzg.wasm.d.ts +3 -0
- package/dist/wasm/internal/kzg.wasm.d.ts.map +1 -0
- package/dist/wasm/internal/kzg.wasm.js +10 -0
- package/dist/wasm/internal/kzg.wasm.js.map +1 -0
- package/dist/wasm/internal/scrypt.d.ts +16 -0
- package/dist/wasm/internal/scrypt.d.ts.map +1 -0
- package/dist/wasm/internal/scrypt.js +78 -0
- package/dist/wasm/internal/scrypt.js.map +1 -0
- package/dist/wasm/internal/scrypt.wasm.d.ts +7 -0
- package/dist/wasm/internal/scrypt.wasm.d.ts.map +1 -0
- package/dist/wasm/internal/scrypt.wasm.js +14 -0
- package/dist/wasm/internal/scrypt.wasm.js.map +1 -0
- package/dist/wasm/internal/secp256k1.d.ts +16 -0
- package/dist/wasm/internal/secp256k1.d.ts.map +1 -0
- package/dist/wasm/internal/secp256k1.js +20 -0
- package/dist/wasm/internal/secp256k1.js.map +1 -0
- package/dist/wasm/internal/secp256k1.wasm.d.ts +3 -0
- package/dist/wasm/internal/secp256k1.wasm.d.ts.map +1 -0
- package/dist/wasm/internal/secp256k1.wasm.js +10 -0
- package/dist/wasm/internal/secp256k1.wasm.js.map +1 -0
- package/dist/webauthn/Authentication.d.ts +2 -0
- package/dist/webauthn/Authentication.d.ts.map +1 -1
- package/dist/webauthn/Authentication.js +2 -1
- package/dist/webauthn/Authentication.js.map +1 -1
- package/dist/webauthn/Registration.d.ts.map +1 -1
- package/dist/webauthn/Registration.js +2 -1
- package/dist/webauthn/Registration.js.map +1 -1
- package/dist/webauthn/Types.d.ts +27 -6
- package/dist/webauthn/Types.d.ts.map +1 -1
- package/dist/webauthn/internal/utils.d.ts.map +1 -1
- package/dist/webauthn/internal/utils.js +35 -9
- package/dist/webauthn/internal/utils.js.map +1 -1
- package/dist/zod/TypedData.d.ts +2 -2
- package/package.json +27 -2
- package/src/benchmarks/Ox.bench.ts +6 -0
- package/src/benchmarks/OxNode.bench.ts +8 -0
- package/src/benchmarks/OxV0.bench.ts +4 -0
- package/src/benchmarks/OxWasm.bench.ts +22 -0
- package/src/core/AbiFunction.ts +5 -5
- package/src/core/AbiParameters.ts +8 -20
- package/src/core/AesGcm.ts +86 -1
- package/src/core/Ed25519.ts +87 -1
- package/src/core/Engine.ts +1 -0
- package/src/core/Hash.ts +321 -1
- package/src/core/Hex.ts +1 -4
- package/src/core/Rlp.ts +172 -5
- package/src/core/Secp256k1.ts +92 -1
- package/src/core/WebAuthn.ts +579 -0
- package/src/core/WebAuthnP256.ts +47 -50
- package/src/core/_test/AbiFunction.test.ts +9 -0
- package/src/core/_test/AbiParameters.differential.fuzz.ts +156 -0
- package/src/core/_test/AbiParameters.encode.test.ts +22 -0
- package/src/core/_test/AbiParameters.fuzz.ts +4 -0
- package/src/core/_test/AesGcm.test.ts +76 -0
- package/src/core/_test/Block.test.ts +9 -2
- package/src/core/_test/Ed25519.test-d.ts +13 -1
- package/src/core/_test/Ed25519.test.ts +120 -1
- package/src/core/_test/Engine.test-d.ts +9 -0
- package/src/core/_test/Engine.test.ts +1 -1
- package/src/core/_test/Hash.test-d.ts +41 -0
- package/src/core/_test/Hash.test.ts +278 -1
- package/src/core/_test/Hash.vectors.test.ts +1 -2
- package/src/core/_test/Hex.test.ts +2 -0
- package/src/core/_test/Rlp.test-d.ts +18 -0
- package/src/core/_test/Rlp.test.ts +109 -0
- package/src/core/_test/Secp256k1.test-d.ts +14 -0
- package/src/core/_test/Secp256k1.test.ts +91 -1
- package/src/core/_test/Transaction.test.ts +11 -2
- package/src/core/_test/WebAuthn.test-d.ts +142 -0
- package/src/core/_test/WebAuthn.test.ts +766 -0
- package/src/core/_test/index.test.ts +1 -0
- package/src/core/internal/abiParameters.ts +466 -326
- package/src/core/internal/engine.ts +47 -2
- package/src/core/internal/hash.ts +53 -1
- package/src/index.ts +24 -14
- package/src/node/Engine.ts +1 -0
- package/src/node/Hash.ts +43 -6
- package/src/node/_test/Engine.test-d.ts +1 -0
- package/src/node/_test/Engine.test.ts +2 -0
- package/src/node/_test/Hash.test-d.ts +11 -0
- package/src/node/_test/Hash.test.ts +46 -0
- package/src/tempo/AuthorizationTempo.ts +6 -6
- package/src/tempo/KeyAuthorization.ts +3 -8
- package/src/tempo/SignatureEnvelope.ts +8 -8
- package/src/trusted-setups/Paths.ts +1 -0
- package/src/trusted-setups/README.md +39 -0
- package/src/trusted-setups/Setups.ts +46 -0
- package/src/trusted-setups/_test/Paths.test.ts +16 -0
- package/src/trusted-setups/_test/Setups.test-d.ts +7 -0
- package/src/trusted-setups/_test/Setups.test.ts +43 -0
- package/src/trusted-setups/_test/index.test.ts +1 -0
- package/src/trusted-setups/index.ts +21 -0
- package/src/trusted-setups/internal/paths.ts +4 -1
- package/src/trusted-setups/internal/setups/mainnet.source.json +7 -0
- package/src/trusted-setups/internal/setups/mainnet.ts +16 -0
- package/src/version.ts +1 -1
- package/src/wasm/Engine.ts +9 -6
- package/src/wasm/Hash.ts +10 -0
- package/src/wasm/Keystore.bench.ts +26 -0
- package/src/wasm/Keystore.ts +32 -14
- package/src/wasm/Kzg.bench.ts +63 -0
- package/src/wasm/Kzg.ts +518 -0
- package/src/wasm/Secp256k1.bench.ts +79 -0
- package/src/wasm/Secp256k1.ts +248 -0
- package/src/wasm/_test/Engine.test-d.ts +2 -0
- package/src/wasm/_test/Engine.test.ts +5 -0
- package/src/wasm/_test/Hash.browser.test.ts +31 -0
- package/src/wasm/_test/Hash.test-d.ts +17 -0
- package/src/wasm/_test/Hash.test.ts +252 -3
- package/src/wasm/_test/Keystore.browser.test.ts +31 -0
- package/src/wasm/_test/Keystore.fuzz.ts +50 -0
- package/src/wasm/_test/Keystore.test-d.ts +10 -1
- package/src/wasm/_test/Keystore.test.ts +289 -4
- package/src/wasm/_test/Kzg.test-d.ts +19 -0
- package/src/wasm/_test/Kzg.test.ts +220 -0
- package/src/wasm/_test/Runtime.test.ts +9 -0
- package/src/wasm/_test/Secp256k1.test-d.ts +35 -0
- package/src/wasm/_test/Secp256k1.test.ts +354 -0
- package/src/wasm/index.ts +46 -1
- package/src/wasm/internal/blake3.ts +23 -2
- package/src/wasm/internal/blake3.wasm.ts +4 -1
- package/src/wasm/internal/hash.ts +27 -1
- package/src/wasm/internal/hashState.ts +154 -0
- package/src/wasm/internal/hashes.ts +56 -15
- package/src/wasm/internal/hashes.wasm.ts +15 -3
- package/src/wasm/internal/instantiate.ts +29 -9
- package/src/wasm/internal/keystore.ts +19 -0
- package/src/wasm/internal/kzg.ts +50 -0
- package/src/wasm/internal/kzg.wasm.ts +11 -0
- package/src/wasm/internal/scrypt.ts +131 -0
- package/src/wasm/internal/scrypt.wasm.ts +17 -0
- package/src/wasm/internal/secp256k1.ts +62 -0
- package/src/wasm/internal/secp256k1.wasm.ts +11 -0
- package/src/webauthn/Authentication.ts +4 -0
- package/src/webauthn/Registration.ts +2 -0
- package/src/webauthn/Types.ts +32 -2
- package/src/webauthn/_test/Authentication.test.ts +123 -1
- package/src/webauthn/_test/Registration.test.ts +26 -6
- package/src/webauthn/_test/WebAuthn.browser.test.ts +28 -0
- package/src/webauthn/internal/utils.ts +41 -8
- package/wasm/vendor/c-kzg-4844/LICENSE +201 -0
- package/wasm/vendor/c-kzg-4844/blst/LICENSE +201 -0
- package/src/trusted-setups/internal/setups/mainnet.txt +0 -4163
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import type * as Engine from '../core/Engine.js'
|
|
2
|
+
import * as Errors from '../core/Errors.js'
|
|
3
|
+
import * as internal from './internal/instantiate.js'
|
|
4
|
+
import * as secp256k1 from './internal/secp256k1.js'
|
|
5
|
+
|
|
6
|
+
export * from '../core/Secp256k1.js'
|
|
7
|
+
export { MemoryError } from './internal/instantiate.js'
|
|
8
|
+
|
|
9
|
+
const privateKeySize = 32
|
|
10
|
+
const publicKeySize = 65
|
|
11
|
+
const sharedSecretSize = 33
|
|
12
|
+
const compactSignatureSize = 64
|
|
13
|
+
const recoveredSignatureSize = 65
|
|
14
|
+
const maxRawMessageSize = 8192
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Compiles WASM implementations of deterministic
|
|
18
|
+
* [`Secp256k1`](/api/Secp256k1) primitives, without installing them.
|
|
19
|
+
*
|
|
20
|
+
* Random key generation remains on Ox's host-backed default implementation.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts twoslash
|
|
24
|
+
* // @noErrors
|
|
25
|
+
* import { Engine } from 'ox'
|
|
26
|
+
* import { Secp256k1 } from 'ox/wasm'
|
|
27
|
+
*
|
|
28
|
+
* await Engine.install({ Secp256k1: Secp256k1.engine() })
|
|
29
|
+
*
|
|
30
|
+
* Secp256k1.getPublicKey({ privateKey: '0x...' })
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @returns The WASM implementation of the deterministic `Secp256k1` primitives.
|
|
34
|
+
*/
|
|
35
|
+
export async function engine(): Promise<engine.ReturnType> {
|
|
36
|
+
const module = await secp256k1.load()
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
getPublicKey(privateKey) {
|
|
40
|
+
assertLength(privateKey, privateKeySize, 'private key')
|
|
41
|
+
const size = privateKeySize + publicKeySize
|
|
42
|
+
module.reserve(size)
|
|
43
|
+
const privateKeyPtr = module.heapBase
|
|
44
|
+
const publicKeyPtr = privateKeyPtr + privateKeySize
|
|
45
|
+
try {
|
|
46
|
+
module.view().set(privateKey, privateKeyPtr)
|
|
47
|
+
if (
|
|
48
|
+
module.exports.secp256k1_get_public_key(
|
|
49
|
+
privateKeyPtr,
|
|
50
|
+
publicKeyPtr,
|
|
51
|
+
) !== 1
|
|
52
|
+
)
|
|
53
|
+
throw new InvalidInputError({ operation: 'getPublicKey' })
|
|
54
|
+
return module.view().slice(publicKeyPtr, publicKeyPtr + publicKeySize)
|
|
55
|
+
} finally {
|
|
56
|
+
module.exports.zero(privateKeyPtr, size)
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
getSharedSecret(privateKey, publicKey) {
|
|
60
|
+
assertLength(privateKey, privateKeySize, 'private key')
|
|
61
|
+
assertPublicKeyLength(publicKey)
|
|
62
|
+
const size = privateKeySize + publicKey.length + sharedSecretSize
|
|
63
|
+
module.reserve(size)
|
|
64
|
+
const privateKeyPtr = module.heapBase
|
|
65
|
+
const publicKeyPtr = privateKeyPtr + privateKeySize
|
|
66
|
+
const sharedSecretPtr = publicKeyPtr + publicKey.length
|
|
67
|
+
try {
|
|
68
|
+
const memory = module.view()
|
|
69
|
+
memory.set(privateKey, privateKeyPtr)
|
|
70
|
+
memory.set(publicKey, publicKeyPtr)
|
|
71
|
+
if (
|
|
72
|
+
module.exports.secp256k1_get_shared_secret(
|
|
73
|
+
privateKeyPtr,
|
|
74
|
+
publicKeyPtr,
|
|
75
|
+
publicKey.length,
|
|
76
|
+
sharedSecretPtr,
|
|
77
|
+
) !== 1
|
|
78
|
+
)
|
|
79
|
+
throw new InvalidInputError({ operation: 'getSharedSecret' })
|
|
80
|
+
return module
|
|
81
|
+
.view()
|
|
82
|
+
.slice(sharedSecretPtr, sharedSecretPtr + sharedSecretSize)
|
|
83
|
+
} finally {
|
|
84
|
+
module.exports.zero(privateKeyPtr, size)
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
recoverPublicKey(signature, payload) {
|
|
88
|
+
assertLength(signature, recoveredSignatureSize, 'signature')
|
|
89
|
+
assertRawMessageLength(payload)
|
|
90
|
+
const size = recoveredSignatureSize + payload.length + publicKeySize
|
|
91
|
+
module.reserve(size)
|
|
92
|
+
const signaturePtr = module.heapBase
|
|
93
|
+
const payloadPtr = signaturePtr + recoveredSignatureSize
|
|
94
|
+
const publicKeyPtr = payloadPtr + payload.length
|
|
95
|
+
try {
|
|
96
|
+
const memory = module.view()
|
|
97
|
+
memory.set(signature, signaturePtr)
|
|
98
|
+
memory.set(payload, payloadPtr)
|
|
99
|
+
if (
|
|
100
|
+
module.exports.secp256k1_recover_public_key(
|
|
101
|
+
signaturePtr,
|
|
102
|
+
payloadPtr,
|
|
103
|
+
payload.length,
|
|
104
|
+
publicKeyPtr,
|
|
105
|
+
) !== 1
|
|
106
|
+
)
|
|
107
|
+
throw new InvalidInputError({ operation: 'recoverPublicKey' })
|
|
108
|
+
return module.view().slice(publicKeyPtr, publicKeyPtr + publicKeySize)
|
|
109
|
+
} finally {
|
|
110
|
+
module.exports.zero(signaturePtr, size)
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
sign(payload, privateKey, options) {
|
|
114
|
+
assertLength(privateKey, privateKeySize, 'private key')
|
|
115
|
+
if (!options.prehash) assertRawMessageLength(payload)
|
|
116
|
+
const entropy =
|
|
117
|
+
options.extraEntropy === true
|
|
118
|
+
? crypto.getRandomValues(new Uint8Array(privateKeySize))
|
|
119
|
+
: options.extraEntropy === false
|
|
120
|
+
? undefined
|
|
121
|
+
: options.extraEntropy
|
|
122
|
+
const entropySize = entropy?.length ?? 0
|
|
123
|
+
const size =
|
|
124
|
+
payload.length + privateKeySize + entropySize + recoveredSignatureSize
|
|
125
|
+
module.reserve(size)
|
|
126
|
+
const payloadPtr = module.heapBase
|
|
127
|
+
const privateKeyPtr = payloadPtr + payload.length
|
|
128
|
+
const entropyPtr = entropy ? privateKeyPtr + privateKeySize : 0
|
|
129
|
+
const signaturePtr = privateKeyPtr + privateKeySize + entropySize
|
|
130
|
+
try {
|
|
131
|
+
const memory = module.view()
|
|
132
|
+
memory.set(payload, payloadPtr)
|
|
133
|
+
memory.set(privateKey, privateKeyPtr)
|
|
134
|
+
if (entropy) memory.set(entropy, entropyPtr)
|
|
135
|
+
if (
|
|
136
|
+
module.exports.secp256k1_sign(
|
|
137
|
+
payloadPtr,
|
|
138
|
+
payload.length,
|
|
139
|
+
privateKeyPtr,
|
|
140
|
+
entropyPtr,
|
|
141
|
+
entropySize,
|
|
142
|
+
Number(options.prehash),
|
|
143
|
+
signaturePtr,
|
|
144
|
+
) !== 1
|
|
145
|
+
)
|
|
146
|
+
throw new InvalidInputError({ operation: 'sign' })
|
|
147
|
+
return module
|
|
148
|
+
.view()
|
|
149
|
+
.slice(signaturePtr, signaturePtr + recoveredSignatureSize)
|
|
150
|
+
} finally {
|
|
151
|
+
module.exports.zero(payloadPtr, size)
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
verify(signature, payload, publicKey, options) {
|
|
155
|
+
assertLength(signature, compactSignatureSize, 'signature')
|
|
156
|
+
assertPublicKeyLength(publicKey)
|
|
157
|
+
if (!options.prehash && payload.length > maxRawMessageSize) return false
|
|
158
|
+
const size = compactSignatureSize + payload.length + publicKey.length
|
|
159
|
+
module.reserve(size)
|
|
160
|
+
const signaturePtr = module.heapBase
|
|
161
|
+
const payloadPtr = signaturePtr + compactSignatureSize
|
|
162
|
+
const publicKeyPtr = payloadPtr + payload.length
|
|
163
|
+
try {
|
|
164
|
+
const memory = module.view()
|
|
165
|
+
memory.set(signature, signaturePtr)
|
|
166
|
+
memory.set(payload, payloadPtr)
|
|
167
|
+
memory.set(publicKey, publicKeyPtr)
|
|
168
|
+
return (
|
|
169
|
+
module.exports.secp256k1_verify(
|
|
170
|
+
signaturePtr,
|
|
171
|
+
payloadPtr,
|
|
172
|
+
payload.length,
|
|
173
|
+
publicKeyPtr,
|
|
174
|
+
publicKey.length,
|
|
175
|
+
Number(options.prehash),
|
|
176
|
+
) === 1
|
|
177
|
+
)
|
|
178
|
+
} finally {
|
|
179
|
+
module.exports.zero(signaturePtr, size)
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export declare namespace engine {
|
|
186
|
+
/** Every `Secp256k1` primitive this module implements. */
|
|
187
|
+
type ReturnType = {
|
|
188
|
+
[key in
|
|
189
|
+
| 'getPublicKey'
|
|
190
|
+
| 'getSharedSecret'
|
|
191
|
+
| 'recoverPublicKey'
|
|
192
|
+
| 'sign'
|
|
193
|
+
| 'verify']-?: NonNullable<Engine.Ecdsa[key]>
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
type ErrorType =
|
|
197
|
+
| InvalidInputError
|
|
198
|
+
| internal.MemoryError
|
|
199
|
+
| Errors.GlobalErrorType
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function assertLength(value: Uint8Array, length: number, name: string): void {
|
|
203
|
+
if (value.length !== length)
|
|
204
|
+
throw new RangeError(
|
|
205
|
+
`Secp256k1 ${name} must be ${length} bytes, got ${value.length}`,
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function assertPublicKeyLength(publicKey: Uint8Array): void {
|
|
210
|
+
if (
|
|
211
|
+
publicKey.length !== sharedSecretSize &&
|
|
212
|
+
publicKey.length !== publicKeySize
|
|
213
|
+
)
|
|
214
|
+
throw new RangeError(
|
|
215
|
+
`Secp256k1 public key must be 33 or 65 bytes, got ${publicKey.length}`,
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function assertRawMessageLength(payload: Uint8Array): void {
|
|
220
|
+
if (payload.length > maxRawMessageSize)
|
|
221
|
+
throw new RangeError(
|
|
222
|
+
`Secp256k1 unhashed payload must not exceed ${maxRawMessageSize} bytes, got ${payload.length}`,
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Thrown when libsecp256k1 rejects a key or recovered signature.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts twoslash
|
|
231
|
+
* import { Secp256k1 } from 'ox/wasm'
|
|
232
|
+
*
|
|
233
|
+
* try {
|
|
234
|
+
* const engine = await Secp256k1.engine()
|
|
235
|
+
* engine.getPublicKey(new Uint8Array(32))
|
|
236
|
+
* } catch (error) {
|
|
237
|
+
* if (error instanceof Secp256k1.InvalidInputError)
|
|
238
|
+
* console.error(error.message)
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
export class InvalidInputError extends Errors.BaseError {
|
|
243
|
+
override readonly name = 'Secp256k1.InvalidInputError'
|
|
244
|
+
|
|
245
|
+
constructor({ operation }: { operation: string }) {
|
|
246
|
+
super(`WASM secp256k1 ${operation} received invalid input.`)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -10,9 +10,11 @@ test('install and engine expose the same precise engine', () => {
|
|
|
10
10
|
expectTypeOf<Installed['Hash']['sha256']>().toEqualTypeOf<
|
|
11
11
|
(input: Uint8Array) => Uint8Array
|
|
12
12
|
>()
|
|
13
|
+
expectTypeOf<Installed['Keystore']>().not.toHaveProperty('scrypt')
|
|
13
14
|
})
|
|
14
15
|
|
|
15
16
|
test('the WASM Engine namespace exposes synchronous core operations', () => {
|
|
17
|
+
expectTypeOf<Engine.HashState>().toEqualTypeOf<CoreEngine.HashState>()
|
|
16
18
|
expectTypeOf(Engine.get).toEqualTypeOf(CoreEngine.get)
|
|
17
19
|
expectTypeOf(Engine.InvalidSlotValueError).toEqualTypeOf(
|
|
18
20
|
CoreEngine.InvalidSlotValueError,
|
|
@@ -27,6 +27,28 @@ describe('engine', () => {
|
|
|
27
27
|
}
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
+
test('behavior: incremental states clone and cross block boundaries', async () => {
|
|
31
|
+
const engine = await WasmHash.engine()
|
|
32
|
+
const prefix = new Uint8Array(137).fill(1)
|
|
33
|
+
const left = new Uint8Array(1025).fill(2)
|
|
34
|
+
const right = new Uint8Array(65).fill(3)
|
|
35
|
+
const state = engine.createBlake3()
|
|
36
|
+
state.update(prefix.subarray(0, 1))
|
|
37
|
+
state.update(prefix.subarray(1, 136))
|
|
38
|
+
state.update(prefix.subarray(136))
|
|
39
|
+
const clone = state.clone()
|
|
40
|
+
state.update(left)
|
|
41
|
+
clone.update(right)
|
|
42
|
+
|
|
43
|
+
const output = new Uint8Array(32)
|
|
44
|
+
state.digestInto(output)
|
|
45
|
+
expect(output).toEqual(blake3(new Uint8Array([...prefix, ...left])))
|
|
46
|
+
|
|
47
|
+
const clonedOutput = new Uint8Array(32)
|
|
48
|
+
clone.digestInto(clonedOutput)
|
|
49
|
+
expect(clonedOutput).toEqual(blake3(new Uint8Array([...prefix, ...right])))
|
|
50
|
+
})
|
|
51
|
+
|
|
30
52
|
test('behavior: grows memory in a real browser, then hashes a small input', async () => {
|
|
31
53
|
const engine = await WasmHash.engine()
|
|
32
54
|
|
|
@@ -44,9 +66,18 @@ describe('engine', () => {
|
|
|
44
66
|
test('behavior: ox uses the WASM implementation once installed', async () => {
|
|
45
67
|
await Engine.install({ Hash: WasmHash.engine() })
|
|
46
68
|
try {
|
|
69
|
+
expect(Hash.blake3('0xdeadbeef')).toBe(
|
|
70
|
+
'0x53147f3ce49ed4f60dfa5b9654c36ba6103c11f5737df3dabd4cbd296c4161bd',
|
|
71
|
+
)
|
|
47
72
|
expect(Hash.keccak256('0xdeadbeef')).toBe(
|
|
48
73
|
'0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1',
|
|
49
74
|
)
|
|
75
|
+
const state = Hash.createKeccak256()
|
|
76
|
+
state.update('0xdead')
|
|
77
|
+
state.update('0xbeef')
|
|
78
|
+
expect(state.digest()).toBe(
|
|
79
|
+
'0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1',
|
|
80
|
+
)
|
|
50
81
|
} finally {
|
|
51
82
|
Engine.reset()
|
|
52
83
|
}
|
|
@@ -21,6 +21,21 @@ test('every primitive is present, so callers need no assertion', () => {
|
|
|
21
21
|
expectTypeOf<Slot['hmacSha256']>().toEqualTypeOf<
|
|
22
22
|
(key: Uint8Array, message: Uint8Array) => Uint8Array
|
|
23
23
|
>()
|
|
24
|
+
expectTypeOf<Slot['createBlake3']>().toEqualTypeOf<
|
|
25
|
+
() => CoreEngine.HashState
|
|
26
|
+
>()
|
|
27
|
+
expectTypeOf<Slot['createHmacSha256']>().toEqualTypeOf<
|
|
28
|
+
(key: Uint8Array) => CoreEngine.HashState
|
|
29
|
+
>()
|
|
30
|
+
expectTypeOf<Slot['createKeccak256']>().toEqualTypeOf<
|
|
31
|
+
() => CoreEngine.HashState
|
|
32
|
+
>()
|
|
33
|
+
expectTypeOf<Slot['createRipemd160']>().toEqualTypeOf<
|
|
34
|
+
() => CoreEngine.HashState
|
|
35
|
+
>()
|
|
36
|
+
expectTypeOf<Slot['createSha256']>().toEqualTypeOf<
|
|
37
|
+
() => CoreEngine.HashState
|
|
38
|
+
>()
|
|
24
39
|
})
|
|
25
40
|
|
|
26
41
|
test('the result is the raw slot, so `Engine.install` accepts it', () => {
|
|
@@ -28,6 +43,8 @@ test('the result is the raw slot, so `Engine.install` accepts it', () => {
|
|
|
28
43
|
})
|
|
29
44
|
|
|
30
45
|
test('the WASM namespace exposes the public Hash API', () => {
|
|
46
|
+
expectTypeOf(WasmHash.blake3).toEqualTypeOf(CoreHash.blake3)
|
|
47
|
+
expectTypeOf(WasmHash.createBlake3).toEqualTypeOf(CoreHash.createBlake3)
|
|
31
48
|
expectTypeOf(WasmHash.sha256).toEqualTypeOf(CoreHash.sha256)
|
|
32
49
|
expectTypeOf<typeof WasmHash>().not.toHaveProperty('create')
|
|
33
50
|
})
|
|
@@ -8,8 +8,14 @@ import { Hash as WasmHash } from 'ox/wasm'
|
|
|
8
8
|
import { beforeAll, describe, expect, test } from 'vp/test'
|
|
9
9
|
import { wasmBase64 as blake3WasmBase64 } from '../internal/blake3.wasm.js'
|
|
10
10
|
import * as blake3_internal from '../internal/blake3.js'
|
|
11
|
-
import {
|
|
11
|
+
import { blake3StateSize } from '../internal/blake3.wasm.js'
|
|
12
|
+
import {
|
|
13
|
+
hmacSha256ScratchSize,
|
|
14
|
+
hmacSha256StateSize,
|
|
15
|
+
wasmBase64,
|
|
16
|
+
} from '../internal/hashes.wasm.js'
|
|
12
17
|
import * as hash from '../internal/hash.js'
|
|
18
|
+
import * as hashes_internal from '../internal/hashes.js'
|
|
13
19
|
import * as internal from '../internal/instantiate.js'
|
|
14
20
|
|
|
15
21
|
let engine: WasmHash.engine.ReturnType
|
|
@@ -23,6 +29,11 @@ describe('engine', () => {
|
|
|
23
29
|
expect(Object.keys(await WasmHash.engine())).toMatchInlineSnapshot(`
|
|
24
30
|
[
|
|
25
31
|
"blake3",
|
|
32
|
+
"createBlake3",
|
|
33
|
+
"createHmacSha256",
|
|
34
|
+
"createKeccak256",
|
|
35
|
+
"createRipemd160",
|
|
36
|
+
"createSha256",
|
|
26
37
|
"hmacSha256",
|
|
27
38
|
"keccak256",
|
|
28
39
|
"ripemd160",
|
|
@@ -58,6 +69,79 @@ function input(size: number) {
|
|
|
58
69
|
return new Uint8Array(size).map((_, index) => (index * 37 + 11) & 0xff)
|
|
59
70
|
}
|
|
60
71
|
|
|
72
|
+
type HashState = ReturnType<WasmHash.engine.ReturnType['createSha256']>
|
|
73
|
+
|
|
74
|
+
type IncrementalCase = {
|
|
75
|
+
create: () => HashState
|
|
76
|
+
digestSize: number
|
|
77
|
+
name: string
|
|
78
|
+
oneShot: (input: Uint8Array) => Uint8Array
|
|
79
|
+
wasmOneShot: (input: Uint8Array) => Uint8Array
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function concat(...values: readonly Uint8Array[]) {
|
|
83
|
+
const output = new Uint8Array(
|
|
84
|
+
values.reduce((length, value) => length + value.length, 0),
|
|
85
|
+
)
|
|
86
|
+
let offset = 0
|
|
87
|
+
for (const value of values) {
|
|
88
|
+
output.set(value, offset)
|
|
89
|
+
offset += value.length
|
|
90
|
+
}
|
|
91
|
+
return output
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function align8(value: number) {
|
|
95
|
+
return Math.ceil(value / 8) * 8
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function digest(state: HashState, size: number) {
|
|
99
|
+
const output = new Uint8Array(size)
|
|
100
|
+
state.digestInto(output)
|
|
101
|
+
return output
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function incrementalCases(): readonly IncrementalCase[] {
|
|
105
|
+
const key = input(100)
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
create: () => engine.createBlake3(),
|
|
109
|
+
digestSize: 32,
|
|
110
|
+
name: 'blake3',
|
|
111
|
+
oneShot: blake3,
|
|
112
|
+
wasmOneShot: (value) => engine.blake3(value),
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
create: () => engine.createHmacSha256(key),
|
|
116
|
+
digestSize: 32,
|
|
117
|
+
name: 'hmacSha256',
|
|
118
|
+
oneShot: (value) => hmac(sha256, key, value),
|
|
119
|
+
wasmOneShot: (value) => engine.hmacSha256(key, value),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
create: () => engine.createKeccak256(),
|
|
123
|
+
digestSize: 32,
|
|
124
|
+
name: 'keccak256',
|
|
125
|
+
oneShot: keccak_256,
|
|
126
|
+
wasmOneShot: (value) => engine.keccak256(value),
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
create: () => engine.createRipemd160(),
|
|
130
|
+
digestSize: 20,
|
|
131
|
+
name: 'ripemd160',
|
|
132
|
+
oneShot: ripemd160,
|
|
133
|
+
wasmOneShot: (value) => engine.ripemd160(value),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
create: () => engine.createSha256(),
|
|
137
|
+
digestSize: 32,
|
|
138
|
+
name: 'sha256',
|
|
139
|
+
oneShot: sha256,
|
|
140
|
+
wasmOneShot: (value) => engine.sha256(value),
|
|
141
|
+
},
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
|
|
61
145
|
describe('Hash', () => {
|
|
62
146
|
test.each(sizes)('blake3 matches the default at %i bytes', (size) => {
|
|
63
147
|
expect(engine.blake3(input(size))).toEqual(blake3(input(size)))
|
|
@@ -86,6 +170,97 @@ describe('Hash', () => {
|
|
|
86
170
|
},
|
|
87
171
|
)
|
|
88
172
|
|
|
173
|
+
test.each(incrementalCases())(
|
|
174
|
+
'$name matches arbitrary chunk boundaries',
|
|
175
|
+
({ create, digestSize, oneShot }) => {
|
|
176
|
+
const message = input(4097)
|
|
177
|
+
const snapshot = message.slice()
|
|
178
|
+
const chunks = [0, 1, 7, 55, 64, 129, 1023, 136, 2]
|
|
179
|
+
const state = create()
|
|
180
|
+
let offset = 0
|
|
181
|
+
let index = 0
|
|
182
|
+
while (offset < message.length) {
|
|
183
|
+
const length = Math.min(
|
|
184
|
+
chunks[index++ % chunks.length]!,
|
|
185
|
+
message.length - offset,
|
|
186
|
+
)
|
|
187
|
+
state.update(message.subarray(offset, offset + length))
|
|
188
|
+
offset += length
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
expect(digest(state, digestSize)).toEqual(oneShot(message))
|
|
192
|
+
expect(message).toEqual(snapshot)
|
|
193
|
+
},
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
test.each(incrementalCases())(
|
|
197
|
+
'$name clones an independent prefix',
|
|
198
|
+
({ create, digestSize, oneShot }) => {
|
|
199
|
+
const prefix = input(137)
|
|
200
|
+
const left = input(63)
|
|
201
|
+
const right = input(1025)
|
|
202
|
+
const state = create()
|
|
203
|
+
state.update(prefix)
|
|
204
|
+
const clone = state.clone()
|
|
205
|
+
state.update(left)
|
|
206
|
+
clone.update(right)
|
|
207
|
+
|
|
208
|
+
expect(digest(state, digestSize)).toEqual(oneShot(concat(prefix, left)))
|
|
209
|
+
expect(digest(clone, digestSize)).toEqual(oneShot(concat(prefix, right)))
|
|
210
|
+
},
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
test.each(incrementalCases())(
|
|
214
|
+
'$name keeps interleaved states independent',
|
|
215
|
+
({ create, digestSize, oneShot }) => {
|
|
216
|
+
const a = input(2049)
|
|
217
|
+
const b = input(271)
|
|
218
|
+
const stateA = create()
|
|
219
|
+
const stateB = create()
|
|
220
|
+
|
|
221
|
+
stateA.update(a.subarray(0, 55))
|
|
222
|
+
stateB.update(b.subarray(0, 136))
|
|
223
|
+
stateA.update(a.subarray(55, 1024))
|
|
224
|
+
stateB.update(b.subarray(136))
|
|
225
|
+
stateA.update(a.subarray(1024))
|
|
226
|
+
|
|
227
|
+
expect(digest(stateB, digestSize)).toEqual(oneShot(b))
|
|
228
|
+
expect(digest(stateA, digestSize)).toEqual(oneShot(a))
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
test.each(incrementalCases())(
|
|
233
|
+
'$name survives one-shot calls through the shared module',
|
|
234
|
+
({ create, digestSize, oneShot, wasmOneShot }) => {
|
|
235
|
+
const message = input(1025)
|
|
236
|
+
const state = create()
|
|
237
|
+
state.update(message.subarray(0, 136))
|
|
238
|
+
|
|
239
|
+
expect(wasmOneShot(input(2049))).toEqual(oneShot(input(2049)))
|
|
240
|
+
|
|
241
|
+
state.update(message.subarray(136))
|
|
242
|
+
expect(digest(state, digestSize)).toEqual(oneShot(message))
|
|
243
|
+
},
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
test.each(incrementalCases())(
|
|
247
|
+
'$name consumes and clears its lifecycle',
|
|
248
|
+
({ create, digestSize, oneShot }) => {
|
|
249
|
+
const message = input(72)
|
|
250
|
+
const state = create()
|
|
251
|
+
state.update(message)
|
|
252
|
+
const output = new Uint8Array(digestSize + 7).fill(0xa5)
|
|
253
|
+
state.digestInto(output)
|
|
254
|
+
|
|
255
|
+
expect(output.subarray(0, digestSize)).toEqual(oneShot(message))
|
|
256
|
+
expect(output.subarray(digestSize)).toEqual(new Uint8Array(7).fill(0xa5))
|
|
257
|
+
expect(() => state.update(message)).toThrow('destroyed')
|
|
258
|
+
expect(() => state.clone()).toThrow('destroyed')
|
|
259
|
+
expect(() => state.digestInto(output)).toThrow('destroyed')
|
|
260
|
+
expect(() => state.destroy()).not.toThrow()
|
|
261
|
+
},
|
|
262
|
+
)
|
|
263
|
+
|
|
89
264
|
test('behavior: known vectors', () => {
|
|
90
265
|
expect(Bytes.toHex(engine.blake3(new Uint8Array(0)))).toBe(
|
|
91
266
|
'0xaf1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262',
|
|
@@ -134,6 +309,34 @@ describe('Hash', () => {
|
|
|
134
309
|
)
|
|
135
310
|
})
|
|
136
311
|
|
|
312
|
+
test('behavior: incremental blake3 clears every WASM workspace', async () => {
|
|
313
|
+
const module = await internal.instantiate<
|
|
314
|
+
blake3_internal.Exports & blake3_internal.StateExports
|
|
315
|
+
>(blake3WasmBase64)
|
|
316
|
+
const initEnd = align8(module.heapBase) + blake3StateSize
|
|
317
|
+
module.view().fill(0xa5, module.heapBase, initEnd)
|
|
318
|
+
const state = blake3_internal.create(module)
|
|
319
|
+
expect(module.view().slice(module.heapBase, initEnd)).toEqual(
|
|
320
|
+
new Uint8Array(initEnd - module.heapBase),
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
const message = input(1025)
|
|
324
|
+
const updateEnd = align8(module.heapBase + message.length) + blake3StateSize
|
|
325
|
+
state.update(message)
|
|
326
|
+
expect(module.view().slice(module.heapBase, updateEnd)).toEqual(
|
|
327
|
+
new Uint8Array(updateEnd - module.heapBase),
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
const output = new Uint8Array(32)
|
|
331
|
+
const finalizeEnd =
|
|
332
|
+
align8(module.heapBase) + blake3StateSize + output.length
|
|
333
|
+
state.digestInto(output)
|
|
334
|
+
expect(output).toEqual(blake3(message))
|
|
335
|
+
expect(module.view().slice(module.heapBase, finalizeEnd)).toEqual(
|
|
336
|
+
new Uint8Array(finalizeEnd - module.heapBase),
|
|
337
|
+
)
|
|
338
|
+
})
|
|
339
|
+
|
|
137
340
|
test('behavior: blake3 clears its complete region after a late trap', async () => {
|
|
138
341
|
const module =
|
|
139
342
|
await internal.instantiate<blake3_internal.Exports>(blake3WasmBase64)
|
|
@@ -215,6 +418,35 @@ describe('Hash', () => {
|
|
|
215
418
|
)
|
|
216
419
|
})
|
|
217
420
|
|
|
421
|
+
test('behavior: incremental hmacSha256 clears every WASM workspace', async () => {
|
|
422
|
+
const module =
|
|
423
|
+
await internal.instantiate<hashes_internal.Exports>(wasmBase64)
|
|
424
|
+
const key = input(100)
|
|
425
|
+
const initEnd = align8(module.heapBase + key.length) + hmacSha256StateSize
|
|
426
|
+
module.view().fill(0xa5, module.heapBase, initEnd)
|
|
427
|
+
const state = hash.createHmacSha256(module, key)
|
|
428
|
+
expect(module.view().slice(module.heapBase, initEnd)).toEqual(
|
|
429
|
+
new Uint8Array(initEnd - module.heapBase),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
const message = input(137)
|
|
433
|
+
const updateEnd =
|
|
434
|
+
align8(module.heapBase + message.length) + hmacSha256StateSize
|
|
435
|
+
state.update(message)
|
|
436
|
+
expect(module.view().slice(module.heapBase, updateEnd)).toEqual(
|
|
437
|
+
new Uint8Array(updateEnd - module.heapBase),
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
const output = new Uint8Array(32)
|
|
441
|
+
const finalizeEnd =
|
|
442
|
+
align8(module.heapBase) + hmacSha256StateSize + output.length
|
|
443
|
+
state.digestInto(output)
|
|
444
|
+
expect(output).toEqual(hmac(sha256, key, message))
|
|
445
|
+
expect(module.view().slice(module.heapBase, finalizeEnd)).toEqual(
|
|
446
|
+
new Uint8Array(finalizeEnd - module.heapBase),
|
|
447
|
+
)
|
|
448
|
+
})
|
|
449
|
+
|
|
218
450
|
test('behavior: hmacSha256 clears its complete region after a trap', async () => {
|
|
219
451
|
const module = await internal.instantiate<hash.Exports>(wasmBase64)
|
|
220
452
|
const key = input(120)
|
|
@@ -264,6 +496,23 @@ describe('Hash', () => {
|
|
|
264
496
|
)
|
|
265
497
|
})
|
|
266
498
|
|
|
499
|
+
test('behavior: streams a large total input through bounded memory', async () => {
|
|
500
|
+
const module =
|
|
501
|
+
await internal.instantiate<hashes_internal.Exports>(wasmBase64)
|
|
502
|
+
const state = hashes_internal.create(module, 'sha256')
|
|
503
|
+
const expected = sha256.create()
|
|
504
|
+
const chunk = input(64 * 1024)
|
|
505
|
+
const memorySize = module.view().length
|
|
506
|
+
|
|
507
|
+
for (let index = 0; index < 1024; index++) {
|
|
508
|
+
state.update(chunk)
|
|
509
|
+
expected.update(chunk)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
expect(module.view().length).toBe(memorySize)
|
|
513
|
+
expect(digest(state, 32)).toEqual(expected.digest())
|
|
514
|
+
}, 60_000)
|
|
515
|
+
|
|
267
516
|
test('behavior: consecutive calls do not corrupt each other', () => {
|
|
268
517
|
const a = input(200)
|
|
269
518
|
const b = input(7)
|
|
@@ -292,8 +541,8 @@ describe('Engine.install', () => {
|
|
|
292
541
|
test('behavior: ox uses the WASM implementation once installed', async () => {
|
|
293
542
|
await Engine.install({ Hash: engine })
|
|
294
543
|
try {
|
|
295
|
-
expect(
|
|
296
|
-
|
|
544
|
+
expect(Hash.blake3('0xdeadbeef')).toBe(
|
|
545
|
+
'0x53147f3ce49ed4f60dfa5b9654c36ba6103c11f5737df3dabd4cbd296c4161bd',
|
|
297
546
|
)
|
|
298
547
|
expect(Hash.keccak256('0xdeadbeef')).toBe(
|
|
299
548
|
'0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1',
|