voltaire-effect 0.2.23 → 0.2.24
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/dist/KZGService-B7PJerOb.d.ts +146 -0
- package/dist/{X25519Test-DGsk1V9o.d.ts → X25519Test-C8Cicdd_.d.ts} +2 -139
- package/dist/crypto/index.d.ts +3 -2
- package/dist/{index-IgkEHjBe.d.ts → index-DsFjN_a3.d.ts} +17633 -11961
- package/dist/index.d.ts +3104 -938
- package/dist/index.js +4467 -2446
- package/dist/native/index.d.ts +14 -5
- package/dist/native/index.js +4489 -2468
- package/dist/primitives/index.d.ts +12 -4
- package/dist/primitives/index.js +3980 -2411
- package/package.json +2 -2
- package/src/crypto/Keccak256/index.ts +1 -0
- package/src/index.ts +2 -2
- package/src/primitives/Abi/decode.test.ts +38 -0
- package/src/primitives/Abi/decode.ts +67 -0
- package/src/primitives/Abi/decodeData.test.ts +37 -0
- package/src/primitives/Abi/decodeData.ts +77 -0
- package/src/primitives/Abi/decodeLog.test.ts +32 -0
- package/src/primitives/Abi/decodeLog.ts +81 -0
- package/src/primitives/Abi/decodeWrappedError.test.ts +41 -0
- package/src/primitives/Abi/decodeWrappedError.ts +68 -0
- package/src/primitives/Abi/encode.test.ts +43 -0
- package/src/primitives/Abi/encode.ts +67 -0
- package/src/primitives/Abi/encodePacked.test.ts +35 -0
- package/src/primitives/Abi/encodePacked.ts +62 -0
- package/src/primitives/Abi/encodeWrappedError.test.ts +21 -0
- package/src/primitives/Abi/encodeWrappedError.ts +64 -0
- package/src/primitives/Abi/findSelectorCollisions.test.ts +50 -0
- package/src/primitives/Abi/findSelectorCollisions.ts +83 -0
- package/src/primitives/Abi/index.ts +33 -7
- package/src/primitives/Abi/parseLogs.test.ts +37 -0
- package/src/primitives/Abi/parseLogs.ts +62 -0
- package/src/primitives/AccessList/AccessList.test.ts +229 -0
- package/src/primitives/AccessList/AccessListTypeSchema.ts +16 -0
- package/src/primitives/AccessList/addressCount.ts +21 -0
- package/src/primitives/AccessList/assertValid.ts +37 -0
- package/src/primitives/AccessList/create.ts +19 -0
- package/src/primitives/AccessList/deduplicate.ts +23 -0
- package/src/primitives/AccessList/from.ts +39 -0
- package/src/primitives/AccessList/fromBytes.ts +36 -0
- package/src/primitives/AccessList/gasCost.ts +22 -0
- package/src/primitives/AccessList/gasSavings.ts +26 -0
- package/src/primitives/AccessList/hasSavings.ts +23 -0
- package/src/primitives/AccessList/includesAddress.ts +25 -0
- package/src/primitives/AccessList/includesStorageKey.ts +28 -0
- package/src/primitives/AccessList/index.ts +99 -19
- package/src/primitives/AccessList/is.ts +23 -0
- package/src/primitives/AccessList/isEmpty.ts +23 -0
- package/src/primitives/AccessList/isItem.ts +22 -0
- package/src/primitives/AccessList/keysFor.ts +29 -0
- package/src/primitives/AccessList/merge.ts +24 -0
- package/src/primitives/AccessList/storageKeyCount.ts +21 -0
- package/src/primitives/AccessList/toBytes.ts +23 -0
- package/src/primitives/AccessList/withAddress.ts +27 -0
- package/src/primitives/AccessList/withStorageKey.ts +30 -0
- package/src/primitives/Address/Address.test.ts +146 -0
- package/src/primitives/Address/assert.ts +51 -0
- package/src/primitives/Address/calculateCreate2Address.ts +33 -0
- package/src/primitives/Address/calculateCreateAddress.ts +30 -0
- package/src/primitives/Address/deduplicateAddresses.ts +20 -0
- package/src/primitives/Address/from.ts +41 -0
- package/src/primitives/Address/fromAbiEncoded.ts +35 -0
- package/src/primitives/Address/fromBase64.ts +25 -0
- package/src/primitives/Address/fromBytes.ts +25 -0
- package/src/primitives/Address/fromHex.ts +31 -0
- package/src/primitives/Address/fromNumber.ts +25 -0
- package/src/primitives/Address/fromPrivateKey.ts +25 -0
- package/src/primitives/Address/fromPublicKey.ts +56 -0
- package/src/primitives/Address/index.ts +99 -35
- package/src/primitives/Address/is.ts +20 -0
- package/src/primitives/Address/isAddress.ts +22 -0
- package/src/primitives/Address/sortAddresses.ts +19 -0
- package/src/primitives/Address/toChecksummed.ts +32 -0
- package/src/primitives/Address/toHex.ts +18 -0
- package/src/primitives/Address/zero.ts +18 -0
- package/src/primitives/Base64/Base64.test.ts +75 -0
- package/src/primitives/Base64/convert.ts +37 -0
- package/src/primitives/Base64/decode.ts +59 -0
- package/src/primitives/Base64/encode.ts +42 -0
- package/src/primitives/Base64/from.ts +39 -0
- package/src/primitives/Base64/index.ts +81 -1
- package/src/primitives/Base64/size.ts +16 -0
- package/src/primitives/Base64/validation.ts +16 -0
- package/src/primitives/Blob/Blob.test.ts +292 -0
- package/src/primitives/Blob/calculateGas.ts +30 -0
- package/src/primitives/Blob/estimateBlobCount.ts +30 -0
- package/src/primitives/Blob/from.ts +38 -0
- package/src/primitives/Blob/fromData.ts +36 -0
- package/src/primitives/Blob/index.ts +99 -12
- package/src/primitives/Blob/isValidVersion.ts +27 -0
- package/src/primitives/Blob/joinData.ts +43 -0
- package/src/primitives/Blob/splitData.ts +36 -0
- package/src/primitives/Blob/toCommitment.ts +43 -0
- package/src/primitives/Blob/toProof.ts +50 -0
- package/src/primitives/Blob/toVersionedHash.ts +35 -0
- package/src/primitives/Blob/verify.ts +49 -0
- package/src/primitives/Blob/verifyBatch.ts +119 -0
- package/src/primitives/BloomFilter/BloomFilter.test.ts +138 -0
- package/src/primitives/BloomFilter/add.ts +23 -0
- package/src/primitives/BloomFilter/combine.ts +21 -0
- package/src/primitives/BloomFilter/contains.ts +26 -0
- package/src/primitives/BloomFilter/create.ts +35 -0
- package/src/primitives/BloomFilter/density.ts +22 -0
- package/src/primitives/BloomFilter/expectedFalsePositiveRate.ts +25 -0
- package/src/primitives/BloomFilter/fromHex.ts +37 -0
- package/src/primitives/BloomFilter/hash.ts +43 -0
- package/src/primitives/BloomFilter/index.ts +59 -37
- package/src/primitives/BloomFilter/isEmpty.ts +22 -0
- package/src/primitives/BloomFilter/merge.ts +24 -0
- package/src/primitives/BloomFilter/toHex.ts +22 -0
- package/src/primitives/Bytecode/analyze.ts +58 -0
- package/src/primitives/Bytecode/detectFusions.ts +10 -0
- package/src/primitives/Bytecode/equals.ts +10 -0
- package/src/primitives/Bytecode/extractRuntime.ts +12 -0
- package/src/primitives/Bytecode/format.ts +16 -0
- package/src/primitives/Bytecode/from.ts +16 -0
- package/src/primitives/Bytecode/fromHex.ts +14 -0
- package/src/primitives/Bytecode/getBlock.ts +12 -0
- package/src/primitives/Bytecode/getNextPc.ts +12 -0
- package/src/primitives/Bytecode/getPushSize.ts +8 -0
- package/src/primitives/Bytecode/hasMetadata.ts +10 -0
- package/src/primitives/Bytecode/hash.ts +9 -0
- package/src/primitives/Bytecode/index.ts +103 -13
- package/src/primitives/Bytecode/isPush.ts +8 -0
- package/src/primitives/Bytecode/isTerminator.ts +8 -0
- package/src/primitives/Bytecode/isValidJumpDest.ts +12 -0
- package/src/primitives/Bytecode/parseInstructions.ts +10 -0
- package/src/primitives/Bytecode/prettyPrint.ts +12 -0
- package/src/primitives/Bytecode/scan.ts +20 -0
- package/src/primitives/Bytecode/size.ts +9 -0
- package/src/primitives/Bytecode/stripMetadata.ts +10 -0
- package/src/primitives/Bytecode/toAbi.ts +10 -0
- package/src/primitives/Bytecode/toHex.ts +10 -0
- package/src/primitives/Bytecode/types.ts +23 -0
- package/src/primitives/Bytecode/validate.ts +9 -0
- package/src/primitives/Ens/Ens.test.ts +71 -0
- package/src/primitives/Ens/convert.ts +13 -0
- package/src/primitives/Ens/from.ts +32 -0
- package/src/primitives/Ens/hash.ts +46 -0
- package/src/primitives/Ens/index.ts +86 -4
- package/src/primitives/Ens/normalize.ts +45 -0
- package/src/primitives/Ens/validation.ts +38 -0
- package/src/primitives/EventLog/accessors.ts +32 -0
- package/src/primitives/EventLog/clone.ts +17 -0
- package/src/primitives/EventLog/create.ts +46 -0
- package/src/primitives/EventLog/filtering.ts +48 -0
- package/src/primitives/EventLog/index.ts +96 -6
- package/src/primitives/EventLog/status.ts +17 -0
- package/src/primitives/EventLog/toRpc.ts +49 -0
- package/src/primitives/Hardfork/HardforkSchema.ts +3 -3
- package/src/primitives/Hardfork/allIds.ts +13 -0
- package/src/primitives/Hardfork/allNames.ts +13 -0
- package/src/primitives/Hardfork/compare.ts +17 -0
- package/src/primitives/Hardfork/comparisons.ts +45 -0
- package/src/primitives/Hardfork/equals.ts +17 -0
- package/src/primitives/Hardfork/features.ts +61 -0
- package/src/primitives/Hardfork/fromString.ts +16 -0
- package/src/primitives/Hardfork/index.ts +128 -18
- package/src/primitives/Hardfork/isValidName.ts +14 -0
- package/src/primitives/Hardfork/minMax.ts +23 -0
- package/src/primitives/Hardfork/range.ts +19 -0
- package/src/primitives/Hardfork/toString.ts +16 -0
- package/src/primitives/Hash/Hash.test.ts +104 -0
- package/src/primitives/Hash/from.ts +47 -0
- package/src/primitives/Hash/fromBytes.ts +46 -0
- package/src/primitives/Hash/fromHex.ts +44 -0
- package/src/primitives/Hash/index.ts +45 -8
- package/src/primitives/Hash/isHash.ts +31 -0
- package/src/primitives/Hash/toHex.ts +29 -0
- package/src/primitives/Hex/Hex.test.ts +266 -155
- package/src/primitives/Hex/assertSize.ts +41 -0
- package/src/primitives/Hex/concat.ts +37 -0
- package/src/primitives/Hex/from.ts +38 -0
- package/src/primitives/Hex/fromBigInt.ts +40 -0
- package/src/primitives/Hex/fromBoolean.ts +29 -0
- package/src/primitives/Hex/fromNumber.ts +41 -0
- package/src/primitives/Hex/fromString.ts +28 -0
- package/src/primitives/Hex/index.ts +68 -37
- package/src/primitives/Hex/pad.ts +40 -0
- package/src/primitives/Hex/padRight.ts +39 -0
- package/src/primitives/Hex/size.ts +29 -0
- package/src/primitives/Hex/slice.ts +42 -0
- package/src/primitives/Hex/toBigInt.ts +27 -0
- package/src/primitives/Hex/toBoolean.ts +38 -0
- package/src/primitives/Hex/toNumber.ts +37 -0
- package/src/primitives/Hex/toStringHex.ts +39 -0
- package/src/primitives/Hex/trim.ts +27 -0
- package/src/primitives/Hex/validate.ts +37 -0
- package/src/primitives/Hex/xor.ts +39 -0
- package/src/primitives/Opcode/OpcodeSchema.ts +1 -1
- package/src/primitives/Opcode/disassemble.ts +15 -0
- package/src/primitives/Opcode/dupPosition.ts +15 -0
- package/src/primitives/Opcode/format.ts +15 -0
- package/src/primitives/Opcode/getters.ts +54 -0
- package/src/primitives/Opcode/index.ts +301 -11
- package/src/primitives/Opcode/info.ts +18 -0
- package/src/primitives/Opcode/jumpDests.ts +15 -0
- package/src/primitives/Opcode/logTopics.ts +15 -0
- package/src/primitives/Opcode/name.ts +15 -0
- package/src/primitives/Opcode/parse.ts +15 -0
- package/src/primitives/Opcode/predicates.ts +72 -0
- package/src/primitives/Opcode/pushBytes.ts +15 -0
- package/src/primitives/Opcode/pushOpcode.ts +15 -0
- package/src/primitives/Opcode/swapPosition.ts +15 -0
- package/src/primitives/Rlp/decodeBatch.ts +46 -0
- package/src/primitives/Rlp/decodeObject.ts +46 -0
- package/src/primitives/Rlp/decodeValue.ts +51 -0
- package/src/primitives/Rlp/encodeBatch.ts +50 -0
- package/src/primitives/Rlp/encodeObject.ts +48 -0
- package/src/primitives/Rlp/encodeVariadic.ts +49 -0
- package/src/primitives/Rlp/equals.ts +22 -0
- package/src/primitives/Rlp/from.ts +44 -0
- package/src/primitives/Rlp/fromJSON.ts +45 -0
- package/src/primitives/Rlp/getEncodedLength.ts +47 -0
- package/src/primitives/Rlp/getLength.ts +44 -0
- package/src/primitives/Rlp/index.ts +67 -14
- package/src/primitives/Rlp/isBytesData.ts +21 -0
- package/src/primitives/Rlp/isCanonical.ts +32 -0
- package/src/primitives/Rlp/isData.ts +21 -0
- package/src/primitives/Rlp/isList.ts +46 -0
- package/src/primitives/Rlp/isListData.ts +21 -0
- package/src/primitives/Rlp/isString.ts +46 -0
- package/src/primitives/Rlp/toJSON.ts +20 -0
- package/src/primitives/Rlp/toRaw.ts +31 -0
- package/src/primitives/Signature/Signature.test.ts +217 -0
- package/src/primitives/Signature/from.ts +38 -0
- package/src/primitives/Signature/fromBytes.ts +31 -0
- package/src/primitives/Signature/fromCompact.ts +33 -0
- package/src/primitives/Signature/fromDER.ts +35 -0
- package/src/primitives/Signature/fromEd25519.ts +24 -0
- package/src/primitives/Signature/fromHex.ts +29 -0
- package/src/primitives/Signature/fromP256.ts +25 -0
- package/src/primitives/Signature/fromRpc.ts +38 -0
- package/src/primitives/Signature/fromSecp256k1.ts +29 -0
- package/src/primitives/Signature/fromTuple.ts +33 -0
- package/src/primitives/Signature/getR.ts +24 -0
- package/src/primitives/Signature/getS.ts +24 -0
- package/src/primitives/Signature/getV.ts +24 -0
- package/src/primitives/Signature/index.ts +61 -11
- package/src/primitives/Signature/toDER.ts +24 -0
- package/src/primitives/Signature/toHex.ts +24 -0
- package/src/primitives/Signature/toRpc.ts +35 -0
- package/src/primitives/Signature/toTuple.ts +29 -0
- package/src/primitives/Signature/verify.ts +31 -0
- package/src/primitives/Siwe/create.ts +56 -0
- package/src/primitives/Siwe/hash.ts +27 -0
- package/src/primitives/Siwe/index.ts +57 -21
- package/src/primitives/Siwe/parse.ts +24 -0
- package/src/primitives/Siwe/verify.ts +47 -0
- package/src/primitives/Transaction/index.ts +467 -2
- package/src/primitives/Uint/Uint.test.ts +200 -0
- package/src/primitives/Uint/dividedBy.ts +34 -0
- package/src/primitives/Uint/from.ts +35 -0
- package/src/primitives/Uint/fromAbiEncoded.ts +29 -0
- package/src/primitives/Uint/fromBigInt.ts +30 -0
- package/src/primitives/Uint/fromBytes.ts +32 -0
- package/src/primitives/Uint/fromHex.ts +32 -0
- package/src/primitives/Uint/fromNumber.ts +30 -0
- package/src/primitives/Uint/index.ts +90 -45
- package/src/primitives/Uint/isUint256.ts +25 -0
- package/src/primitives/Uint/isValid.ts +25 -0
- package/src/primitives/Uint/modulo.ts +34 -0
- package/src/primitives/Uint/toHex.ts +31 -0
- package/src/primitives/Uint/tryFrom.ts +30 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module splitData
|
|
3
|
+
* @description Split large data into multiple blobs
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BrandedBlob as BlobNamespace } from "@tevm/voltaire";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import type { InvalidBlobDataSizeError } from "@tevm/voltaire/Blob";
|
|
9
|
+
|
|
10
|
+
type BrandedBlob = BlobNamespace.BrandedBlob;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Split large data into multiple blobs.
|
|
14
|
+
*
|
|
15
|
+
* Each blob holds up to 126972 bytes of data (max 6 blobs per transaction).
|
|
16
|
+
*
|
|
17
|
+
* @param data - Data to split
|
|
18
|
+
* @returns Effect yielding array of blobs or failing with InvalidBlobDataSizeError
|
|
19
|
+
* @throws {InvalidBlobDataSizeError} If data requires more than 6 blobs
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import * as Blob from 'voltaire-effect/primitives/Blob'
|
|
23
|
+
* import * as Effect from 'effect/Effect'
|
|
24
|
+
*
|
|
25
|
+
* const largeData = new Uint8Array(300000)
|
|
26
|
+
* const blobs = await Effect.runPromise(Blob.splitData(largeData)) // [blob1, blob2, blob3]
|
|
27
|
+
* ```
|
|
28
|
+
* @since 0.1.0
|
|
29
|
+
*/
|
|
30
|
+
export const splitData = (
|
|
31
|
+
data: Uint8Array,
|
|
32
|
+
): Effect.Effect<BrandedBlob[], InvalidBlobDataSizeError> =>
|
|
33
|
+
Effect.try({
|
|
34
|
+
try: () => BlobNamespace.splitData(data),
|
|
35
|
+
catch: (e) => e as InvalidBlobDataSizeError,
|
|
36
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module toCommitment
|
|
3
|
+
* @description Compute KZG commitment for blob using KZGService
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import type { BrandedBlob as BlobNamespace } from "@tevm/voltaire";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import {
|
|
9
|
+
type KZGError,
|
|
10
|
+
KZGService,
|
|
11
|
+
} from "../../crypto/KZG/KZGService.js";
|
|
12
|
+
|
|
13
|
+
type BrandedBlob = BlobNamespace.BrandedBlob;
|
|
14
|
+
type Commitment = BlobNamespace.Commitment;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Compute KZG commitment for blob.
|
|
18
|
+
*
|
|
19
|
+
* Requires KZGService to be provided in the Effect context.
|
|
20
|
+
*
|
|
21
|
+
* @param blob - 128KB blob data
|
|
22
|
+
* @returns Effect yielding 48-byte commitment, requiring KZGService
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import * as Blob from 'voltaire-effect/primitives/Blob'
|
|
26
|
+
* import { KZGLive } from 'voltaire-effect/crypto/KZG'
|
|
27
|
+
* import * as Effect from 'effect/Effect'
|
|
28
|
+
*
|
|
29
|
+
* const program = Blob.toCommitment(blob).pipe(Effect.provide(KZGLive))
|
|
30
|
+
* const commitment = await Effect.runPromise(program)
|
|
31
|
+
* ```
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export const toCommitment = (
|
|
35
|
+
blob: BrandedBlob,
|
|
36
|
+
): Effect.Effect<Commitment, KZGError, KZGService> =>
|
|
37
|
+
Effect.gen(function* () {
|
|
38
|
+
const kzg = yield* KZGService;
|
|
39
|
+
const commitment = yield* kzg.blobToKzgCommitment(
|
|
40
|
+
blob as unknown as import("@tevm/voltaire").KzgBlobType,
|
|
41
|
+
);
|
|
42
|
+
return commitment as unknown as Commitment;
|
|
43
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module toProof
|
|
3
|
+
* @description Generate KZG proof for blob using KZGService
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import type { BrandedBlob as BlobNamespace } from "@tevm/voltaire";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import {
|
|
9
|
+
type KZGError,
|
|
10
|
+
KZGService,
|
|
11
|
+
} from "../../crypto/KZG/KZGService.js";
|
|
12
|
+
|
|
13
|
+
type BrandedBlob = BlobNamespace.BrandedBlob;
|
|
14
|
+
type Commitment = BlobNamespace.Commitment;
|
|
15
|
+
type Proof = BlobNamespace.Proof;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Generate KZG proof for blob and commitment.
|
|
19
|
+
*
|
|
20
|
+
* Requires KZGService to be provided in the Effect context.
|
|
21
|
+
*
|
|
22
|
+
* @param blob - 128KB blob data
|
|
23
|
+
* @param commitment - 48-byte KZG commitment
|
|
24
|
+
* @returns Effect yielding 48-byte proof, requiring KZGService
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import * as Blob from 'voltaire-effect/primitives/Blob'
|
|
28
|
+
* import { KZGLive } from 'voltaire-effect/crypto/KZG'
|
|
29
|
+
* import * as Effect from 'effect/Effect'
|
|
30
|
+
*
|
|
31
|
+
* const program = Effect.gen(function* () {
|
|
32
|
+
* const commitment = yield* Blob.toCommitment(blob)
|
|
33
|
+
* const proof = yield* Blob.toProof(blob, commitment)
|
|
34
|
+
* return proof
|
|
35
|
+
* }).pipe(Effect.provide(KZGLive))
|
|
36
|
+
* ```
|
|
37
|
+
* @since 0.1.0
|
|
38
|
+
*/
|
|
39
|
+
export const toProof = (
|
|
40
|
+
blob: BrandedBlob,
|
|
41
|
+
commitment: Commitment,
|
|
42
|
+
): Effect.Effect<Proof, KZGError, KZGService> =>
|
|
43
|
+
Effect.gen(function* () {
|
|
44
|
+
const kzg = yield* KZGService;
|
|
45
|
+
const proof = yield* kzg.computeBlobKzgProof(
|
|
46
|
+
blob as unknown as import("@tevm/voltaire").KzgBlobType,
|
|
47
|
+
commitment as unknown as import("@tevm/voltaire").KzgCommitmentType,
|
|
48
|
+
);
|
|
49
|
+
return proof as unknown as Proof;
|
|
50
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module toVersionedHash
|
|
3
|
+
* @description Create versioned hash from commitment
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BrandedBlob as BlobNamespace } from "@tevm/voltaire";
|
|
7
|
+
import type { InvalidCommitmentSizeError } from "@tevm/voltaire/Blob";
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
|
|
10
|
+
type Commitment = BlobNamespace.Commitment;
|
|
11
|
+
type VersionedHash = BlobNamespace.VersionedHash;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create versioned hash from commitment.
|
|
15
|
+
*
|
|
16
|
+
* Formula: BLOB_COMMITMENT_VERSION_KZG (0x01) || sha256(commitment)[1:]
|
|
17
|
+
*
|
|
18
|
+
* @param commitment - 48-byte KZG commitment
|
|
19
|
+
* @returns Effect yielding 32-byte versioned hash or failing with InvalidCommitmentSizeError
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import * as Blob from 'voltaire-effect/primitives/Blob'
|
|
23
|
+
* import * as Effect from 'effect/Effect'
|
|
24
|
+
*
|
|
25
|
+
* const hash = await Effect.runPromise(Blob.toVersionedHash(commitment))
|
|
26
|
+
* ```
|
|
27
|
+
* @since 0.1.0
|
|
28
|
+
*/
|
|
29
|
+
export const toVersionedHash = (
|
|
30
|
+
commitment: Commitment,
|
|
31
|
+
): Effect.Effect<VersionedHash, InvalidCommitmentSizeError> =>
|
|
32
|
+
Effect.try({
|
|
33
|
+
try: () => BlobNamespace.toVersionedHash(commitment),
|
|
34
|
+
catch: (e) => e as InvalidCommitmentSizeError,
|
|
35
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module verify
|
|
3
|
+
* @description Verify KZG proof for blob using KZGService
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import type { BrandedBlob as BlobNamespace } from "@tevm/voltaire";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import {
|
|
9
|
+
type KZGError,
|
|
10
|
+
KZGService,
|
|
11
|
+
} from "../../crypto/KZG/KZGService.js";
|
|
12
|
+
|
|
13
|
+
type BrandedBlob = BlobNamespace.BrandedBlob;
|
|
14
|
+
type Commitment = BlobNamespace.Commitment;
|
|
15
|
+
type Proof = BlobNamespace.Proof;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Verify KZG proof for blob and commitment.
|
|
19
|
+
*
|
|
20
|
+
* Requires KZGService to be provided in the Effect context.
|
|
21
|
+
*
|
|
22
|
+
* @param blob - 128KB blob data
|
|
23
|
+
* @param commitment - 48-byte KZG commitment
|
|
24
|
+
* @param proof - 48-byte KZG proof
|
|
25
|
+
* @returns Effect yielding boolean (true if valid), requiring KZGService
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import * as Blob from 'voltaire-effect/primitives/Blob'
|
|
29
|
+
* import { KZGLive } from 'voltaire-effect/crypto/KZG'
|
|
30
|
+
* import * as Effect from 'effect/Effect'
|
|
31
|
+
*
|
|
32
|
+
* const program = Blob.verify(blob, commitment, proof).pipe(Effect.provide(KZGLive))
|
|
33
|
+
* const isValid = await Effect.runPromise(program)
|
|
34
|
+
* ```
|
|
35
|
+
* @since 0.1.0
|
|
36
|
+
*/
|
|
37
|
+
export const verify = (
|
|
38
|
+
blob: BrandedBlob,
|
|
39
|
+
commitment: Commitment,
|
|
40
|
+
proof: Proof,
|
|
41
|
+
): Effect.Effect<boolean, KZGError, KZGService> =>
|
|
42
|
+
Effect.gen(function* () {
|
|
43
|
+
const kzg = yield* KZGService;
|
|
44
|
+
return yield* kzg.verifyBlobKzgProof(
|
|
45
|
+
blob as unknown as import("@tevm/voltaire").KzgBlobType,
|
|
46
|
+
commitment as unknown as import("@tevm/voltaire").KzgCommitmentType,
|
|
47
|
+
proof as unknown as import("@tevm/voltaire").KzgProofType,
|
|
48
|
+
);
|
|
49
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module verifyBatch
|
|
3
|
+
* @description Verify batch of KZG proofs for blobs
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import type { BrandedBlob as BlobNamespace } from "@tevm/voltaire";
|
|
7
|
+
import {
|
|
8
|
+
BlobArrayLengthMismatchError,
|
|
9
|
+
BlobNotImplementedError,
|
|
10
|
+
InvalidBlobCountError,
|
|
11
|
+
InvalidBlobSizeError,
|
|
12
|
+
InvalidCommitmentSizeError,
|
|
13
|
+
InvalidProofSizeError,
|
|
14
|
+
MAX_PER_TRANSACTION,
|
|
15
|
+
SIZE,
|
|
16
|
+
} from "@tevm/voltaire/Blob";
|
|
17
|
+
import { Effect } from "effect";
|
|
18
|
+
|
|
19
|
+
type BrandedBlob = BlobNamespace.BrandedBlob;
|
|
20
|
+
type Commitment = BlobNamespace.Commitment;
|
|
21
|
+
type Proof = BlobNamespace.Proof;
|
|
22
|
+
|
|
23
|
+
type VerifyBatchError =
|
|
24
|
+
| BlobArrayLengthMismatchError
|
|
25
|
+
| InvalidBlobCountError
|
|
26
|
+
| InvalidBlobSizeError
|
|
27
|
+
| InvalidCommitmentSizeError
|
|
28
|
+
| InvalidProofSizeError
|
|
29
|
+
| BlobNotImplementedError;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Verify batch of KZG proofs for blobs.
|
|
33
|
+
*
|
|
34
|
+
* Note: Batch verification is not yet implemented. This function validates
|
|
35
|
+
* inputs and throws BlobNotImplementedError.
|
|
36
|
+
*
|
|
37
|
+
* @param blobs - Array of 128KB blobs
|
|
38
|
+
* @param commitments - Array of 48-byte commitments
|
|
39
|
+
* @param proofs - Array of 48-byte proofs
|
|
40
|
+
* @returns Effect failing with BlobNotImplementedError (not yet implemented)
|
|
41
|
+
* @throws {BlobArrayLengthMismatchError} If array lengths don't match
|
|
42
|
+
* @throws {InvalidBlobCountError} If too many blobs
|
|
43
|
+
* @throws {InvalidBlobSizeError} If blob size is invalid
|
|
44
|
+
* @throws {InvalidCommitmentSizeError} If commitment size is invalid
|
|
45
|
+
* @throws {InvalidProofSizeError} If proof size is invalid
|
|
46
|
+
* @throws {BlobNotImplementedError} Always (not yet implemented)
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import * as Blob from 'voltaire-effect/primitives/Blob'
|
|
50
|
+
* import * as Effect from 'effect/Effect'
|
|
51
|
+
*
|
|
52
|
+
* const program = Blob.verifyBatch(blobs, commitments, proofs)
|
|
53
|
+
* // Will fail with BlobNotImplementedError
|
|
54
|
+
* ```
|
|
55
|
+
* @since 0.1.0
|
|
56
|
+
*/
|
|
57
|
+
export const verifyBatch = (
|
|
58
|
+
blobs: readonly BrandedBlob[],
|
|
59
|
+
commitments: readonly Commitment[],
|
|
60
|
+
proofs: readonly Proof[],
|
|
61
|
+
): Effect.Effect<boolean, VerifyBatchError> =>
|
|
62
|
+
Effect.try({
|
|
63
|
+
try: (): boolean => {
|
|
64
|
+
if (
|
|
65
|
+
blobs.length !== commitments.length ||
|
|
66
|
+
blobs.length !== proofs.length
|
|
67
|
+
) {
|
|
68
|
+
throw new BlobArrayLengthMismatchError("Arrays must have same length", {
|
|
69
|
+
value: {
|
|
70
|
+
blobs: blobs.length,
|
|
71
|
+
commitments: commitments.length,
|
|
72
|
+
proofs: proofs.length,
|
|
73
|
+
},
|
|
74
|
+
expected: "equal array lengths",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (blobs.length > MAX_PER_TRANSACTION) {
|
|
78
|
+
throw new InvalidBlobCountError("Too many blobs", {
|
|
79
|
+
value: blobs.length,
|
|
80
|
+
expected: `max ${MAX_PER_TRANSACTION} blobs`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
for (let i = 0; i < blobs.length; i++) {
|
|
84
|
+
const blob = blobs[i] as Uint8Array;
|
|
85
|
+
if (blob.length !== SIZE) {
|
|
86
|
+
throw new InvalidBlobSizeError("Invalid blob size", {
|
|
87
|
+
value: blob.length,
|
|
88
|
+
expected: `${SIZE} bytes`,
|
|
89
|
+
context: { index: i },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (let i = 0; i < commitments.length; i++) {
|
|
94
|
+
const commitment = commitments[i] as unknown as Uint8Array;
|
|
95
|
+
if (commitment.length !== 48) {
|
|
96
|
+
throw new InvalidCommitmentSizeError("Invalid commitment size", {
|
|
97
|
+
value: commitment.length,
|
|
98
|
+
expected: "48 bytes",
|
|
99
|
+
context: { index: i },
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (let i = 0; i < proofs.length; i++) {
|
|
104
|
+
const proof = proofs[i] as unknown as Uint8Array;
|
|
105
|
+
if (proof.length !== 48) {
|
|
106
|
+
throw new InvalidProofSizeError("Invalid proof size", {
|
|
107
|
+
value: proof.length,
|
|
108
|
+
expected: "48 bytes",
|
|
109
|
+
context: { index: i },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
throw new BlobNotImplementedError("Not implemented", {
|
|
114
|
+
value: "verifyBatch",
|
|
115
|
+
expected: "implementation",
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
catch: (e) => e as VerifyBatchError,
|
|
119
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { describe, expect, it } from "@effect/vitest";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as BloomFilter from "./index.js";
|
|
4
|
+
|
|
5
|
+
describe("BloomFilter.create", () => {
|
|
6
|
+
it("creates a filter with valid parameters", async () => {
|
|
7
|
+
const program = BloomFilter.create(2048, 3);
|
|
8
|
+
const filter = await Effect.runPromise(program);
|
|
9
|
+
expect(filter).toBeInstanceOf(Uint8Array);
|
|
10
|
+
expect(filter.length).toBe(256); // 2048 bits / 8
|
|
11
|
+
expect(filter.m).toBe(2048);
|
|
12
|
+
expect(filter.k).toBe(3);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("fails on invalid parameters (m <= 0)", async () => {
|
|
16
|
+
const program = BloomFilter.create(0, 3);
|
|
17
|
+
const result = await Effect.runPromiseExit(program);
|
|
18
|
+
expect(result._tag).toBe("Failure");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("fails on invalid parameters (k <= 0)", async () => {
|
|
22
|
+
const program = BloomFilter.create(2048, 0);
|
|
23
|
+
const result = await Effect.runPromiseExit(program);
|
|
24
|
+
expect(result._tag).toBe("Failure");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("BloomFilter.fromHex", () => {
|
|
29
|
+
it("creates filter from valid hex", async () => {
|
|
30
|
+
const hex = "0x" + "00".repeat(256);
|
|
31
|
+
const program = BloomFilter.fromHex(hex, 2048, 3);
|
|
32
|
+
const filter = await Effect.runPromise(program);
|
|
33
|
+
expect(filter.length).toBe(256);
|
|
34
|
+
expect(filter.m).toBe(2048);
|
|
35
|
+
expect(filter.k).toBe(3);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("fails on wrong hex length", async () => {
|
|
39
|
+
const hex = "0x" + "00".repeat(128);
|
|
40
|
+
const program = BloomFilter.fromHex(hex, 2048, 3);
|
|
41
|
+
const result = await Effect.runPromiseExit(program);
|
|
42
|
+
expect(result._tag).toBe("Failure");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("BloomFilter pure functions", () => {
|
|
47
|
+
it("add and contains", async () => {
|
|
48
|
+
const filter = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
49
|
+
const item = new Uint8Array([1, 2, 3, 4, 5]);
|
|
50
|
+
|
|
51
|
+
expect(BloomFilter.contains(filter, item)).toBe(false);
|
|
52
|
+
BloomFilter.add(filter, item);
|
|
53
|
+
expect(BloomFilter.contains(filter, item)).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("isEmpty", async () => {
|
|
57
|
+
const filter = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
58
|
+
expect(BloomFilter.isEmpty(filter)).toBe(true);
|
|
59
|
+
|
|
60
|
+
BloomFilter.add(filter, new Uint8Array([1, 2, 3]));
|
|
61
|
+
expect(BloomFilter.isEmpty(filter)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("density", async () => {
|
|
65
|
+
const filter = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
66
|
+
expect(BloomFilter.density(filter)).toBe(0);
|
|
67
|
+
|
|
68
|
+
BloomFilter.add(filter, new Uint8Array([1, 2, 3]));
|
|
69
|
+
expect(BloomFilter.density(filter)).toBeGreaterThan(0);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("toHex", async () => {
|
|
73
|
+
const filter = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
74
|
+
const hex = BloomFilter.toHex(filter);
|
|
75
|
+
expect(hex).toMatch(/^0x[0-9a-f]+$/i);
|
|
76
|
+
expect(hex.length).toBe(514); // 0x + 512 hex chars
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("merge", async () => {
|
|
80
|
+
const filter1 = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
81
|
+
const filter2 = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
82
|
+
|
|
83
|
+
BloomFilter.add(filter1, new Uint8Array([1, 2, 3]));
|
|
84
|
+
BloomFilter.add(filter2, new Uint8Array([4, 5, 6]));
|
|
85
|
+
|
|
86
|
+
const merged = BloomFilter.merge(filter1, filter2);
|
|
87
|
+
expect(BloomFilter.contains(merged, new Uint8Array([1, 2, 3]))).toBe(true);
|
|
88
|
+
expect(BloomFilter.contains(merged, new Uint8Array([4, 5, 6]))).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("combine", async () => {
|
|
92
|
+
const filter1 = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
93
|
+
const filter2 = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
94
|
+
const filter3 = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
95
|
+
|
|
96
|
+
BloomFilter.add(filter1, new Uint8Array([1]));
|
|
97
|
+
BloomFilter.add(filter2, new Uint8Array([2]));
|
|
98
|
+
BloomFilter.add(filter3, new Uint8Array([3]));
|
|
99
|
+
|
|
100
|
+
const combined = BloomFilter.combine(filter1, filter2, filter3);
|
|
101
|
+
expect(BloomFilter.contains(combined, new Uint8Array([1]))).toBe(true);
|
|
102
|
+
expect(BloomFilter.contains(combined, new Uint8Array([2]))).toBe(true);
|
|
103
|
+
expect(BloomFilter.contains(combined, new Uint8Array([3]))).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("hash", () => {
|
|
107
|
+
const item = new Uint8Array([1, 2, 3, 4, 5]);
|
|
108
|
+
const h = BloomFilter.hash(item, 0, 2048);
|
|
109
|
+
expect(h).toBeGreaterThanOrEqual(0);
|
|
110
|
+
expect(h).toBeLessThan(2048);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("hashFromKeccak", () => {
|
|
114
|
+
const keccakHash = new Uint8Array(32).fill(0xff);
|
|
115
|
+
const h = BloomFilter.hashFromKeccak(keccakHash, 0, 2048);
|
|
116
|
+
expect(h).toBeGreaterThanOrEqual(0);
|
|
117
|
+
expect(h).toBeLessThan(2048);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("expectedFalsePositiveRate", async () => {
|
|
121
|
+
const filter = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
122
|
+
const rate = BloomFilter.expectedFalsePositiveRate(filter, 100);
|
|
123
|
+
expect(rate).toBeGreaterThanOrEqual(0);
|
|
124
|
+
expect(rate).toBeLessThanOrEqual(1);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("BloomFilter round-trip", () => {
|
|
129
|
+
it("fromHex(toHex(filter)) preserves data", async () => {
|
|
130
|
+
const filter = await Effect.runPromise(BloomFilter.create(2048, 3));
|
|
131
|
+
BloomFilter.add(filter, new Uint8Array([1, 2, 3]));
|
|
132
|
+
|
|
133
|
+
const hex = BloomFilter.toHex(filter);
|
|
134
|
+
const restored = await Effect.runPromise(BloomFilter.fromHex(hex, 2048, 3));
|
|
135
|
+
|
|
136
|
+
expect(BloomFilter.contains(restored, new Uint8Array([1, 2, 3]))).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module add
|
|
3
|
+
* @description Add item to BloomFilter (pure, in-place mutation)
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BloomFilter, type BloomFilterType } from "@tevm/voltaire/BloomFilter";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Add an item to a BloomFilter (mutates in place)
|
|
10
|
+
*
|
|
11
|
+
* @param filter - The bloom filter
|
|
12
|
+
* @param item - Item to add (Uint8Array)
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
16
|
+
* import * as Effect from 'effect/Effect'
|
|
17
|
+
*
|
|
18
|
+
* const filter = await Effect.runPromise(BloomFilter.create(2048, 3))
|
|
19
|
+
* BloomFilter.add(filter, new Uint8Array([1, 2, 3]))
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const add = (filter: BloomFilterType, item: Uint8Array): void =>
|
|
23
|
+
BloomFilter.add(filter, item);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module combine
|
|
3
|
+
* @description Combine multiple BloomFilters into one (pure)
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BloomFilter, type BloomFilterType } from "@tevm/voltaire/BloomFilter";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Combine multiple BloomFilters into a single filter
|
|
10
|
+
*
|
|
11
|
+
* @param filters - Filters to combine
|
|
12
|
+
* @returns Combined bloom filter
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
16
|
+
*
|
|
17
|
+
* const combined = BloomFilter.combine(filter1, filter2, filter3)
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const combine = (...filters: BloomFilterType[]): BloomFilterType =>
|
|
21
|
+
BloomFilter.combine(...filters);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module contains
|
|
3
|
+
* @description Check if BloomFilter may contain an item (pure predicate)
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BloomFilter, type BloomFilterType } from "@tevm/voltaire/BloomFilter";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if a BloomFilter might contain an item
|
|
10
|
+
*
|
|
11
|
+
* False positives are possible, false negatives are not.
|
|
12
|
+
*
|
|
13
|
+
* @param filter - The bloom filter
|
|
14
|
+
* @param item - Item to check
|
|
15
|
+
* @returns true if item might be in filter, false if definitely not
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
19
|
+
*
|
|
20
|
+
* if (BloomFilter.contains(filter, item)) {
|
|
21
|
+
* console.log('Item might be in filter')
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const contains = (filter: BloomFilterType, item: Uint8Array): boolean =>
|
|
26
|
+
BloomFilter.contains(filter, item);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module create
|
|
3
|
+
* @description Create BloomFilter with Effect error handling
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { Effect } from "effect";
|
|
7
|
+
import {
|
|
8
|
+
BloomFilter,
|
|
9
|
+
type BloomFilterType,
|
|
10
|
+
InvalidBloomFilterParameterError,
|
|
11
|
+
} from "@tevm/voltaire/BloomFilter";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a new BloomFilter with specified parameters
|
|
15
|
+
*
|
|
16
|
+
* @param m - Number of bits in the filter
|
|
17
|
+
* @param k - Number of hash functions
|
|
18
|
+
* @returns Effect yielding BloomFilterType or failing with InvalidBloomFilterParameterError
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
22
|
+
* import * as Effect from 'effect/Effect'
|
|
23
|
+
*
|
|
24
|
+
* const program = BloomFilter.create(2048, 3)
|
|
25
|
+
* const filter = await Effect.runPromise(program)
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const create = (
|
|
29
|
+
m: number,
|
|
30
|
+
k: number,
|
|
31
|
+
): Effect.Effect<BloomFilterType, InvalidBloomFilterParameterError> =>
|
|
32
|
+
Effect.try({
|
|
33
|
+
try: () => BloomFilter.create(m, k),
|
|
34
|
+
catch: (e) => e as InvalidBloomFilterParameterError,
|
|
35
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module density
|
|
3
|
+
* @description Calculate BloomFilter bit density (pure)
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BloomFilter, type BloomFilterType } from "@tevm/voltaire/BloomFilter";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calculate the density (fill ratio) of a BloomFilter
|
|
10
|
+
*
|
|
11
|
+
* @param filter - The bloom filter
|
|
12
|
+
* @returns Density as a number between 0 and 1
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
16
|
+
*
|
|
17
|
+
* const d = BloomFilter.density(filter)
|
|
18
|
+
* console.log(d) // e.g. 0.15
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export const density = (filter: BloomFilterType): number =>
|
|
22
|
+
BloomFilter.density(filter);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module expectedFalsePositiveRate
|
|
3
|
+
* @description Calculate expected false positive rate (pure)
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { BloomFilter, type BloomFilterType } from "@tevm/voltaire/BloomFilter";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calculate the expected false positive rate for a given item count
|
|
10
|
+
*
|
|
11
|
+
* @param filter - The bloom filter
|
|
12
|
+
* @param itemCount - Number of items in the filter
|
|
13
|
+
* @returns Expected false positive rate (0 to 1)
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
17
|
+
*
|
|
18
|
+
* const rate = BloomFilter.expectedFalsePositiveRate(filter, 100)
|
|
19
|
+
* console.log(rate) // e.g. 0.001
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const expectedFalsePositiveRate = (
|
|
23
|
+
filter: BloomFilterType,
|
|
24
|
+
itemCount: number,
|
|
25
|
+
): number => BloomFilter.expectedFalsePositiveRate(filter, itemCount);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module fromHex
|
|
3
|
+
* @description Create BloomFilter from hex string with Effect error handling
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { Effect } from "effect";
|
|
7
|
+
import {
|
|
8
|
+
BloomFilter,
|
|
9
|
+
type BloomFilterType,
|
|
10
|
+
InvalidBloomFilterLengthError,
|
|
11
|
+
} from "@tevm/voltaire/BloomFilter";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create BloomFilter from hex string
|
|
15
|
+
*
|
|
16
|
+
* @param hex - Hex string (with or without 0x prefix)
|
|
17
|
+
* @param m - Number of bits
|
|
18
|
+
* @param k - Number of hash functions
|
|
19
|
+
* @returns Effect yielding BloomFilterType or failing with InvalidBloomFilterLengthError
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import * as BloomFilter from 'voltaire-effect/primitives/BloomFilter'
|
|
23
|
+
* import * as Effect from 'effect/Effect'
|
|
24
|
+
*
|
|
25
|
+
* const program = BloomFilter.fromHex('0x00...', 2048, 3)
|
|
26
|
+
* const filter = await Effect.runPromise(program)
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export const fromHex = (
|
|
30
|
+
hex: string,
|
|
31
|
+
m: number,
|
|
32
|
+
k: number,
|
|
33
|
+
): Effect.Effect<BloomFilterType, InvalidBloomFilterLengthError> =>
|
|
34
|
+
Effect.try({
|
|
35
|
+
try: () => BloomFilter.fromHex(hex, m, k),
|
|
36
|
+
catch: (e) => e as InvalidBloomFilterLengthError,
|
|
37
|
+
});
|