ox 1.1.0 → 1.2.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 +54 -0
- package/dist/core/Engine.d.ts +43 -11
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +40 -10
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Hash.d.ts +36 -0
- package/dist/core/Hash.d.ts.map +1 -1
- package/dist/core/Hash.js +35 -0
- package/dist/core/Hash.js.map +1 -1
- package/dist/core/internal/engine.d.ts +8 -8
- package/dist/core/internal/engine.d.ts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/node/Ed25519.d.ts +33 -0
- package/dist/node/Ed25519.d.ts.map +1 -0
- package/dist/node/Ed25519.js +67 -0
- package/dist/node/Ed25519.js.map +1 -0
- package/dist/node/Engine.d.ts +29 -16
- package/dist/node/Engine.d.ts.map +1 -1
- package/dist/node/Engine.js +38 -14
- package/dist/node/Engine.js.map +1 -1
- package/dist/node/Hash.d.ts +17 -19
- package/dist/node/Hash.d.ts.map +1 -1
- package/dist/node/Hash.js +17 -19
- package/dist/node/Hash.js.map +1 -1
- package/dist/node/Keystore.d.ts +36 -0
- package/dist/node/Keystore.d.ts.map +1 -0
- package/dist/node/Keystore.js +72 -0
- package/dist/node/Keystore.js.map +1 -0
- package/dist/node/Mnemonic.d.ts +35 -0
- package/dist/node/Mnemonic.d.ts.map +1 -0
- package/dist/node/Mnemonic.js +46 -0
- package/dist/node/Mnemonic.js.map +1 -0
- package/dist/node/P256.d.ts +32 -0
- package/dist/node/P256.d.ts.map +1 -0
- package/dist/node/P256.js +34 -0
- package/dist/node/P256.js.map +1 -0
- package/dist/node/X25519.d.ts +31 -0
- package/dist/node/X25519.d.ts.map +1 -0
- package/dist/node/X25519.js +71 -0
- package/dist/node/X25519.js.map +1 -0
- package/dist/node/index.d.ts +95 -8
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +95 -8
- package/dist/node/index.js.map +1 -1
- 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/Ed25519.d.ts +35 -0
- package/dist/wasm/Ed25519.d.ts.map +1 -0
- package/dist/wasm/Ed25519.js +88 -0
- package/dist/wasm/Ed25519.js.map +1 -0
- package/dist/wasm/Engine.d.ts +36 -26
- package/dist/wasm/Engine.d.ts.map +1 -1
- package/dist/wasm/Engine.js +44 -25
- package/dist/wasm/Engine.js.map +1 -1
- package/dist/wasm/Hash.d.ts +13 -19
- package/dist/wasm/Hash.d.ts.map +1 -1
- package/dist/wasm/Hash.js +21 -27
- package/dist/wasm/Hash.js.map +1 -1
- package/dist/wasm/Keystore.d.ts +51 -0
- package/dist/wasm/Keystore.d.ts.map +1 -0
- package/dist/wasm/Keystore.js +51 -0
- package/dist/wasm/Keystore.js.map +1 -0
- 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/Mnemonic.d.ts +33 -0
- package/dist/wasm/Mnemonic.d.ts.map +1 -0
- package/dist/wasm/Mnemonic.js +30 -0
- package/dist/wasm/Mnemonic.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/X25519.d.ts +33 -0
- package/dist/wasm/X25519.d.ts.map +1 -0
- package/dist/wasm/X25519.js +53 -0
- package/dist/wasm/X25519.js.map +1 -0
- package/dist/wasm/index.d.ts +124 -12
- package/dist/wasm/index.d.ts.map +1 -1
- package/dist/wasm/index.js +124 -12
- package/dist/wasm/index.js.map +1 -1
- package/dist/wasm/internal/blake3.d.ts +11 -0
- package/dist/wasm/internal/blake3.d.ts.map +1 -0
- package/dist/wasm/internal/blake3.js +31 -0
- package/dist/wasm/internal/blake3.js.map +1 -0
- package/dist/wasm/internal/blake3.wasm.d.ts +3 -0
- package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -0
- package/dist/wasm/internal/blake3.wasm.js +10 -0
- package/dist/wasm/internal/blake3.wasm.js.map +1 -0
- package/dist/wasm/internal/crypto25519.d.ts +16 -0
- package/dist/wasm/internal/crypto25519.d.ts.map +1 -0
- package/dist/wasm/internal/crypto25519.js +5 -0
- package/dist/wasm/internal/crypto25519.js.map +1 -0
- package/dist/wasm/internal/crypto25519.wasm.d.ts +3 -0
- package/dist/wasm/internal/crypto25519.wasm.d.ts.map +1 -0
- package/dist/wasm/internal/crypto25519.wasm.js +10 -0
- package/dist/wasm/internal/crypto25519.wasm.js.map +1 -0
- package/dist/wasm/internal/ed25519.d.ts +4 -0
- package/dist/wasm/internal/ed25519.d.ts.map +1 -0
- package/dist/wasm/internal/ed25519.js +21 -0
- package/dist/wasm/internal/ed25519.js.map +1 -0
- package/dist/wasm/internal/hashes.d.ts +12 -0
- package/dist/wasm/internal/hashes.d.ts.map +1 -0
- package/dist/wasm/internal/hashes.js +8 -0
- package/dist/wasm/internal/hashes.js.map +1 -0
- package/dist/wasm/internal/hashes.wasm.d.ts +4 -2
- package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.wasm.js +4 -2
- 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/mnemonic.d.ts +4 -0
- package/dist/wasm/internal/mnemonic.d.ts.map +1 -0
- package/dist/wasm/internal/mnemonic.js +45 -0
- package/dist/wasm/internal/mnemonic.js.map +1 -0
- package/dist/wasm/internal/pbkdf2.d.ts +12 -0
- package/dist/wasm/internal/pbkdf2.d.ts.map +1 -0
- package/dist/wasm/internal/pbkdf2.js +51 -0
- package/dist/wasm/internal/pbkdf2.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/wasm/internal/x25519.d.ts +4 -0
- package/dist/wasm/internal/x25519.d.ts.map +1 -0
- package/dist/wasm/internal/x25519.js +21 -0
- package/dist/wasm/internal/x25519.js.map +1 -0
- package/package.json +64 -2
- package/src/core/Engine.ts +84 -11
- package/src/core/Hash.ts +59 -0
- package/src/core/_test/Block.test.ts +9 -2
- package/src/core/_test/Engine.test-d.ts +56 -0
- package/src/core/_test/Engine.test.ts +95 -0
- package/src/core/_test/Hash.test-d.ts +18 -0
- package/src/core/_test/Hash.test.ts +100 -1
- package/src/core/_test/Hash.vectors.test.ts +7 -0
- package/src/core/_test/Transaction.test.ts +11 -2
- package/src/core/internal/engine.ts +8 -8
- package/src/index.ts +5 -2
- package/src/node/Ed25519.ts +87 -0
- package/src/node/Engine.ts +79 -23
- package/src/node/Hash.ts +25 -30
- package/src/node/Keystore.ts +103 -0
- package/src/node/Mnemonic.ts +68 -0
- package/src/node/P256.ts +48 -0
- package/src/node/X25519.ts +93 -0
- package/src/node/_test/Curves.fuzz.ts +76 -0
- package/src/node/_test/Ed25519.test-d.ts +35 -0
- package/src/node/_test/Ed25519.test.ts +220 -0
- package/src/node/_test/Engine.test-d.ts +28 -0
- package/src/node/_test/Engine.test.ts +62 -22
- package/src/node/_test/Hash.test-d.ts +16 -9
- package/src/node/_test/Hash.test.ts +10 -11
- package/src/node/_test/Keystore.fuzz.ts +58 -0
- package/src/node/_test/Keystore.test-d.ts +43 -0
- package/src/node/_test/Keystore.test.ts +198 -0
- package/src/node/_test/Mnemonic.fuzz.ts +31 -0
- package/src/node/_test/Mnemonic.test-d.ts +21 -0
- package/src/node/_test/Mnemonic.test.ts +98 -0
- package/src/node/_test/P256.test-d.ts +29 -0
- package/src/node/_test/P256.test.ts +102 -0
- package/src/node/_test/X25519.test-d.ts +28 -0
- package/src/node/_test/X25519.test.ts +239 -0
- package/src/node/index.ts +100 -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/Ed25519.ts +114 -0
- package/src/wasm/Engine.ts +78 -31
- package/src/wasm/Hash.bench.ts +2 -2
- package/src/wasm/Hash.ts +29 -50
- package/src/wasm/Keystore.bench.ts +26 -0
- package/src/wasm/Keystore.ts +66 -0
- package/src/wasm/Kzg.bench.ts +63 -0
- package/src/wasm/Kzg.ts +518 -0
- package/src/wasm/Mnemonic.ts +44 -0
- package/src/wasm/Secp256k1.bench.ts +79 -0
- package/src/wasm/Secp256k1.ts +248 -0
- package/src/wasm/X25519.ts +70 -0
- package/src/wasm/_test/Crypto25519.conformance.ts +57 -0
- package/src/wasm/_test/Crypto25519.fuzz.ts +187 -0
- package/src/wasm/_test/Ed25519.test-d.ts +28 -0
- package/src/wasm/_test/Ed25519.test.ts +168 -0
- package/src/wasm/_test/Ed25519.vectors.test.ts +73 -0
- package/src/wasm/_test/Engine.test-d.ts +29 -0
- package/src/wasm/_test/Engine.test.ts +59 -25
- package/src/wasm/_test/Hash.browser.test.ts +14 -7
- package/src/wasm/_test/Hash.fuzz.ts +58 -23
- package/src/wasm/_test/Hash.test-d.ts +16 -10
- package/src/wasm/_test/Hash.test.ts +148 -48
- package/src/wasm/_test/Hash.vectors.test.ts +15 -8
- package/src/wasm/_test/Keystore.browser.test.ts +73 -0
- package/src/wasm/_test/Keystore.fuzz.ts +163 -0
- package/src/wasm/_test/Keystore.test-d.ts +42 -0
- package/src/wasm/_test/Keystore.test.ts +477 -0
- package/src/wasm/_test/Keystore.vectors.test.ts +21 -0
- package/src/wasm/_test/Kzg.test-d.ts +19 -0
- package/src/wasm/_test/Kzg.test.ts +220 -0
- package/src/wasm/_test/Mnemonic.test-d.ts +17 -0
- package/src/wasm/_test/Mnemonic.test.ts +110 -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/_test/X25519.test-d.ts +21 -0
- package/src/wasm/_test/X25519.test.ts +194 -0
- package/src/wasm/_test/fixtures.ts +4 -0
- package/src/wasm/index.ts +130 -12
- package/src/wasm/internal/blake3.ts +45 -0
- package/src/wasm/internal/blake3.wasm.ts +11 -0
- package/src/wasm/internal/crypto25519.ts +43 -0
- package/src/wasm/internal/crypto25519.wasm.ts +11 -0
- package/src/wasm/internal/ed25519.ts +31 -0
- package/src/wasm/internal/hashes.ts +29 -0
- package/src/wasm/internal/hashes.wasm.ts +5 -2
- 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/mnemonic.ts +56 -0
- package/src/wasm/internal/pbkdf2.ts +86 -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/wasm/internal/x25519.ts +29 -0
- 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,168 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519.js'
|
|
2
|
+
import { describe, expect, test } from 'vp/test'
|
|
3
|
+
import * as Ed25519 from '../Ed25519.js'
|
|
4
|
+
import * as crypto25519 from '../internal/crypto25519.js'
|
|
5
|
+
import { wasmBase64 } from '../internal/crypto25519.wasm.js'
|
|
6
|
+
import * as ed25519_internal from '../internal/ed25519.js'
|
|
7
|
+
import * as internal from '../internal/instantiate.js'
|
|
8
|
+
|
|
9
|
+
const privateKey = fromHex(
|
|
10
|
+
'9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60',
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
describe('engine', () => {
|
|
14
|
+
test('behavior: exposes only semantics-compatible primitives', async () => {
|
|
15
|
+
const engine = await Ed25519.engine()
|
|
16
|
+
|
|
17
|
+
expect(Object.keys(engine).sort()).toMatchInlineSnapshot(`
|
|
18
|
+
[
|
|
19
|
+
"getPublicKey",
|
|
20
|
+
"sign",
|
|
21
|
+
"toMontgomerySecret",
|
|
22
|
+
"verify",
|
|
23
|
+
]
|
|
24
|
+
`)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('behavior: signs and verifies boundary-sized messages', async () => {
|
|
28
|
+
const engine = await Ed25519.engine()
|
|
29
|
+
|
|
30
|
+
for (const size of [0, 1, 31, 32, 63, 64, 65, 127, 128, 129, 1024]) {
|
|
31
|
+
const payload = Uint8Array.from(
|
|
32
|
+
{ length: size },
|
|
33
|
+
(_, index) => (index * 29 + size) % 251,
|
|
34
|
+
)
|
|
35
|
+
const signature = engine.sign(payload, privateKey)
|
|
36
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
37
|
+
|
|
38
|
+
expect(signature).toEqual(ed25519.sign(payload, privateKey))
|
|
39
|
+
expect(engine.verify(signature, payload, publicKey)).toBe(true)
|
|
40
|
+
expect(
|
|
41
|
+
engine.verify(signature, Uint8Array.of(...payload, 1), publicKey),
|
|
42
|
+
).toBe(false)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('behavior: matches private-key conversion', async () => {
|
|
47
|
+
const engine = await Ed25519.engine()
|
|
48
|
+
|
|
49
|
+
expect(engine.toMontgomerySecret(privateKey)).toEqual(
|
|
50
|
+
ed25519.utils.toMontgomerySecret(privateKey),
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('behavior: respects subviews and leaves inputs immutable', async () => {
|
|
55
|
+
const engine = await Ed25519.engine()
|
|
56
|
+
const key = offsetView(privateKey)
|
|
57
|
+
const payload = offsetView(new Uint8Array(257).fill(0xa5))
|
|
58
|
+
const keyBefore = key.slice()
|
|
59
|
+
const payloadBefore = payload.slice()
|
|
60
|
+
const publicKey = offsetView(engine.getPublicKey(key))
|
|
61
|
+
const signature = offsetView(engine.sign(payload, key))
|
|
62
|
+
const publicKeyBefore = publicKey.slice()
|
|
63
|
+
const signatureBefore = signature.slice()
|
|
64
|
+
|
|
65
|
+
expect(engine.getPublicKey(key)).toEqual(ed25519.getPublicKey(key))
|
|
66
|
+
expect(engine.verify(signature, payload, publicKey)).toBe(true)
|
|
67
|
+
expect(engine.toMontgomerySecret(key)).toEqual(
|
|
68
|
+
ed25519.utils.toMontgomerySecret(key),
|
|
69
|
+
)
|
|
70
|
+
expect({ key, payload, publicKey, signature }).toEqual({
|
|
71
|
+
key: keyBefore,
|
|
72
|
+
payload: payloadBefore,
|
|
73
|
+
publicKey: publicKeyBefore,
|
|
74
|
+
signature: signatureBefore,
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('behavior: rejects malformed key and signature lengths', async () => {
|
|
79
|
+
const engine = await Ed25519.engine()
|
|
80
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
81
|
+
|
|
82
|
+
for (const size of [0, 1, 31, 33, 63, 64]) {
|
|
83
|
+
if (size !== 32) {
|
|
84
|
+
expect(() => engine.getPublicKey(new Uint8Array(size))).toThrowError(
|
|
85
|
+
`Ed25519 private key must be 32 bytes, got ${size}`,
|
|
86
|
+
)
|
|
87
|
+
expect(() =>
|
|
88
|
+
engine.sign(new Uint8Array(), new Uint8Array(size)),
|
|
89
|
+
).toThrowError(`Ed25519 private key must be 32 bytes, got ${size}`)
|
|
90
|
+
}
|
|
91
|
+
if (size !== 64)
|
|
92
|
+
expect(() =>
|
|
93
|
+
engine.verify(new Uint8Array(size), new Uint8Array(), publicKey),
|
|
94
|
+
).toThrowError(`Ed25519 signature must be 64 bytes, got ${size}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
expect(() =>
|
|
98
|
+
engine.verify(new Uint8Array(64), new Uint8Array(), new Uint8Array(31)),
|
|
99
|
+
).toThrowError('Ed25519 public key must be 32 bytes, got 31')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('behavior: outputs are owned across calls and memory growth', async () => {
|
|
103
|
+
const engine = await Ed25519.engine()
|
|
104
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
105
|
+
const signature = engine.sign(new Uint8Array(), privateKey)
|
|
106
|
+
const snapshots = [publicKey.slice(), signature.slice()]
|
|
107
|
+
|
|
108
|
+
engine.sign(new Uint8Array(1024 * 1024).fill(0x5a), privateKey)
|
|
109
|
+
|
|
110
|
+
expect([publicKey, signature]).toEqual(snapshots)
|
|
111
|
+
expect(engine.getPublicKey(privateKey) === publicKey).toBe(false)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test('behavior: clears the shared staging region', async () => {
|
|
115
|
+
const engine = await Ed25519.engine()
|
|
116
|
+
const payload = new Uint8Array(1024).fill(0xa5)
|
|
117
|
+
engine.sign(payload, privateKey)
|
|
118
|
+
|
|
119
|
+
const module = await crypto25519.load()
|
|
120
|
+
const size = 32 + payload.length + 64
|
|
121
|
+
expect(
|
|
122
|
+
module
|
|
123
|
+
.view()
|
|
124
|
+
.subarray(module.heapBase, module.heapBase + size)
|
|
125
|
+
.every((byte) => byte === 0),
|
|
126
|
+
).toBe(true)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('behavior: clears the complete region after a late trap', async () => {
|
|
130
|
+
const module = await internal.instantiate<crypto25519.Exports>(wasmBase64)
|
|
131
|
+
const payload = new Uint8Array(1024).fill(0xa5)
|
|
132
|
+
const exports: crypto25519.Exports = {
|
|
133
|
+
...module.exports,
|
|
134
|
+
ed25519_sign(...parameters) {
|
|
135
|
+
module.exports.ed25519_sign(...parameters)
|
|
136
|
+
throw new WebAssembly.RuntimeError('forced late trap')
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
expect(() =>
|
|
141
|
+
ed25519_internal.sign({ ...module, exports }, payload, privateKey),
|
|
142
|
+
).toThrow(WebAssembly.RuntimeError)
|
|
143
|
+
expect(
|
|
144
|
+
module
|
|
145
|
+
.view()
|
|
146
|
+
.subarray(module.heapBase, module.heapBase + 32 + payload.length + 64)
|
|
147
|
+
.every((byte) => byte === 0),
|
|
148
|
+
).toBe(true)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test('behavior: rejects a workspace beyond wasm32 without growing', async () => {
|
|
152
|
+
const module = await internal.instantiate<crypto25519.Exports>(wasmBase64)
|
|
153
|
+
const memory = module.view().length
|
|
154
|
+
|
|
155
|
+
expect(() => module.reserve(0x1_0000_0000)).toThrow(internal.MemoryError)
|
|
156
|
+
expect(module.view()).toHaveLength(memory)
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
function fromHex(value: string): Uint8Array {
|
|
161
|
+
return Uint8Array.from(Buffer.from(value, 'hex'))
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function offsetView(value: Uint8Array): Uint8Array {
|
|
165
|
+
const bytes = new Uint8Array(value.length + 4).fill(0xff)
|
|
166
|
+
bytes.set(value, 2)
|
|
167
|
+
return bytes.subarray(2, -2)
|
|
168
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import { describe, expect, test } from 'vp/test'
|
|
3
|
+
import * as Ed25519 from '../Ed25519.js'
|
|
4
|
+
|
|
5
|
+
type Zip215Vector = {
|
|
6
|
+
sig_bytes: string
|
|
7
|
+
valid_legacy: boolean
|
|
8
|
+
valid_zip215: boolean
|
|
9
|
+
vk_bytes: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const zip215 = JSON.parse(
|
|
13
|
+
fs.readFileSync(
|
|
14
|
+
new URL('../../../test/vectors/ed25519/zip215.json', import.meta.url),
|
|
15
|
+
'utf8',
|
|
16
|
+
),
|
|
17
|
+
) as readonly Zip215Vector[]
|
|
18
|
+
|
|
19
|
+
const rfc8032 = [
|
|
20
|
+
{
|
|
21
|
+
message: '',
|
|
22
|
+
publicKey:
|
|
23
|
+
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a',
|
|
24
|
+
seed: '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60',
|
|
25
|
+
signature:
|
|
26
|
+
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
message: '72',
|
|
30
|
+
publicKey:
|
|
31
|
+
'3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c',
|
|
32
|
+
seed: '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb',
|
|
33
|
+
signature:
|
|
34
|
+
'92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00',
|
|
35
|
+
},
|
|
36
|
+
] as const
|
|
37
|
+
|
|
38
|
+
describe('engine', () => {
|
|
39
|
+
test('vectors: matches RFC 8032 key, signature, and verification cases', async () => {
|
|
40
|
+
const engine = await Ed25519.engine()
|
|
41
|
+
|
|
42
|
+
for (const vector of rfc8032) {
|
|
43
|
+
const seed = fromHex(vector.seed)
|
|
44
|
+
const message = fromHex(vector.message)
|
|
45
|
+
const publicKey = fromHex(vector.publicKey)
|
|
46
|
+
const signature = fromHex(vector.signature)
|
|
47
|
+
|
|
48
|
+
expect(engine.getPublicKey(seed)).toEqual(publicKey)
|
|
49
|
+
expect(engine.sign(message, seed)).toEqual(signature)
|
|
50
|
+
expect(engine.verify(signature, message, publicKey)).toBe(true)
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('vectors: matches all 196 ZIP-215 compliance cases', async () => {
|
|
55
|
+
const engine = await Ed25519.engine()
|
|
56
|
+
const message = new TextEncoder().encode('Zcash')
|
|
57
|
+
|
|
58
|
+
expect(zip215).toHaveLength(196)
|
|
59
|
+
for (const vector of zip215)
|
|
60
|
+
expect(
|
|
61
|
+
engine.verify(
|
|
62
|
+
fromHex(vector.sig_bytes),
|
|
63
|
+
message,
|
|
64
|
+
fromHex(vector.vk_bytes),
|
|
65
|
+
),
|
|
66
|
+
JSON.stringify(vector),
|
|
67
|
+
).toBe(vector.valid_zip215)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
function fromHex(value: string): Uint8Array {
|
|
72
|
+
return Uint8Array.from(Buffer.from(value, 'hex'))
|
|
73
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Engine } from 'ox/wasm'
|
|
2
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
3
|
+
import * as CoreEngine from '../../core/Engine.js'
|
|
4
|
+
|
|
5
|
+
type Installed = Awaited<ReturnType<typeof Engine.install>>
|
|
6
|
+
type Uninstalled = Awaited<ReturnType<typeof Engine.engine>>
|
|
7
|
+
|
|
8
|
+
test('install and engine expose the same precise engine', () => {
|
|
9
|
+
expectTypeOf<Installed>().toEqualTypeOf<Uninstalled>()
|
|
10
|
+
expectTypeOf<Installed['Hash']['sha256']>().toEqualTypeOf<
|
|
11
|
+
(input: Uint8Array) => Uint8Array
|
|
12
|
+
>()
|
|
13
|
+
expectTypeOf<Installed['Keystore']>().not.toHaveProperty('scrypt')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('the WASM Engine namespace exposes synchronous core operations', () => {
|
|
17
|
+
expectTypeOf(Engine.get).toEqualTypeOf(CoreEngine.get)
|
|
18
|
+
expectTypeOf(Engine.InvalidSlotValueError).toEqualTypeOf(
|
|
19
|
+
CoreEngine.InvalidSlotValueError,
|
|
20
|
+
)
|
|
21
|
+
expectTypeOf(Engine.reset).toEqualTypeOf(CoreEngine.reset)
|
|
22
|
+
expectTypeOf(Engine.set).toEqualTypeOf(CoreEngine.set)
|
|
23
|
+
expectTypeOf(Engine.with).toEqualTypeOf(CoreEngine.with)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('the replaced aliases are absent', () => {
|
|
27
|
+
expectTypeOf<typeof Engine>().not.toHaveProperty('create')
|
|
28
|
+
expectTypeOf<typeof Engine>().not.toHaveProperty('load')
|
|
29
|
+
})
|
|
@@ -1,62 +1,96 @@
|
|
|
1
|
-
import { Engine as CoreEngine
|
|
2
|
-
import { Engine } from 'ox/wasm'
|
|
1
|
+
import { Engine as CoreEngine } from 'ox'
|
|
2
|
+
import { Engine, Hash } from 'ox/wasm'
|
|
3
3
|
import { describe, expect, test } from 'vp/test'
|
|
4
4
|
|
|
5
|
-
describe('
|
|
5
|
+
describe('engine', () => {
|
|
6
6
|
test('behavior: does not install', async () => {
|
|
7
|
-
const engine = await Engine.
|
|
7
|
+
const engine = await Engine.engine()
|
|
8
8
|
expect(Object.keys(engine)).toMatchInlineSnapshot(`
|
|
9
9
|
[
|
|
10
|
+
"Ed25519",
|
|
10
11
|
"Hash",
|
|
12
|
+
"Keystore",
|
|
13
|
+
"Mnemonic",
|
|
14
|
+
"X25519",
|
|
11
15
|
]
|
|
12
16
|
`)
|
|
13
|
-
//
|
|
14
|
-
//
|
|
17
|
+
// Benches, differential tests, and composition need an implementation
|
|
18
|
+
// value without touching global state.
|
|
15
19
|
expect(CoreEngine.get()).toMatchInlineSnapshot('{}')
|
|
16
20
|
})
|
|
17
21
|
|
|
18
22
|
test('behavior: installs for the duration of a call', async () => {
|
|
19
23
|
// `with` is the case that genuinely needs a value: there is nothing
|
|
20
24
|
// installed for `set` to merge into.
|
|
21
|
-
const wasm = await Engine.
|
|
22
|
-
const inside = CoreEngine.with(wasm, () => Hash.
|
|
23
|
-
expect(inside).toEqual(Hash.
|
|
25
|
+
const wasm = await Engine.engine()
|
|
26
|
+
const inside = CoreEngine.with(wasm, () => Hash.sha256('0xdeadbeef'))
|
|
27
|
+
expect(inside).toEqual(Hash.sha256('0xdeadbeef'))
|
|
24
28
|
expect(CoreEngine.get()).toMatchInlineSnapshot('{}')
|
|
25
29
|
})
|
|
26
30
|
})
|
|
27
31
|
|
|
28
|
-
describe('
|
|
32
|
+
describe('install', () => {
|
|
29
33
|
test('behavior: merges with a later set, rather than being replaced', async () => {
|
|
30
|
-
await Engine.
|
|
31
|
-
CoreEngine.set({
|
|
34
|
+
await Engine.install()
|
|
35
|
+
CoreEngine.set({ Bls: { randomSecretKey: () => new Uint8Array(32) } })
|
|
32
36
|
expect(Object.keys(CoreEngine.get()).sort()).toMatchInlineSnapshot(`
|
|
33
37
|
[
|
|
38
|
+
"Bls",
|
|
39
|
+
"Ed25519",
|
|
34
40
|
"Hash",
|
|
41
|
+
"Keystore",
|
|
35
42
|
"Mnemonic",
|
|
43
|
+
"X25519",
|
|
36
44
|
]
|
|
37
45
|
`)
|
|
38
46
|
})
|
|
39
47
|
|
|
40
48
|
test('behavior: installs, and returns what it installed', async () => {
|
|
41
|
-
const before = Hash.
|
|
49
|
+
const before = Hash.sha256('0xdeadbeef')
|
|
42
50
|
|
|
43
|
-
const engine = await Engine.
|
|
51
|
+
const engine = await Engine.install()
|
|
44
52
|
|
|
45
53
|
expect(Object.keys(CoreEngine.get())).toEqual(Object.keys(engine))
|
|
46
54
|
// Installing changes which implementation runs, never the answer.
|
|
47
|
-
expect(Hash.
|
|
55
|
+
expect(Hash.sha256('0xdeadbeef')).toEqual(before)
|
|
56
|
+
expect(Engine.get()).toEqual(CoreEngine.get())
|
|
48
57
|
})
|
|
49
58
|
|
|
50
59
|
test('behavior: routes every slot it reports', async () => {
|
|
51
|
-
await Engine.
|
|
52
|
-
expect(
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
await Engine.install()
|
|
61
|
+
expect(
|
|
62
|
+
Object.fromEntries(
|
|
63
|
+
Object.entries(CoreEngine.get()).map(([slot, value]) => [
|
|
64
|
+
slot,
|
|
65
|
+
Object.keys(value ?? {}).sort(),
|
|
66
|
+
]),
|
|
67
|
+
),
|
|
68
|
+
).toMatchInlineSnapshot(`
|
|
69
|
+
{
|
|
70
|
+
"Ed25519": [
|
|
71
|
+
"getPublicKey",
|
|
72
|
+
"sign",
|
|
73
|
+
"toMontgomerySecret",
|
|
74
|
+
"verify",
|
|
75
|
+
],
|
|
76
|
+
"Hash": [
|
|
77
|
+
"blake3",
|
|
78
|
+
"hmacSha256",
|
|
79
|
+
"keccak256",
|
|
80
|
+
"ripemd160",
|
|
81
|
+
"sha256",
|
|
82
|
+
],
|
|
83
|
+
"Keystore": [
|
|
84
|
+
"pbkdf2Sha256",
|
|
85
|
+
],
|
|
86
|
+
"Mnemonic": [
|
|
87
|
+
"toSeed",
|
|
88
|
+
],
|
|
89
|
+
"X25519": [
|
|
90
|
+
"getPublicKey",
|
|
91
|
+
"getSharedSecret",
|
|
92
|
+
],
|
|
93
|
+
}
|
|
94
|
+
`)
|
|
61
95
|
})
|
|
62
96
|
})
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { blake3 } from '@noble/hashes/blake3.js'
|
|
1
2
|
import { keccak_256 } from '@noble/hashes/sha3.js'
|
|
2
3
|
import { describe, expect, test, vi } from 'vp/test'
|
|
3
4
|
import * as Engine from '../../core/Engine.js'
|
|
4
5
|
import * as Hash from '../../core/Hash.js'
|
|
5
6
|
import * as WasmHash from '../Hash.js'
|
|
6
7
|
|
|
7
|
-
describe('
|
|
8
|
+
describe('engine', () => {
|
|
8
9
|
test('behavior: instantiates asynchronously', async () => {
|
|
9
10
|
// Chrome refuses to compile modules above a few kilobytes synchronously on
|
|
10
11
|
// the main thread, so `new WebAssembly.Module` must never be reached. A spy
|
|
@@ -13,12 +14,13 @@ describe('create', () => {
|
|
|
13
14
|
const Module = vi.spyOn(globalThis.WebAssembly, 'Module')
|
|
14
15
|
const Instance = vi.spyOn(globalThis.WebAssembly, 'Instance')
|
|
15
16
|
try {
|
|
16
|
-
const engine = await WasmHash.
|
|
17
|
+
const engine = await WasmHash.engine()
|
|
17
18
|
expect(Module).not.toHaveBeenCalled()
|
|
18
19
|
expect(Instance).not.toHaveBeenCalled()
|
|
19
20
|
|
|
20
21
|
const input = new Uint8Array(32).fill(1)
|
|
21
|
-
expect(engine.
|
|
22
|
+
expect(engine.keccak256(input)).toEqual(keccak_256(input))
|
|
23
|
+
expect(engine.blake3(input)).toEqual(blake3(input))
|
|
22
24
|
} finally {
|
|
23
25
|
Module.mockRestore()
|
|
24
26
|
Instance.mockRestore()
|
|
@@ -26,20 +28,25 @@ describe('create', () => {
|
|
|
26
28
|
})
|
|
27
29
|
|
|
28
30
|
test('behavior: grows memory in a real browser, then hashes a small input', async () => {
|
|
29
|
-
const engine = await WasmHash.
|
|
31
|
+
const engine = await WasmHash.engine()
|
|
30
32
|
|
|
31
33
|
const large = new Uint8Array(3 * 1024 * 1024).fill(7)
|
|
32
|
-
expect(engine.
|
|
34
|
+
expect(engine.keccak256(large)).toEqual(keccak_256(large))
|
|
35
|
+
expect(engine.blake3(large)).toEqual(blake3(large))
|
|
33
36
|
|
|
34
37
|
// `memory.grow` detached the previous `ArrayBuffer`; a retained view would
|
|
35
38
|
// now read zero bytes.
|
|
36
39
|
const small = new Uint8Array(32).fill(1)
|
|
37
|
-
expect(engine.
|
|
40
|
+
expect(engine.keccak256(small)).toEqual(keccak_256(small))
|
|
41
|
+
expect(engine.blake3(small)).toEqual(blake3(small))
|
|
38
42
|
})
|
|
39
43
|
|
|
40
44
|
test('behavior: ox uses the WASM implementation once installed', async () => {
|
|
41
|
-
Engine.
|
|
45
|
+
await Engine.install({ Hash: WasmHash.engine() })
|
|
42
46
|
try {
|
|
47
|
+
expect(Hash.blake3('0xdeadbeef')).toBe(
|
|
48
|
+
'0x53147f3ce49ed4f60dfa5b9654c36ba6103c11f5737df3dabd4cbd296c4161bd',
|
|
49
|
+
)
|
|
43
50
|
expect(Hash.keccak256('0xdeadbeef')).toBe(
|
|
44
51
|
'0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1',
|
|
45
52
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fc, test } from '@fast-check/vitest'
|
|
2
|
+
import { blake3 } from '@noble/hashes/blake3.js'
|
|
2
3
|
import { hmac } from '@noble/hashes/hmac.js'
|
|
3
4
|
import { ripemd160 } from '@noble/hashes/legacy.js'
|
|
4
5
|
import { sha256 } from '@noble/hashes/sha2.js'
|
|
@@ -7,10 +8,10 @@ import { Hash as WasmHash } from 'ox/wasm'
|
|
|
7
8
|
import { beforeAll, describe, expect } from 'vp/test'
|
|
8
9
|
import { numRuns } from '../../../test/fuzz/numRuns.js'
|
|
9
10
|
|
|
10
|
-
let engine: WasmHash.
|
|
11
|
+
let engine: WasmHash.engine.ReturnType
|
|
11
12
|
|
|
12
13
|
beforeAll(async () => {
|
|
13
|
-
engine = await WasmHash.
|
|
14
|
+
engine = await WasmHash.engine()
|
|
14
15
|
})
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -21,14 +22,33 @@ beforeAll(async () => {
|
|
|
21
22
|
*
|
|
22
23
|
* The distribution is weighted toward the sizes where padding and block-boundary
|
|
23
24
|
* bugs hide -- empty input, exact multiples of the keccak256 rate (136) and the
|
|
24
|
-
* SHA-2 block (64), and the 56-byte threshold at which
|
|
25
|
-
* longer fits in the final block.
|
|
25
|
+
* SHA-2 block (64), BLAKE3 chunk (1024), and the 56-byte threshold at which
|
|
26
|
+
* the SHA-2 length counter no longer fits in the final block.
|
|
26
27
|
*/
|
|
27
28
|
const arbitraryInput = fc.oneof(
|
|
28
29
|
{ arbitrary: fc.uint8Array({ maxLength: 300, minLength: 0 }), weight: 6 },
|
|
29
30
|
{
|
|
30
31
|
arbitrary: fc
|
|
31
|
-
.constantFrom(
|
|
32
|
+
.constantFrom(
|
|
33
|
+
0,
|
|
34
|
+
1,
|
|
35
|
+
55,
|
|
36
|
+
56,
|
|
37
|
+
63,
|
|
38
|
+
64,
|
|
39
|
+
65,
|
|
40
|
+
111,
|
|
41
|
+
112,
|
|
42
|
+
135,
|
|
43
|
+
136,
|
|
44
|
+
137,
|
|
45
|
+
272,
|
|
46
|
+
1023,
|
|
47
|
+
1024,
|
|
48
|
+
1025,
|
|
49
|
+
2048,
|
|
50
|
+
2049,
|
|
51
|
+
)
|
|
32
52
|
.chain((size) => fc.uint8Array({ maxLength: size, minLength: size })),
|
|
33
53
|
weight: 3,
|
|
34
54
|
},
|
|
@@ -54,55 +74,63 @@ const arbitraryKey = fc.oneof(
|
|
|
54
74
|
)
|
|
55
75
|
|
|
56
76
|
const primitives = {
|
|
77
|
+
blake3: {
|
|
78
|
+
reference: (input: Uint8Array) => blake3(input),
|
|
79
|
+
wasm: (input: Uint8Array) => engine.blake3(input),
|
|
80
|
+
},
|
|
57
81
|
hmacSha256: {
|
|
58
82
|
reference: (input: Uint8Array, key: Uint8Array) => hmac(sha256, key, input),
|
|
59
|
-
wasm: (input: Uint8Array, key: Uint8Array) =>
|
|
60
|
-
engine.Hash.hmacSha256(key, input),
|
|
83
|
+
wasm: (input: Uint8Array, key: Uint8Array) => engine.hmacSha256(key, input),
|
|
61
84
|
},
|
|
62
85
|
keccak256: {
|
|
63
86
|
reference: (input: Uint8Array) => keccak_256(input),
|
|
64
|
-
wasm: (input: Uint8Array) => engine.
|
|
87
|
+
wasm: (input: Uint8Array) => engine.keccak256(input),
|
|
65
88
|
},
|
|
66
89
|
ripemd160: {
|
|
67
90
|
reference: (input: Uint8Array) => ripemd160(input),
|
|
68
|
-
wasm: (input: Uint8Array) => engine.
|
|
91
|
+
wasm: (input: Uint8Array) => engine.ripemd160(input),
|
|
69
92
|
},
|
|
70
93
|
sha256: {
|
|
71
94
|
reference: (input: Uint8Array) => sha256(input),
|
|
72
|
-
wasm: (input: Uint8Array) => engine.
|
|
95
|
+
wasm: (input: Uint8Array) => engine.sha256(input),
|
|
73
96
|
},
|
|
74
97
|
} as const
|
|
75
98
|
|
|
76
99
|
type Name = keyof typeof primitives
|
|
77
100
|
|
|
78
101
|
describe('Hash', () => {
|
|
102
|
+
test.prop({ input: arbitraryInput }, { numRuns })(
|
|
103
|
+
'blake3 ≡ @noble/hashes',
|
|
104
|
+
({ input }) => {
|
|
105
|
+
expect(engine.blake3(input)).toEqual(blake3(input))
|
|
106
|
+
},
|
|
107
|
+
)
|
|
108
|
+
|
|
79
109
|
test.prop({ input: arbitraryInput }, { numRuns })(
|
|
80
110
|
'keccak256 ≡ @noble/hashes',
|
|
81
111
|
({ input }) => {
|
|
82
|
-
expect(engine.
|
|
112
|
+
expect(engine.keccak256(input)).toEqual(keccak_256(input))
|
|
83
113
|
},
|
|
84
114
|
)
|
|
85
115
|
|
|
86
116
|
test.prop({ input: arbitraryInput }, { numRuns })(
|
|
87
117
|
'sha256 ≡ @noble/hashes',
|
|
88
118
|
({ input }) => {
|
|
89
|
-
expect(engine.
|
|
119
|
+
expect(engine.sha256(input)).toEqual(sha256(input))
|
|
90
120
|
},
|
|
91
121
|
)
|
|
92
122
|
|
|
93
123
|
test.prop({ input: arbitraryInput }, { numRuns })(
|
|
94
124
|
'ripemd160 ≡ @noble/hashes',
|
|
95
125
|
({ input }) => {
|
|
96
|
-
expect(engine.
|
|
126
|
+
expect(engine.ripemd160(input)).toEqual(ripemd160(input))
|
|
97
127
|
},
|
|
98
128
|
)
|
|
99
129
|
|
|
100
130
|
test.prop({ input: arbitraryInput, key: arbitraryKey }, { numRuns })(
|
|
101
131
|
'hmacSha256 ≡ @noble/hashes',
|
|
102
132
|
({ input, key }) => {
|
|
103
|
-
expect(engine.
|
|
104
|
-
hmac(sha256, key, input),
|
|
105
|
-
)
|
|
133
|
+
expect(engine.hmacSha256(key, input)).toEqual(hmac(sha256, key, input))
|
|
106
134
|
},
|
|
107
135
|
)
|
|
108
136
|
})
|
|
@@ -115,6 +143,7 @@ describe('memory', () => {
|
|
|
115
143
|
input: arbitraryInput,
|
|
116
144
|
key: arbitraryKey,
|
|
117
145
|
name: fc.constantFrom<Name>(
|
|
146
|
+
'blake3',
|
|
118
147
|
'hmacSha256',
|
|
119
148
|
'keccak256',
|
|
120
149
|
'ripemd160',
|
|
@@ -156,7 +185,7 @@ describe('memory', () => {
|
|
|
156
185
|
// as zeroes rather than throwing.
|
|
157
186
|
for (const pages of sizes) {
|
|
158
187
|
const input = new Uint8Array(pages * 65_536).fill(pages & 0xff)
|
|
159
|
-
expect(engine.
|
|
188
|
+
expect(engine.keccak256(input), `${pages} pages`).toEqual(
|
|
160
189
|
keccak_256(input),
|
|
161
190
|
)
|
|
162
191
|
}
|
|
@@ -167,10 +196,15 @@ describe('memory', () => {
|
|
|
167
196
|
({ input }) => {
|
|
168
197
|
// A digest returned as a view over linear memory would be silently
|
|
169
198
|
// rewritten by the next call. Hold one across a larger call and check it.
|
|
170
|
-
const digest = engine.
|
|
199
|
+
const digest = engine.keccak256(input)
|
|
171
200
|
const snapshot = digest.slice()
|
|
172
|
-
engine.
|
|
201
|
+
engine.keccak256(new Uint8Array(input.length + 1024).fill(0xaa))
|
|
173
202
|
expect(digest).toEqual(snapshot)
|
|
203
|
+
|
|
204
|
+
const blake3Digest = engine.blake3(input)
|
|
205
|
+
const blake3Snapshot = blake3Digest.slice()
|
|
206
|
+
engine.blake3(new Uint8Array(input.length + 1024).fill(0xaa))
|
|
207
|
+
expect(blake3Digest).toEqual(blake3Snapshot)
|
|
174
208
|
},
|
|
175
209
|
)
|
|
176
210
|
|
|
@@ -178,10 +212,11 @@ describe('memory', () => {
|
|
|
178
212
|
'inputs are not mutated',
|
|
179
213
|
({ input }) => {
|
|
180
214
|
const snapshot = input.slice()
|
|
181
|
-
engine.
|
|
182
|
-
engine.
|
|
183
|
-
engine.
|
|
184
|
-
engine.
|
|
215
|
+
engine.blake3(input)
|
|
216
|
+
engine.keccak256(input)
|
|
217
|
+
engine.sha256(input)
|
|
218
|
+
engine.ripemd160(input)
|
|
219
|
+
engine.hmacSha256(input, input)
|
|
185
220
|
expect(input).toEqual(snapshot)
|
|
186
221
|
},
|
|
187
222
|
)
|
|
@@ -1,28 +1,34 @@
|
|
|
1
|
-
import type { Engine } from 'ox'
|
|
2
1
|
import { Hash as WasmHash } from 'ox/wasm'
|
|
3
2
|
import { expectTypeOf, test } from 'vp/test'
|
|
3
|
+
import type * as CoreEngine from '../../core/Engine.js'
|
|
4
|
+
import * as CoreHash from '../../core/Hash.js'
|
|
4
5
|
|
|
5
|
-
type
|
|
6
|
+
type Slot = Awaited<ReturnType<typeof WasmHash.engine>>
|
|
6
7
|
|
|
7
8
|
test('every primitive is present, so callers need no assertion', () => {
|
|
8
|
-
expectTypeOf<
|
|
9
|
+
expectTypeOf<Slot['blake3']>().toEqualTypeOf<
|
|
9
10
|
(input: Uint8Array) => Uint8Array
|
|
10
11
|
>()
|
|
11
|
-
expectTypeOf<
|
|
12
|
+
expectTypeOf<Slot['keccak256']>().toEqualTypeOf<
|
|
12
13
|
(input: Uint8Array) => Uint8Array
|
|
13
14
|
>()
|
|
14
|
-
expectTypeOf<
|
|
15
|
+
expectTypeOf<Slot['sha256']>().toEqualTypeOf<
|
|
15
16
|
(input: Uint8Array) => Uint8Array
|
|
16
17
|
>()
|
|
17
|
-
expectTypeOf<
|
|
18
|
+
expectTypeOf<Slot['ripemd160']>().toEqualTypeOf<
|
|
19
|
+
(input: Uint8Array) => Uint8Array
|
|
20
|
+
>()
|
|
21
|
+
expectTypeOf<Slot['hmacSha256']>().toEqualTypeOf<
|
|
18
22
|
(key: Uint8Array, message: Uint8Array) => Uint8Array
|
|
19
23
|
>()
|
|
20
24
|
})
|
|
21
25
|
|
|
22
|
-
test('
|
|
23
|
-
expectTypeOf<
|
|
26
|
+
test('the result is the raw slot, so `Engine.install` accepts it', () => {
|
|
27
|
+
expectTypeOf<{ Hash: Slot }>().toExtend<CoreEngine.Engine>()
|
|
24
28
|
})
|
|
25
29
|
|
|
26
|
-
test('the
|
|
27
|
-
expectTypeOf
|
|
30
|
+
test('the WASM namespace exposes the public Hash API', () => {
|
|
31
|
+
expectTypeOf(WasmHash.blake3).toEqualTypeOf(CoreHash.blake3)
|
|
32
|
+
expectTypeOf(WasmHash.sha256).toEqualTypeOf(CoreHash.sha256)
|
|
33
|
+
expectTypeOf<typeof WasmHash>().not.toHaveProperty('create')
|
|
28
34
|
})
|