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
package/src/core/Hash.ts
CHANGED
|
@@ -1,8 +1,246 @@
|
|
|
1
1
|
import * as Bytes from './Bytes.js'
|
|
2
|
-
import
|
|
2
|
+
import * as Errors from './Errors.js'
|
|
3
3
|
import * as Hex from './Hex.js'
|
|
4
|
+
import type { HashState } from './internal/engine.js'
|
|
4
5
|
import * as engine from './internal/hash.js'
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Incremental hash state.
|
|
9
|
+
*
|
|
10
|
+
* A hasher accepts any number of chunks. Calling `digest` or `digestInto`
|
|
11
|
+
* consumes the state. Call `clone` before finalizing to branch from the same
|
|
12
|
+
* prefix.
|
|
13
|
+
*/
|
|
14
|
+
export type Hasher = {
|
|
15
|
+
/** Creates an independent copy of the current state. */
|
|
16
|
+
clone(): Hasher
|
|
17
|
+
/** Destroys the state. Calling `destroy` more than once has no effect. */
|
|
18
|
+
destroy(): void
|
|
19
|
+
/** Finalizes the digest and consumes the state. */
|
|
20
|
+
digest<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
21
|
+
options?: Hasher.DigestOptions<as>,
|
|
22
|
+
): Hasher.DigestReturnType<as>
|
|
23
|
+
/**
|
|
24
|
+
* Finalizes into the start of `output` and consumes the state.
|
|
25
|
+
*
|
|
26
|
+
* `output` may be larger than the digest. Bytes after the digest are left
|
|
27
|
+
* unchanged.
|
|
28
|
+
*/
|
|
29
|
+
digestInto(output: Bytes.Bytes): void
|
|
30
|
+
/** Absorbs a message chunk. */
|
|
31
|
+
update(value: Hex.Hex | Bytes.Bytes): Hasher
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export declare namespace Hasher {
|
|
35
|
+
/** Options for `Hasher.digest`. */
|
|
36
|
+
type DigestOptions<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
37
|
+
/** The return type. @default 'Hex' */
|
|
38
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Return type for `Hasher.digest`. */
|
|
42
|
+
type DigestReturnType<as extends 'Hex' | 'Bytes' = 'Hex'> =
|
|
43
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
44
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
45
|
+
|
|
46
|
+
/** Errors thrown by an incremental hash state. */
|
|
47
|
+
type ErrorType =
|
|
48
|
+
| HasherDestroyedError
|
|
49
|
+
| InvalidDigestSizeError
|
|
50
|
+
| Bytes.from.ErrorType
|
|
51
|
+
| Hex.fromBytes.ErrorType
|
|
52
|
+
| Errors.GlobalErrorType
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates an incremental BLAKE3 hasher.
|
|
57
|
+
*
|
|
58
|
+
* The installed Engine provider is captured when this function is called.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts twoslash
|
|
62
|
+
* import { Hash } from 'ox'
|
|
63
|
+
*
|
|
64
|
+
* const hash = Hash.createBlake3()
|
|
65
|
+
* hash.update('0xdead')
|
|
66
|
+
* hash.update('0xbeef')
|
|
67
|
+
* hash.digest()
|
|
68
|
+
* // @log: '0x53147f3ce49ed4f60dfa5b9654c36ba6103c11f5737df3dabd4cbd296c4161bd'
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @returns An incremental BLAKE3 hasher.
|
|
72
|
+
*/
|
|
73
|
+
export function createBlake3(): Hasher {
|
|
74
|
+
return fromState(engine.createBlake3(), 32)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export declare namespace createBlake3 {
|
|
78
|
+
type ErrorType = Hasher.ErrorType
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates an incremental HMAC-SHA256 hasher.
|
|
83
|
+
*
|
|
84
|
+
* The installed Engine provider is captured when this function is called.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts twoslash
|
|
88
|
+
* import { Hash, Hex } from 'ox'
|
|
89
|
+
*
|
|
90
|
+
* const hash = Hash.createHmac256(Hex.fromString('key'))
|
|
91
|
+
* hash.update('0xdead')
|
|
92
|
+
* hash.update('0xbeef')
|
|
93
|
+
* hash.digest()
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @param key - HMAC key.
|
|
97
|
+
* @returns An incremental HMAC-SHA256 hasher.
|
|
98
|
+
*/
|
|
99
|
+
export function createHmac256(key: Hex.Hex | Bytes.Bytes): Hasher {
|
|
100
|
+
return fromState(engine.createHmacSha256(Bytes.from(key)), 32)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export declare namespace createHmac256 {
|
|
104
|
+
type ErrorType = Hasher.ErrorType
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Creates an incremental Keccak256 hasher.
|
|
109
|
+
*
|
|
110
|
+
* The installed Engine provider is captured when this function is called.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts twoslash
|
|
114
|
+
* import { Hash } from 'ox'
|
|
115
|
+
*
|
|
116
|
+
* const hash = Hash.createKeccak256()
|
|
117
|
+
* hash.update('0xdead')
|
|
118
|
+
* hash.update('0xbeef')
|
|
119
|
+
* hash.digest()
|
|
120
|
+
* // @log: '0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1'
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @returns An incremental Keccak256 hasher.
|
|
124
|
+
*/
|
|
125
|
+
export function createKeccak256(): Hasher {
|
|
126
|
+
return fromState(engine.createKeccak256(), 32)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export declare namespace createKeccak256 {
|
|
130
|
+
type ErrorType = Hasher.ErrorType
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Creates an incremental RIPEMD-160 hasher.
|
|
135
|
+
*
|
|
136
|
+
* The installed Engine provider is captured when this function is called.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts twoslash
|
|
140
|
+
* import { Hash } from 'ox'
|
|
141
|
+
*
|
|
142
|
+
* const hash = Hash.createRipemd160()
|
|
143
|
+
* hash.update('0xdead')
|
|
144
|
+
* hash.update('0xbeef')
|
|
145
|
+
* hash.digest()
|
|
146
|
+
* // @log: '0x226821c2f5423e11fe9af68bd285c249db2e4b5a'
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @returns An incremental RIPEMD-160 hasher.
|
|
150
|
+
*/
|
|
151
|
+
export function createRipemd160(): Hasher {
|
|
152
|
+
return fromState(engine.createRipemd160(), 20)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export declare namespace createRipemd160 {
|
|
156
|
+
type ErrorType = Hasher.ErrorType
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Creates an incremental SHA-256 hasher.
|
|
161
|
+
*
|
|
162
|
+
* The installed Engine provider is captured when this function is called.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts twoslash
|
|
166
|
+
* import { Hash } from 'ox'
|
|
167
|
+
*
|
|
168
|
+
* const hash = Hash.createSha256()
|
|
169
|
+
* hash.update('0xdead')
|
|
170
|
+
* hash.update('0xbeef')
|
|
171
|
+
* hash.digest()
|
|
172
|
+
* // @log: '0x5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953'
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* @returns An incremental SHA-256 hasher.
|
|
176
|
+
*/
|
|
177
|
+
export function createSha256(): Hasher {
|
|
178
|
+
return fromState(engine.createSha256(), 32)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export declare namespace createSha256 {
|
|
182
|
+
type ErrorType = Hasher.ErrorType
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Calculates the [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
|
|
187
|
+
*
|
|
188
|
+
* Backed by `blake3` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library, unless another implementation is installed with {@link ox#Engine.set}.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts twoslash
|
|
192
|
+
* import { Hash } from 'ox'
|
|
193
|
+
*
|
|
194
|
+
* Hash.blake3('0xdeadbeef')
|
|
195
|
+
* // @log: '0x53147f3ce49ed4f60dfa5b9654c36ba6103c11f5737df3dabd4cbd296c4161bd'
|
|
196
|
+
* ```
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ### Configure Return Type
|
|
200
|
+
*
|
|
201
|
+
* ```ts twoslash
|
|
202
|
+
* import { Hash } from 'ox'
|
|
203
|
+
*
|
|
204
|
+
* Hash.blake3('0xdeadbeef', { as: 'Bytes' })
|
|
205
|
+
* // @log: Uint8Array [...]
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @param value - {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
|
|
209
|
+
* @param options - Options.
|
|
210
|
+
* @returns BLAKE3 hash.
|
|
211
|
+
*/
|
|
212
|
+
export function blake3<
|
|
213
|
+
value extends Hex.Hex | Bytes.Bytes,
|
|
214
|
+
as extends 'Hex' | 'Bytes' =
|
|
215
|
+
| (value extends Hex.Hex ? 'Hex' : never)
|
|
216
|
+
| (value extends Bytes.Bytes ? 'Bytes' : never),
|
|
217
|
+
>(
|
|
218
|
+
value: value | Hex.Hex | Bytes.Bytes,
|
|
219
|
+
options: blake3.Options<as> = {},
|
|
220
|
+
): blake3.ReturnType<as> {
|
|
221
|
+
const isBytes = value instanceof Uint8Array
|
|
222
|
+
const { as = isBytes ? 'Bytes' : 'Hex' } = options
|
|
223
|
+
const bytes = engine.blake3(isBytes ? value : Bytes.from(value))
|
|
224
|
+
if (as === 'Bytes') return bytes as never
|
|
225
|
+
return Hex.fromBytes(bytes) as never
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export declare namespace blake3 {
|
|
229
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> = {
|
|
230
|
+
/** The return type. Defaults to the input format. */
|
|
231
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
|
|
235
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
236
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
237
|
+
|
|
238
|
+
type ErrorType =
|
|
239
|
+
| Bytes.from.ErrorType
|
|
240
|
+
| Hex.fromBytes.ErrorType
|
|
241
|
+
| Errors.GlobalErrorType
|
|
242
|
+
}
|
|
243
|
+
|
|
6
244
|
/**
|
|
7
245
|
* Calculates the [Keccak256](https://en.wikipedia.org/wiki/SHA-3) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
|
|
8
246
|
*
|
|
@@ -264,3 +502,85 @@ export declare namespace validate {
|
|
|
264
502
|
| Hex.size.ErrorType
|
|
265
503
|
| Errors.GlobalErrorType
|
|
266
504
|
}
|
|
505
|
+
|
|
506
|
+
/** Thrown when an incremental hash state has been consumed or destroyed. */
|
|
507
|
+
export class HasherDestroyedError extends Errors.BaseError {
|
|
508
|
+
override readonly name = 'Hash.HasherDestroyedError'
|
|
509
|
+
|
|
510
|
+
constructor() {
|
|
511
|
+
super('Hasher has been destroyed.')
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** Thrown when a digest output buffer is too small. */
|
|
516
|
+
export class InvalidDigestSizeError extends Errors.BaseError {
|
|
517
|
+
override readonly name = 'Hash.InvalidDigestSizeError'
|
|
518
|
+
|
|
519
|
+
constructor(options: InvalidDigestSizeError.Options) {
|
|
520
|
+
const { minimum, size } = options
|
|
521
|
+
super(
|
|
522
|
+
`Digest output is too small. Expected at least ${minimum} bytes. Received ${size} bytes.`,
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export declare namespace InvalidDigestSizeError {
|
|
528
|
+
type Options = {
|
|
529
|
+
/** Minimum output size. */
|
|
530
|
+
minimum: number
|
|
531
|
+
/** Received output size. */
|
|
532
|
+
size: number
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function fromState(state: HashState, digestSize: number): Hasher {
|
|
537
|
+
let active = true
|
|
538
|
+
|
|
539
|
+
const assertActive = () => {
|
|
540
|
+
if (!active) throw new HasherDestroyedError()
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const consume = <returnType>(fn: () => returnType): returnType => {
|
|
544
|
+
assertActive()
|
|
545
|
+
active = false
|
|
546
|
+
try {
|
|
547
|
+
return fn()
|
|
548
|
+
} finally {
|
|
549
|
+
state.destroy()
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const hasher: Hasher = {
|
|
554
|
+
clone() {
|
|
555
|
+
assertActive()
|
|
556
|
+
return fromState(state.clone(), digestSize)
|
|
557
|
+
},
|
|
558
|
+
destroy() {
|
|
559
|
+
if (!active) return
|
|
560
|
+
active = false
|
|
561
|
+
state.destroy()
|
|
562
|
+
},
|
|
563
|
+
digest(options = {}) {
|
|
564
|
+
const value = new Uint8Array(digestSize)
|
|
565
|
+
consume(() => state.digestInto(value))
|
|
566
|
+
if (options.as === 'Bytes') return value as never
|
|
567
|
+
return Hex.fromBytes(value) as never
|
|
568
|
+
},
|
|
569
|
+
digestInto(output) {
|
|
570
|
+
assertActive()
|
|
571
|
+
if (output.length < digestSize)
|
|
572
|
+
throw new InvalidDigestSizeError({
|
|
573
|
+
minimum: digestSize,
|
|
574
|
+
size: output.length,
|
|
575
|
+
})
|
|
576
|
+
consume(() => state.digestInto(output))
|
|
577
|
+
},
|
|
578
|
+
update(value) {
|
|
579
|
+
assertActive()
|
|
580
|
+
state.update(Bytes.from(value))
|
|
581
|
+
return hasher
|
|
582
|
+
},
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return hasher
|
|
586
|
+
}
|
package/src/core/Hex.ts
CHANGED
|
@@ -74,10 +74,7 @@ export function concat(...values: readonly Hex[]): Hex {
|
|
|
74
74
|
if (values.length === 1) return values[0]!
|
|
75
75
|
if (values.length === 2)
|
|
76
76
|
return `0x${(values[0] as string).slice(2)}${(values[1] as string).slice(2)}` as Hex
|
|
77
|
-
|
|
78
|
-
for (let i = 0; i < values.length; i++)
|
|
79
|
-
parts[i] = (values[i] as string).slice(2)
|
|
80
|
-
return `0x${parts.join('')}` as Hex
|
|
77
|
+
return `0x${values.reduce((hex, value) => hex + value.replace('0x', ''), '')}`
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
export declare namespace concat {
|
package/src/core/Rlp.ts
CHANGED
|
@@ -192,6 +192,48 @@ export declare namespace readList {
|
|
|
192
192
|
| Errors.GlobalErrorType
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Encodes a value as Recursive-Length Prefix (RLP) and writes the encoded bytes
|
|
197
|
+
* through a synchronous callback without allocating the complete encoding.
|
|
198
|
+
*
|
|
199
|
+
* Ox validates the complete input before the first write. If the callback
|
|
200
|
+
* throws, the error propagates and earlier callback side effects remain.
|
|
201
|
+
*
|
|
202
|
+
* Ox does not mutate a chunk after the callback returns. A chunk may alias a
|
|
203
|
+
* byte-array leaf from the encoded value. The callback must not mutate the
|
|
204
|
+
* chunk before `encodeTo` returns.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts twoslash
|
|
208
|
+
* import { Bytes, Rlp } from 'ox'
|
|
209
|
+
*
|
|
210
|
+
* const chunks: Uint8Array[] = []
|
|
211
|
+
* Rlp.encodeTo(['0x01', '0x0203'], (chunk) => {
|
|
212
|
+
* chunks.push(chunk)
|
|
213
|
+
* })
|
|
214
|
+
*
|
|
215
|
+
* const encoded = Bytes.concat(...chunks)
|
|
216
|
+
* // @log: Uint8Array([196, 1, 130, 2, 3])
|
|
217
|
+
* ```
|
|
218
|
+
*
|
|
219
|
+
* @param value - The bytes or Hex value, or nested list of values, to encode.
|
|
220
|
+
* @param write - The synchronous callback for encoded chunks.
|
|
221
|
+
* @returns Nothing.
|
|
222
|
+
*/
|
|
223
|
+
export function encodeTo(
|
|
224
|
+
value: RecursiveArray<Bytes.Bytes> | RecursiveArray<Hex.Hex>,
|
|
225
|
+
write: (chunk: Bytes.Bytes) => undefined,
|
|
226
|
+
): void {
|
|
227
|
+
const snapshot = snapshotValue(value)
|
|
228
|
+
const ctx: EncodeCtx = { lengths: [], cursor: 0 }
|
|
229
|
+
measure(snapshot, ctx)
|
|
230
|
+
writeEncodedTo(write, snapshot, { lengths: ctx.lengths, cursor: 0 })
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export declare namespace encodeTo {
|
|
234
|
+
type ErrorType = Errors.BaseError | Errors.GlobalErrorType
|
|
235
|
+
}
|
|
236
|
+
|
|
195
237
|
/**
|
|
196
238
|
* Encodes a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value into a Recursive-Length Prefix (RLP) value.
|
|
197
239
|
*
|
|
@@ -368,7 +410,29 @@ function getSizeOfLength(length: number) {
|
|
|
368
410
|
*
|
|
369
411
|
* @internal
|
|
370
412
|
*/
|
|
371
|
-
type EncodeCtx = {
|
|
413
|
+
type EncodeCtx = {
|
|
414
|
+
cursor: number
|
|
415
|
+
lengths: number[]
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
type Encodable = RecursiveArray<Bytes.Bytes | Hex.Hex>
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Validates Hex leaves and copies list structure before the callback can mutate
|
|
422
|
+
* the input during encoding. Byte leaves remain zero-copy.
|
|
423
|
+
*
|
|
424
|
+
* @internal
|
|
425
|
+
*/
|
|
426
|
+
function snapshotValue(value: Encodable): Encodable {
|
|
427
|
+
if (Array.isArray(value)) {
|
|
428
|
+
const snapshot: Encodable[] = []
|
|
429
|
+
for (let i = 0; i < value.length; i++)
|
|
430
|
+
snapshot.push(snapshotValue(value[i]!))
|
|
431
|
+
return snapshot
|
|
432
|
+
}
|
|
433
|
+
if (typeof value === 'string') validateHexLeaf(value)
|
|
434
|
+
return value
|
|
435
|
+
}
|
|
372
436
|
|
|
373
437
|
/**
|
|
374
438
|
* Walks `value` once, caches each list's `bodyLength` into `ctx.lengths`,
|
|
@@ -377,10 +441,7 @@ type EncodeCtx = { lengths: number[]; cursor: number }
|
|
|
377
441
|
*
|
|
378
442
|
* @internal
|
|
379
443
|
*/
|
|
380
|
-
function measure(
|
|
381
|
-
value: RecursiveArray<Bytes.Bytes> | RecursiveArray<Hex.Hex>,
|
|
382
|
-
ctx: EncodeCtx,
|
|
383
|
-
): number {
|
|
444
|
+
function measure(value: Encodable, ctx: EncodeCtx): number {
|
|
384
445
|
if (Array.isArray(value)) {
|
|
385
446
|
// Reserve this list's slot before descending so children's slots come
|
|
386
447
|
// after ours; `writeEncoded` walks in the same order and reads slot N
|
|
@@ -458,6 +519,112 @@ function writeEncoded(
|
|
|
458
519
|
return writeBytesLeaf(bytes, offset, value as Bytes.Bytes)
|
|
459
520
|
}
|
|
460
521
|
|
|
522
|
+
const writeChunkSize = 16_384
|
|
523
|
+
|
|
524
|
+
type Write = (chunk: Bytes.Bytes) => undefined
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Writes an RLP value using list lengths cached by `measure`.
|
|
528
|
+
*
|
|
529
|
+
* @internal
|
|
530
|
+
*/
|
|
531
|
+
function writeEncodedTo(write: Write, value: Encodable, ctx: EncodeCtx): void {
|
|
532
|
+
if (Array.isArray(value)) {
|
|
533
|
+
write(encodePrefix(ctx.lengths[ctx.cursor++]!, 0xc0))
|
|
534
|
+
for (let i = 0; i < value.length; i++) writeEncodedTo(write, value[i]!, ctx)
|
|
535
|
+
return
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (typeof value === 'string') {
|
|
539
|
+
writeHexLeafTo(write, value)
|
|
540
|
+
return
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
writeBytesLeafTo(write, value as Bytes.Bytes)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Writes a Hex leaf in bounded chunks. `snapshotValue` validated every nibble
|
|
548
|
+
* before this function can run.
|
|
549
|
+
*
|
|
550
|
+
* @internal
|
|
551
|
+
*/
|
|
552
|
+
function writeHexLeafTo(write: Write, hex: Hex.Hex): void {
|
|
553
|
+
const byteLength = (hex.length - 1) >> 1
|
|
554
|
+
if (byteLength === 1 && readHexByte(hex, 0) < 0x80) {
|
|
555
|
+
write(Uint8Array.of(readHexByte(hex, 0)))
|
|
556
|
+
return
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
write(encodePrefix(byteLength, 0x80))
|
|
560
|
+
for (let offset = 0; offset < byteLength; offset += writeChunkSize) {
|
|
561
|
+
const length = Math.min(writeChunkSize, byteLength - offset)
|
|
562
|
+
const chunk = new Uint8Array(length)
|
|
563
|
+
for (let i = 0; i < length; i++) chunk[i] = readHexByte(hex, offset + i)
|
|
564
|
+
write(chunk)
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Writes a byte leaf without copying its body.
|
|
570
|
+
*
|
|
571
|
+
* @internal
|
|
572
|
+
*/
|
|
573
|
+
function writeBytesLeafTo(write: Write, leaf: Bytes.Bytes): void {
|
|
574
|
+
const length = leaf.length
|
|
575
|
+
if (length === 1 && leaf[0]! < 0x80) {
|
|
576
|
+
write(leaf)
|
|
577
|
+
return
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
write(encodePrefix(length, 0x80))
|
|
581
|
+
if (length > 0) write(leaf)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Encodes a string or list length prefix.
|
|
586
|
+
*
|
|
587
|
+
* @internal
|
|
588
|
+
*/
|
|
589
|
+
function encodePrefix(length: number, offset: 0x80 | 0xc0): Uint8Array {
|
|
590
|
+
if (length <= 55) return Uint8Array.of(offset + length)
|
|
591
|
+
|
|
592
|
+
const size = getSizeOfLength(length)
|
|
593
|
+
const prefix = new Uint8Array(size + 1)
|
|
594
|
+
prefix[0] = offset + 55 + size
|
|
595
|
+
writeBigEndian(prefix, 1, length, size)
|
|
596
|
+
return prefix
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Reads one byte from an odd- or even-nibble Hex value.
|
|
601
|
+
*
|
|
602
|
+
* @internal
|
|
603
|
+
*/
|
|
604
|
+
function readHexByte(hex: Hex.Hex, index: number): number {
|
|
605
|
+
const odd = (hex.length & 1) === 1
|
|
606
|
+
if (odd && index === 0)
|
|
607
|
+
return internal_bytes.charCodeToBase16(hex.charCodeAt(2))!
|
|
608
|
+
|
|
609
|
+
const nibble = odd ? index * 2 - 1 : index * 2
|
|
610
|
+
const high = internal_bytes.charCodeToBase16(hex.charCodeAt(2 + nibble))!
|
|
611
|
+
const low = internal_bytes.charCodeToBase16(hex.charCodeAt(3 + nibble))!
|
|
612
|
+
return (high << 4) | low
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Validates a Hex leaf while preserving RLP's odd-nibble left-padding.
|
|
617
|
+
*
|
|
618
|
+
* @internal
|
|
619
|
+
*/
|
|
620
|
+
function validateHexLeaf(hex: string): asserts hex is Hex.Hex {
|
|
621
|
+
if (hex.length < 2 || hex.charCodeAt(0) !== 48 || hex.charCodeAt(1) !== 120)
|
|
622
|
+
throw invalidNibble(hex as Hex.Hex)
|
|
623
|
+
for (let i = 2; i < hex.length; i++)
|
|
624
|
+
if (internal_bytes.charCodeToBase16(hex.charCodeAt(i)) === undefined)
|
|
625
|
+
throw invalidNibble(hex as Hex.Hex)
|
|
626
|
+
}
|
|
627
|
+
|
|
461
628
|
/**
|
|
462
629
|
* Hex-leaf fast path: writes the RLP encoding of a hex string directly into
|
|
463
630
|
* `bytes` by nibble-decoding the source hex chars into the destination
|
package/src/core/Secp256k1.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { secp256k1 } from '@noble/curves/secp256k1.js'
|
|
2
2
|
import * as Address from './Address.js'
|
|
3
3
|
import * as Bytes from './Bytes.js'
|
|
4
|
-
import
|
|
4
|
+
import * as Errors from './Errors.js'
|
|
5
|
+
import * as Hash from './Hash.js'
|
|
5
6
|
import * as Hex from './Hex.js'
|
|
6
7
|
import {
|
|
7
8
|
formatPublicKey,
|
|
@@ -71,6 +72,75 @@ export declare namespace createKeyPair {
|
|
|
71
72
|
| Errors.GlobalErrorType
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Derives a valid secp256k1 private key from a 32-byte WebAuthn PRF output.
|
|
77
|
+
*
|
|
78
|
+
* The permanent derivation contract uses the PRF output as the HMAC-SHA256
|
|
79
|
+
* key. Its message is the UTF-8 bytes of `ox.secp256k1.fromPrf.v1` followed by
|
|
80
|
+
* a 32-bit big-endian counter starting at zero. Invalid scalars are skipped.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts twoslash
|
|
84
|
+
* import { Secp256k1 } from 'ox'
|
|
85
|
+
*
|
|
86
|
+
* const privateKey = Secp256k1.fromPrf(
|
|
87
|
+
* '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
|
|
88
|
+
* )
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @param value - A 32-byte WebAuthn PRF output.
|
|
92
|
+
* @param options - Options.
|
|
93
|
+
* @returns A valid secp256k1 private key.
|
|
94
|
+
*/
|
|
95
|
+
export function fromPrf<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
96
|
+
value: Hex.Hex | Bytes.Bytes,
|
|
97
|
+
options: fromPrf.Options<as> = {},
|
|
98
|
+
): fromPrf.ReturnType<as> {
|
|
99
|
+
const { as = 'Hex' } = options
|
|
100
|
+
const bytes = Bytes.from(value)
|
|
101
|
+
if (bytes.length !== 32) throw new InvalidPrfSizeError({ size: bytes.length })
|
|
102
|
+
|
|
103
|
+
for (let counter = 0; ; counter++) {
|
|
104
|
+
const candidate = Hash.hmac256(
|
|
105
|
+
bytes,
|
|
106
|
+
Bytes.concat(fromPrfLabel, Bytes.fromNumber(counter, { size: 4 })),
|
|
107
|
+
{ as: 'Bytes' },
|
|
108
|
+
)
|
|
109
|
+
if (noble.utils.isValidSecretKey(candidate)) {
|
|
110
|
+
if (as === 'Hex') {
|
|
111
|
+
const value = Hex.fromBytes(candidate)
|
|
112
|
+
candidate.fill(0)
|
|
113
|
+
return value as never
|
|
114
|
+
}
|
|
115
|
+
return candidate as never
|
|
116
|
+
}
|
|
117
|
+
candidate.fill(0)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export declare namespace fromPrf {
|
|
122
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
123
|
+
/**
|
|
124
|
+
* Format of the returned private key.
|
|
125
|
+
* @default 'Hex'
|
|
126
|
+
*/
|
|
127
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
131
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
132
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
133
|
+
|
|
134
|
+
type ErrorType =
|
|
135
|
+
| Bytes.concat.ErrorType
|
|
136
|
+
| Bytes.from.ErrorType
|
|
137
|
+
| Bytes.fromNumber.ErrorType
|
|
138
|
+
| Hash.hmac256.ErrorType
|
|
139
|
+
| Hex.fromBytes.ErrorType
|
|
140
|
+
| InvalidPrfSizeError
|
|
141
|
+
| Errors.GlobalErrorType
|
|
142
|
+
}
|
|
143
|
+
|
|
74
144
|
/**
|
|
75
145
|
* Computes the secp256k1 ECDSA public key from a provided private key.
|
|
76
146
|
*
|
|
@@ -503,3 +573,24 @@ export declare namespace verify {
|
|
|
503
573
|
|
|
504
574
|
type ErrorType = Errors.GlobalErrorType
|
|
505
575
|
}
|
|
576
|
+
|
|
577
|
+
/** Thrown when a WebAuthn PRF output is not 32 bytes. */
|
|
578
|
+
export class InvalidPrfSizeError extends Errors.BaseError {
|
|
579
|
+
override readonly name = 'Secp256k1.InvalidPrfSizeError'
|
|
580
|
+
|
|
581
|
+
constructor(options: InvalidPrfSizeError.Options) {
|
|
582
|
+
super(
|
|
583
|
+
`PRF output must be exactly 32 bytes. Received ${options.size} bytes.`,
|
|
584
|
+
)
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
export declare namespace InvalidPrfSizeError {
|
|
589
|
+
/** Options for {@link ox#Secp256k1.InvalidPrfSizeError}. */
|
|
590
|
+
type Options = {
|
|
591
|
+
/** Received PRF output size. */
|
|
592
|
+
size: number
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const fromPrfLabel = Bytes.fromString('ox.secp256k1.fromPrf.v1')
|