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,220 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from 'vp/test'
|
|
2
|
+
import { kzg as reference } from '../../../test/kzg.js'
|
|
3
|
+
import type * as Bytes from '../../core/Bytes.js'
|
|
4
|
+
import type * as CoreKzg from '../../core/Kzg.js'
|
|
5
|
+
import { mainnet as trustedSetup } from '../../trusted-setups/Setups.js'
|
|
6
|
+
import * as Kzg from '../Kzg.js'
|
|
7
|
+
|
|
8
|
+
const blob = Uint8Array.from({ length: 131_072 }, (_, index) =>
|
|
9
|
+
index % 32 === 31 ? index % 251 : 0,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
let instance: Kzg.create.ReturnType
|
|
13
|
+
let commitment: Bytes.Bytes
|
|
14
|
+
let cells: readonly Bytes.Bytes[]
|
|
15
|
+
let proofs: readonly Bytes.Bytes[]
|
|
16
|
+
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
instance = await Kzg.create({ trustedSetup })
|
|
19
|
+
commitment = instance.blobToKzgCommitment(blob)
|
|
20
|
+
;({ cells, proofs } = instance.computeCellsAndKzgProofs(blob))
|
|
21
|
+
}, 120_000)
|
|
22
|
+
|
|
23
|
+
afterAll(() => {
|
|
24
|
+
instance.dispose()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('create', () => {
|
|
28
|
+
test('returns the injected Kzg.Kzg boundary', () => {
|
|
29
|
+
expect(instance satisfies CoreKzg.Kzg).toMatchInlineSnapshot(`
|
|
30
|
+
{
|
|
31
|
+
"blobToKzgCommitment": [Function],
|
|
32
|
+
"computeCells": [Function],
|
|
33
|
+
"computeCellsAndKzgProofs": [Function],
|
|
34
|
+
"dispose": [Function],
|
|
35
|
+
"recoverCellsAndKzgProofs": [Function],
|
|
36
|
+
"verifyCellKzgProofBatch": [Function],
|
|
37
|
+
}
|
|
38
|
+
`)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('compiles concurrently into independently owned instances', async () => {
|
|
42
|
+
const [first, second] = await Promise.all([
|
|
43
|
+
Kzg.create({ trustedSetup }),
|
|
44
|
+
Kzg.create({ trustedSetup }),
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
first.dispose()
|
|
48
|
+
expect(() => first.blobToKzgCommitment(blob)).toThrow(Kzg.DisposedError)
|
|
49
|
+
expect(second.blobToKzgCommitment(blob)).toEqual(commitment)
|
|
50
|
+
second.dispose()
|
|
51
|
+
second.dispose()
|
|
52
|
+
expect(() => second.computeCells(blob)).toThrowErrorMatchingInlineSnapshot(
|
|
53
|
+
`[Kzg.DisposedError: KZG instance has been disposed.]`,
|
|
54
|
+
)
|
|
55
|
+
}, 120_000)
|
|
56
|
+
|
|
57
|
+
test('rejects precomputation beyond the memory bound', async () => {
|
|
58
|
+
await expect(
|
|
59
|
+
Kzg.create({ precompute: 9, trustedSetup }),
|
|
60
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
61
|
+
`[Kzg.InvalidPrecomputeError: \`precompute\` must be an integer from 0 through 8. Got 9.]`,
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('rejects malformed trusted setup points', async () => {
|
|
66
|
+
await expect(
|
|
67
|
+
Kzg.create({
|
|
68
|
+
trustedSetup: {
|
|
69
|
+
...trustedSetup,
|
|
70
|
+
g2_monomial: trustedSetup.g2_monomial.slice(1),
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
74
|
+
`[Kzg.InvalidTrustedSetupError: \`g2_monomial\` must contain exactly 6240 bytes.]`,
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('rejects invalid trusted setup points', async () => {
|
|
79
|
+
const g1Lagrange = trustedSetup.g1_lagrange.slice()
|
|
80
|
+
g1Lagrange.fill(0, 0, 48)
|
|
81
|
+
await expect(
|
|
82
|
+
Kzg.create({
|
|
83
|
+
trustedSetup: {
|
|
84
|
+
...trustedSetup,
|
|
85
|
+
g1_lagrange: g1Lagrange,
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
89
|
+
`[Kzg.InvalidTrustedSetupError: c-kzg rejected the trusted setup.]`,
|
|
90
|
+
)
|
|
91
|
+
}, 120_000)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('blobToKzgCommitment', () => {
|
|
95
|
+
test('conformance: matches the independent reference implementation', () => {
|
|
96
|
+
expect(commitment).toEqual(reference.blobToKzgCommitment(blob))
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('rejects a malformed blob', () => {
|
|
100
|
+
expect(() =>
|
|
101
|
+
instance.blobToKzgCommitment(new Uint8Array(31)),
|
|
102
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
103
|
+
`[Kzg.InvalidInputError: \`blob\` must contain exactly 131072 bytes.]`,
|
|
104
|
+
)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('reuses setup and scratch state', () => {
|
|
108
|
+
for (let i = 0; i < 100; i++)
|
|
109
|
+
expect(instance.blobToKzgCommitment(blob)).toEqual(commitment)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('computeCells', () => {
|
|
114
|
+
test('conformance: matches the independent reference implementation', () => {
|
|
115
|
+
expect(instance.computeCells(blob)).toEqual(reference.computeCells(blob))
|
|
116
|
+
}, 120_000)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
describe('computeCellsAndKzgProofs', () => {
|
|
120
|
+
test('conformance: matches the independent reference implementation', () => {
|
|
121
|
+
const expected = reference.computeCellsAndKzgProofs(blob)
|
|
122
|
+
expect(cells).toEqual(expected.cells)
|
|
123
|
+
expect(proofs).toEqual(expected.proofs)
|
|
124
|
+
}, 120_000)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
describe('recoverCellsAndKzgProofs', () => {
|
|
128
|
+
test('conformance: matches the independent reference implementation', () => {
|
|
129
|
+
const indices = cells.map((_, index) => index).filter((index) => index % 2)
|
|
130
|
+
const partial = cells.filter((_, index) => index % 2)
|
|
131
|
+
const expected = reference.recoverCellsAndKzgProofs(indices, partial)
|
|
132
|
+
|
|
133
|
+
expect(instance.recoverCellsAndKzgProofs(indices, partial)).toEqual(
|
|
134
|
+
expected,
|
|
135
|
+
)
|
|
136
|
+
}, 120_000)
|
|
137
|
+
|
|
138
|
+
test('accepts unordered indices', () => {
|
|
139
|
+
const indices = cells
|
|
140
|
+
.map((_, index) => index)
|
|
141
|
+
.filter((index) => index % 2)
|
|
142
|
+
.reverse()
|
|
143
|
+
const partial = indices.map((index) => cells[index]!)
|
|
144
|
+
|
|
145
|
+
expect(instance.recoverCellsAndKzgProofs(indices, partial)).toEqual({
|
|
146
|
+
cells,
|
|
147
|
+
proofs,
|
|
148
|
+
})
|
|
149
|
+
}, 120_000)
|
|
150
|
+
|
|
151
|
+
test('rejects duplicate indices', () => {
|
|
152
|
+
expect(() =>
|
|
153
|
+
instance.recoverCellsAndKzgProofs(
|
|
154
|
+
Array.from({ length: 64 }, () => 0),
|
|
155
|
+
cells.slice(0, 64),
|
|
156
|
+
),
|
|
157
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
158
|
+
`[Kzg.InvalidInputError: \`cellIndices\` must not contain duplicate indices.]`,
|
|
159
|
+
)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
describe('verifyCellKzgProofBatch', () => {
|
|
164
|
+
const indices = Array.from({ length: 128 }, (_, index) => index)
|
|
165
|
+
|
|
166
|
+
test('conformance: matches the independent reference implementation', () => {
|
|
167
|
+
const commitments = cells.map(() => commitment)
|
|
168
|
+
expect(
|
|
169
|
+
instance.verifyCellKzgProofBatch(commitments, indices, cells, proofs),
|
|
170
|
+
).toBe(
|
|
171
|
+
reference.verifyCellKzgProofBatch(commitments, indices, cells, proofs),
|
|
172
|
+
)
|
|
173
|
+
}, 120_000)
|
|
174
|
+
|
|
175
|
+
test('returns false for a corrupted cell', () => {
|
|
176
|
+
const corrupted = cells.map((cell, index) => {
|
|
177
|
+
if (index !== 7) return cell
|
|
178
|
+
const value = Uint8Array.from(cell)
|
|
179
|
+
value[0] = value[0]! ^ 1
|
|
180
|
+
return value
|
|
181
|
+
})
|
|
182
|
+
expect(
|
|
183
|
+
instance.verifyCellKzgProofBatch(
|
|
184
|
+
cells.map(() => commitment),
|
|
185
|
+
indices,
|
|
186
|
+
corrupted,
|
|
187
|
+
proofs,
|
|
188
|
+
),
|
|
189
|
+
).toMatchInlineSnapshot('false')
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
test('rejects mismatched input lengths', () => {
|
|
193
|
+
expect(() =>
|
|
194
|
+
instance.verifyCellKzgProofBatch(
|
|
195
|
+
[commitment],
|
|
196
|
+
[],
|
|
197
|
+
[cells[0]!],
|
|
198
|
+
[proofs[0]!],
|
|
199
|
+
),
|
|
200
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
201
|
+
`[Kzg.InvalidInputError: \`commitments\`, \`cellIndices\`, \`cells\`, and \`proofs\` must have the same non-zero length.]`,
|
|
202
|
+
)
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
test('exports', () => {
|
|
207
|
+
expect(Object.keys(Kzg)).toMatchInlineSnapshot(`
|
|
208
|
+
[
|
|
209
|
+
"create",
|
|
210
|
+
"DisposedError",
|
|
211
|
+
"InvalidInputError",
|
|
212
|
+
"InvalidPrecomputeError",
|
|
213
|
+
"InvalidTrustedSetupError",
|
|
214
|
+
"MemoryError",
|
|
215
|
+
"WasmError",
|
|
216
|
+
"versionedHashVersion",
|
|
217
|
+
"from",
|
|
218
|
+
]
|
|
219
|
+
`)
|
|
220
|
+
})
|
|
@@ -19,3 +19,12 @@ test('memmove compares flat-memory offsets rather than C object pointers', () =>
|
|
|
19
19
|
expect(body).toContain('if ((size_t)d < (size_t)s)')
|
|
20
20
|
expect(body).not.toMatch(/if\s*\(\s*d\s*<\s*s\s*\)/)
|
|
21
21
|
})
|
|
22
|
+
|
|
23
|
+
test('KZG artifact loads only when create runs', () => {
|
|
24
|
+
const source = readFileSync(new URL('../Kzg.ts', import.meta.url), 'utf8')
|
|
25
|
+
|
|
26
|
+
expect(source).not.toMatch(
|
|
27
|
+
/^import(?!\s+type\b)[^\n]*['"]\.\/internal\/kzg\.js['"]/m,
|
|
28
|
+
)
|
|
29
|
+
expect(source).toContain("await import('./internal/kzg.js')")
|
|
30
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
2
|
+
import type * as Engine from '../../core/Engine.js'
|
|
3
|
+
import * as core_Secp256k1 from '../../core/Secp256k1.js'
|
|
4
|
+
import * as Secp256k1 from '../Secp256k1.js'
|
|
5
|
+
|
|
6
|
+
type Slot = Awaited<ReturnType<typeof Secp256k1.engine>>
|
|
7
|
+
|
|
8
|
+
test('return type exposes only deterministic Secp256k1 primitives', () => {
|
|
9
|
+
expectTypeOf<Slot['getPublicKey']>().toEqualTypeOf<
|
|
10
|
+
NonNullable<Engine.Ecdsa['getPublicKey']>
|
|
11
|
+
>()
|
|
12
|
+
expectTypeOf<Slot['getSharedSecret']>().toEqualTypeOf<
|
|
13
|
+
NonNullable<Engine.Ecdsa['getSharedSecret']>
|
|
14
|
+
>()
|
|
15
|
+
expectTypeOf<Slot['recoverPublicKey']>().toEqualTypeOf<
|
|
16
|
+
NonNullable<Engine.Ecdsa['recoverPublicKey']>
|
|
17
|
+
>()
|
|
18
|
+
expectTypeOf<Slot['sign']>().toEqualTypeOf<
|
|
19
|
+
NonNullable<Engine.Ecdsa['sign']>
|
|
20
|
+
>()
|
|
21
|
+
expectTypeOf<Slot['verify']>().toEqualTypeOf<
|
|
22
|
+
NonNullable<Engine.Ecdsa['verify']>
|
|
23
|
+
>()
|
|
24
|
+
expectTypeOf<Slot>().not.toHaveProperty('randomSecretKey')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('the WASM namespace exposes the public Secp256k1 API', () => {
|
|
28
|
+
expectTypeOf(Secp256k1.getPublicKey).toEqualTypeOf(
|
|
29
|
+
core_Secp256k1.getPublicKey,
|
|
30
|
+
)
|
|
31
|
+
expectTypeOf(Secp256k1.randomPrivateKey).toEqualTypeOf(
|
|
32
|
+
core_Secp256k1.randomPrivateKey,
|
|
33
|
+
)
|
|
34
|
+
expectTypeOf<typeof Secp256k1>().not.toHaveProperty('create')
|
|
35
|
+
})
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js'
|
|
2
|
+
import { describe, expect, test } from 'vp/test'
|
|
3
|
+
import * as Secp256k1 from '../Secp256k1.js'
|
|
4
|
+
import * as secp256k1_internal from '../internal/secp256k1.js'
|
|
5
|
+
|
|
6
|
+
const privateKey = fromHex(
|
|
7
|
+
'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
|
|
8
|
+
)
|
|
9
|
+
const privateKeyB = fromHex(
|
|
10
|
+
'59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',
|
|
11
|
+
)
|
|
12
|
+
const curveOrder = BigInt(
|
|
13
|
+
'0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
describe('engine', () => {
|
|
17
|
+
test('behavior: exposes only deterministic primitives', async () => {
|
|
18
|
+
const engine = await Secp256k1.engine()
|
|
19
|
+
|
|
20
|
+
expect(Object.keys(engine).sort()).toMatchInlineSnapshot(`
|
|
21
|
+
[
|
|
22
|
+
"getPublicKey",
|
|
23
|
+
"getSharedSecret",
|
|
24
|
+
"recoverPublicKey",
|
|
25
|
+
"sign",
|
|
26
|
+
"verify",
|
|
27
|
+
]
|
|
28
|
+
`)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('behavior: matches public keys and compressed shared points', async () => {
|
|
32
|
+
const engine = await Secp256k1.engine()
|
|
33
|
+
const publicKey = secp256k1.getPublicKey(privateKey, false)
|
|
34
|
+
const publicKeyB = secp256k1.getPublicKey(privateKeyB, false)
|
|
35
|
+
const compressedPublicKeyB = secp256k1.getPublicKey(privateKeyB, true)
|
|
36
|
+
const expected = secp256k1.getSharedSecret(privateKey, publicKeyB, true)
|
|
37
|
+
|
|
38
|
+
expect(engine.getPublicKey(privateKey)).toEqual(publicKey)
|
|
39
|
+
expect(engine.getSharedSecret(privateKey, publicKeyB)).toEqual(expected)
|
|
40
|
+
expect(engine.getSharedSecret(privateKey, compressedPublicKeyB)).toEqual(
|
|
41
|
+
expected,
|
|
42
|
+
)
|
|
43
|
+
expect(engine.getSharedSecret(privateKeyB, publicKey)).toEqual(expected)
|
|
44
|
+
expect(expected).toHaveLength(33)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('behavior: matches signing across payload and entropy boundaries', async () => {
|
|
48
|
+
const engine = await Secp256k1.engine()
|
|
49
|
+
const publicKey = secp256k1.getPublicKey(privateKey, false)
|
|
50
|
+
|
|
51
|
+
for (const size of [0, 1, 31, 32, 33, 63, 64, 65, 127, 1024, 8192])
|
|
52
|
+
for (const prehash of [false, true])
|
|
53
|
+
for (const extraEntropy of [
|
|
54
|
+
false,
|
|
55
|
+
new Uint8Array(),
|
|
56
|
+
Uint8Array.of(1),
|
|
57
|
+
new Uint8Array(32).fill(7),
|
|
58
|
+
new Uint8Array(100).fill(9),
|
|
59
|
+
] as const) {
|
|
60
|
+
const payload = bytes(size)
|
|
61
|
+
const signature = engine.sign(payload, privateKey, {
|
|
62
|
+
extraEntropy,
|
|
63
|
+
prehash,
|
|
64
|
+
})
|
|
65
|
+
const expected = secp256k1.sign(payload, privateKey, {
|
|
66
|
+
extraEntropy,
|
|
67
|
+
format: 'recovered',
|
|
68
|
+
lowS: true,
|
|
69
|
+
prehash,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
expect(signature).toEqual(expected)
|
|
73
|
+
expect(
|
|
74
|
+
engine.verify(signature.slice(1), payload, publicKey, { prehash }),
|
|
75
|
+
).toBe(true)
|
|
76
|
+
expect(signature[0]).toBeOneOf([0, 1])
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('behavior: generates host entropy for hedged signing', async () => {
|
|
81
|
+
const engine = await Secp256k1.engine()
|
|
82
|
+
const payload = bytes(32)
|
|
83
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
84
|
+
const signatureA = engine.sign(payload, privateKey, {
|
|
85
|
+
extraEntropy: true,
|
|
86
|
+
prehash: false,
|
|
87
|
+
})
|
|
88
|
+
const signatureB = engine.sign(payload, privateKey, {
|
|
89
|
+
extraEntropy: true,
|
|
90
|
+
prehash: false,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
expect(signatureA).not.toEqual(signatureB)
|
|
94
|
+
expect(
|
|
95
|
+
engine.verify(signatureA.slice(1), payload, publicKey, {
|
|
96
|
+
prehash: false,
|
|
97
|
+
}),
|
|
98
|
+
).toBe(true)
|
|
99
|
+
expect(
|
|
100
|
+
engine.verify(signatureB.slice(1), payload, publicKey, {
|
|
101
|
+
prehash: false,
|
|
102
|
+
}),
|
|
103
|
+
).toBe(true)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('behavior: recovers the public key with both parities', async () => {
|
|
107
|
+
const engine = await Secp256k1.engine()
|
|
108
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
109
|
+
const signatures = new Map<
|
|
110
|
+
number,
|
|
111
|
+
{ payload: Uint8Array; signature: Uint8Array }
|
|
112
|
+
>()
|
|
113
|
+
|
|
114
|
+
for (let index = 0; signatures.size < 2; index++) {
|
|
115
|
+
const payload = bytes(32, index)
|
|
116
|
+
const signature = engine.sign(payload, privateKey, {
|
|
117
|
+
extraEntropy: false,
|
|
118
|
+
prehash: false,
|
|
119
|
+
})
|
|
120
|
+
signatures.set(signature[0]!, { payload, signature })
|
|
121
|
+
if (index > 100)
|
|
122
|
+
throw new Error('could not produce both recovery parities')
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const { payload, signature } of signatures.values())
|
|
126
|
+
expect(engine.recoverPublicKey(signature, payload)).toEqual(publicKey)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('behavior: rejects high-S signatures', async () => {
|
|
130
|
+
const engine = await Secp256k1.engine()
|
|
131
|
+
const payload = bytes(32)
|
|
132
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
133
|
+
const signature = engine
|
|
134
|
+
.sign(payload, privateKey, {
|
|
135
|
+
extraEntropy: false,
|
|
136
|
+
prehash: false,
|
|
137
|
+
})
|
|
138
|
+
.slice(1)
|
|
139
|
+
const highS = signature.slice()
|
|
140
|
+
highS.set(toBytes(curveOrder - toBigInt(signature.slice(32))), 32)
|
|
141
|
+
|
|
142
|
+
expect(
|
|
143
|
+
engine.verify(signature, payload, publicKey, { prehash: false }),
|
|
144
|
+
).toBe(true)
|
|
145
|
+
expect(engine.verify(highS, payload, publicKey, { prehash: false })).toBe(
|
|
146
|
+
false,
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('behavior: matches large payload boundaries', async () => {
|
|
151
|
+
const engine = await Secp256k1.engine()
|
|
152
|
+
const payload = bytes(8193)
|
|
153
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
154
|
+
const truncatedSignature = secp256k1.sign(
|
|
155
|
+
payload.slice(0, 32),
|
|
156
|
+
privateKey,
|
|
157
|
+
{
|
|
158
|
+
extraEntropy: false,
|
|
159
|
+
format: 'compact',
|
|
160
|
+
lowS: true,
|
|
161
|
+
prehash: false,
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
expect(() =>
|
|
166
|
+
engine.sign(payload, privateKey, {
|
|
167
|
+
extraEntropy: false,
|
|
168
|
+
prehash: false,
|
|
169
|
+
}),
|
|
170
|
+
).toThrowError(
|
|
171
|
+
'Secp256k1 unhashed payload must not exceed 8192 bytes, got 8193',
|
|
172
|
+
)
|
|
173
|
+
expect(
|
|
174
|
+
engine.verify(new Uint8Array(64), payload, publicKey, {
|
|
175
|
+
prehash: false,
|
|
176
|
+
}),
|
|
177
|
+
).toBe(false)
|
|
178
|
+
expect(
|
|
179
|
+
secp256k1.verify(truncatedSignature, payload, publicKey, {
|
|
180
|
+
lowS: true,
|
|
181
|
+
prehash: false,
|
|
182
|
+
}),
|
|
183
|
+
).toBe(false)
|
|
184
|
+
expect(
|
|
185
|
+
engine.verify(truncatedSignature, payload, publicKey, { prehash: false }),
|
|
186
|
+
).toBe(false)
|
|
187
|
+
expect(() =>
|
|
188
|
+
engine.recoverPublicKey(new Uint8Array(65), payload),
|
|
189
|
+
).toThrowError(
|
|
190
|
+
'Secp256k1 unhashed payload must not exceed 8192 bytes, got 8193',
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
const signature = engine.sign(payload, privateKey, {
|
|
194
|
+
extraEntropy: false,
|
|
195
|
+
prehash: true,
|
|
196
|
+
})
|
|
197
|
+
expect(
|
|
198
|
+
engine.verify(signature.slice(1), payload, publicKey, { prehash: true }),
|
|
199
|
+
).toBe(true)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
test('behavior: rejects malformed keys and recovered signatures', async () => {
|
|
203
|
+
const engine = await Secp256k1.engine()
|
|
204
|
+
const publicKey = engine.getPublicKey(privateKey)
|
|
205
|
+
const payload = bytes(32)
|
|
206
|
+
|
|
207
|
+
for (const size of [0, 1, 31, 33, 64, 65]) {
|
|
208
|
+
if (size !== 32) {
|
|
209
|
+
expect(() => engine.getPublicKey(new Uint8Array(size))).toThrowError(
|
|
210
|
+
`Secp256k1 private key must be 32 bytes, got ${size}`,
|
|
211
|
+
)
|
|
212
|
+
expect(() =>
|
|
213
|
+
engine.sign(payload, new Uint8Array(size), {
|
|
214
|
+
extraEntropy: false,
|
|
215
|
+
prehash: false,
|
|
216
|
+
}),
|
|
217
|
+
).toThrowError(`Secp256k1 private key must be 32 bytes, got ${size}`)
|
|
218
|
+
}
|
|
219
|
+
if (size !== 64)
|
|
220
|
+
expect(() =>
|
|
221
|
+
engine.verify(new Uint8Array(size), payload, publicKey, {
|
|
222
|
+
prehash: false,
|
|
223
|
+
}),
|
|
224
|
+
).toThrowError(`Secp256k1 signature must be 64 bytes, got ${size}`)
|
|
225
|
+
if (size !== 65)
|
|
226
|
+
expect(() =>
|
|
227
|
+
engine.recoverPublicKey(new Uint8Array(size), payload),
|
|
228
|
+
).toThrowError(`Secp256k1 signature must be 65 bytes, got ${size}`)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
for (const size of [0, 1, 32, 34, 64, 66])
|
|
232
|
+
expect(() =>
|
|
233
|
+
engine.getSharedSecret(privateKey, new Uint8Array(size)),
|
|
234
|
+
).toThrowError(`Secp256k1 public key must be 33 or 65 bytes, got ${size}`)
|
|
235
|
+
|
|
236
|
+
const invalidPrivateKeys = [
|
|
237
|
+
new Uint8Array(32),
|
|
238
|
+
toBytes(curveOrder),
|
|
239
|
+
toBytes(curveOrder + 1n),
|
|
240
|
+
]
|
|
241
|
+
for (const value of invalidPrivateKeys) {
|
|
242
|
+
expect(() => engine.getPublicKey(value)).toThrow(
|
|
243
|
+
Secp256k1.InvalidInputError,
|
|
244
|
+
)
|
|
245
|
+
expect(() => engine.getSharedSecret(value, publicKey)).toThrow(
|
|
246
|
+
Secp256k1.InvalidInputError,
|
|
247
|
+
)
|
|
248
|
+
expect(() =>
|
|
249
|
+
engine.sign(payload, value, {
|
|
250
|
+
extraEntropy: false,
|
|
251
|
+
prehash: false,
|
|
252
|
+
}),
|
|
253
|
+
).toThrow(Secp256k1.InvalidInputError)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
for (const publicKeySize of [33, 65]) {
|
|
257
|
+
const invalidPublicKey = new Uint8Array(publicKeySize)
|
|
258
|
+
expect(() =>
|
|
259
|
+
engine.getSharedSecret(privateKey, invalidPublicKey),
|
|
260
|
+
).toThrow(Secp256k1.InvalidInputError)
|
|
261
|
+
expect(
|
|
262
|
+
engine.verify(new Uint8Array(64), payload, invalidPublicKey, {
|
|
263
|
+
prehash: false,
|
|
264
|
+
}),
|
|
265
|
+
).toBe(false)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const invalidRecovery = new Uint8Array(65)
|
|
269
|
+
invalidRecovery[0] = 2
|
|
270
|
+
expect(() => engine.recoverPublicKey(invalidRecovery, payload)).toThrow(
|
|
271
|
+
Secp256k1.InvalidInputError,
|
|
272
|
+
)
|
|
273
|
+
expect(() => engine.recoverPublicKey(new Uint8Array(65), payload)).toThrow(
|
|
274
|
+
Secp256k1.InvalidInputError,
|
|
275
|
+
)
|
|
276
|
+
expect(
|
|
277
|
+
engine.verify(new Uint8Array(64), payload, publicKey, {
|
|
278
|
+
prehash: false,
|
|
279
|
+
}),
|
|
280
|
+
).toBe(false)
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
test('behavior: preserves subviews, input ownership, and output ownership', async () => {
|
|
284
|
+
const engine = await Secp256k1.engine()
|
|
285
|
+
const key = offsetView(privateKey)
|
|
286
|
+
const payload = offsetView(bytes(257))
|
|
287
|
+
const publicKey = offsetView(engine.getPublicKey(key))
|
|
288
|
+
const before = {
|
|
289
|
+
key: key.slice(),
|
|
290
|
+
payload: payload.slice(),
|
|
291
|
+
publicKey: publicKey.slice(),
|
|
292
|
+
}
|
|
293
|
+
const signature = engine.sign(payload, key, {
|
|
294
|
+
extraEntropy: false,
|
|
295
|
+
prehash: false,
|
|
296
|
+
})
|
|
297
|
+
const outputs = [
|
|
298
|
+
engine.getPublicKey(key),
|
|
299
|
+
engine.getSharedSecret(key, publicKey),
|
|
300
|
+
signature,
|
|
301
|
+
engine.recoverPublicKey(signature, payload),
|
|
302
|
+
]
|
|
303
|
+
const snapshots = outputs.map((output) => output.slice())
|
|
304
|
+
|
|
305
|
+
engine.sign(new Uint8Array(1024 * 1024), key, {
|
|
306
|
+
extraEntropy: false,
|
|
307
|
+
prehash: true,
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
expect(outputs).toEqual(snapshots)
|
|
311
|
+
expect({ key, payload, publicKey }).toEqual(before)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
test('behavior: clears the shared staging region', async () => {
|
|
315
|
+
const engine = await Secp256k1.engine()
|
|
316
|
+
const payload = new Uint8Array(1024).fill(0xa5)
|
|
317
|
+
const entropy = new Uint8Array(17).fill(0x5a)
|
|
318
|
+
engine.sign(payload, privateKey, {
|
|
319
|
+
extraEntropy: entropy,
|
|
320
|
+
prehash: false,
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
const module = await secp256k1_internal.load()
|
|
324
|
+
const size = payload.length + 32 + entropy.length + 65
|
|
325
|
+
expect(
|
|
326
|
+
module
|
|
327
|
+
.view()
|
|
328
|
+
.subarray(module.heapBase, module.heapBase + size)
|
|
329
|
+
.every((byte) => byte === 0),
|
|
330
|
+
).toBe(true)
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
function bytes(length: number, offset = length): Uint8Array {
|
|
335
|
+
return Uint8Array.from({ length }, (_, index) => (index * 29 + offset) % 251)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function fromHex(value: string): Uint8Array {
|
|
339
|
+
return Uint8Array.from(Buffer.from(value, 'hex'))
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function offsetView(value: Uint8Array): Uint8Array {
|
|
343
|
+
const bytes = new Uint8Array(value.length + 4).fill(0xff)
|
|
344
|
+
bytes.set(value, 2)
|
|
345
|
+
return bytes.subarray(2, -2)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function toBigInt(value: Uint8Array): bigint {
|
|
349
|
+
return BigInt(`0x${Buffer.from(value).toString('hex')}`)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function toBytes(value: bigint): Uint8Array {
|
|
353
|
+
return fromHex(value.toString(16).padStart(64, '0'))
|
|
354
|
+
}
|
package/src/wasm/index.ts
CHANGED
|
@@ -64,7 +64,8 @@ export * as Ed25519 from './Ed25519.js'
|
|
|
64
64
|
export * as Hash from './Hash.js'
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* WASM
|
|
67
|
+
* WASM implementations of Ox's synchronous PBKDF2-HMAC-SHA256 and scrypt
|
|
68
|
+
* primitives.
|
|
68
69
|
*
|
|
69
70
|
* @example
|
|
70
71
|
* ```ts twoslash
|
|
@@ -81,6 +82,29 @@ export * as Hash from './Hash.js'
|
|
|
81
82
|
*/
|
|
82
83
|
export * as Keystore from './Keystore.js'
|
|
83
84
|
|
|
85
|
+
/**
|
|
86
|
+
* WASM implementation of Ox's KZG interface, backed by c-kzg-4844.
|
|
87
|
+
*
|
|
88
|
+
* This module is not installed into [`Engine`](/api/Engine). Create an explicit
|
|
89
|
+
* instance, pass it anywhere that accepts `Kzg.Kzg`, and dispose it when done.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts twoslash
|
|
93
|
+
* // @noErrors
|
|
94
|
+
* import { Setups } from 'ox/trusted-setups'
|
|
95
|
+
* import { Kzg } from 'ox/wasm'
|
|
96
|
+
*
|
|
97
|
+
* const kzg = await Kzg.create({
|
|
98
|
+
* trustedSetup: Setups.mainnet
|
|
99
|
+
* })
|
|
100
|
+
*
|
|
101
|
+
* kzg.dispose()
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @category Crypto
|
|
105
|
+
*/
|
|
106
|
+
export * as Kzg from './Kzg.js'
|
|
107
|
+
|
|
84
108
|
/**
|
|
85
109
|
* WASM implementation of Ox's BIP-39 seed derivation.
|
|
86
110
|
*
|
|
@@ -101,6 +125,27 @@ export * as Keystore from './Keystore.js'
|
|
|
101
125
|
*/
|
|
102
126
|
export * as Mnemonic from './Mnemonic.js'
|
|
103
127
|
|
|
128
|
+
/**
|
|
129
|
+
* WASM implementations of deterministic Secp256k1 primitives.
|
|
130
|
+
*
|
|
131
|
+
* This provider is opt-in because its embedded libsecp256k1 artifact is larger
|
|
132
|
+
* than the modules installed by [`Engine.install`](/api/Engine/install).
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts twoslash
|
|
136
|
+
* // @noErrors
|
|
137
|
+
* import { Engine } from 'ox'
|
|
138
|
+
* import { Secp256k1 } from 'ox/wasm'
|
|
139
|
+
*
|
|
140
|
+
* await Engine.install({ Secp256k1: Secp256k1.engine() })
|
|
141
|
+
*
|
|
142
|
+
* Secp256k1.getPublicKey({ privateKey: '0x...' })
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @category Crypto
|
|
146
|
+
*/
|
|
147
|
+
export * as Secp256k1 from './Secp256k1.js'
|
|
148
|
+
|
|
104
149
|
/**
|
|
105
150
|
* WASM implementations of Ox's supported X25519 primitives.
|
|
106
151
|
*
|