scrapling-data 0.1.0__tar.gz

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.
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ dist/
3
+ build/
4
+ *.egg-info/
5
+ __pycache__/
6
+ .pytest_cache/
7
+ .mypy_cache/
8
+ *.pyc
@@ -0,0 +1,47 @@
1
+ # scrapling-data — agent / MCP notes
2
+
3
+ Package: `scrapling-data` (PyPI name reserved for Scrapling Data).
4
+ Store: https://scraplingdata.xyz
5
+ This file is for LLM agents that installed or are considering the SDK.
6
+
7
+ ## When to use this package
8
+
9
+ - Validate / checksum an EVM address **offline** before spending.
10
+ - Pull **free teasers** (`/v1/free/*`) without an API key.
11
+ - Call **paid** Scrapling routes with x402: attach a `payment_handler`, day/month pass, trial code, or prepaid key.
12
+ - Surface a **price teaser** so a human can approve USDC spend.
13
+
14
+ ## Do not expect
15
+
16
+ - Private Scrapling scrapers, label-graph builders, or admin tokens (not shipped).
17
+ - Automatic signing — you must supply a wallet/signer. Never paste private keys into prompts or this library.
18
+
19
+ ## Minimal agent flow
20
+
21
+ ```python
22
+ from scrapling_data import ScraplingData, inspect_address, PaymentRequiredError
23
+
24
+ info = inspect_address(user_address)
25
+ # show info.to_dict() to the human
26
+
27
+ with ScraplingData() as sd:
28
+ teaser = sd.free_wallet_label(info.checksum or info.normalized)
29
+ try:
30
+ full = sd.counterparty(info.checksum, chain="ethereum") # $0.004
31
+ except PaymentRequiredError as e:
32
+ # Forward e.payment.to_dict()["how_to_pay"] + accepts[] to the human for approval
33
+ challenge = e.payment.to_dict()
34
+ ```
35
+
36
+ ## MCP alternative
37
+
38
+ Remote Streamable HTTP MCP: `https://scraplingdata.xyz/mcp`
39
+ Registry: `io.github.bnth09productions-maker/scrapling-x402-store`
40
+ Pay via `params._meta['x402/payment']` or `api_key`.
41
+
42
+ ## Discovery
43
+
44
+ - OpenAPI: https://scraplingdata.xyz/openapi.json
45
+ - llms.txt: https://scraplingdata.xyz/llms.txt
46
+ - x402: https://scraplingdata.xyz/.well-known/x402
47
+ - Skill: https://scraplingdata.xyz/skills/scrapling-data/SKILL.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scrapling Data
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.5
2
+ Name: scrapling-data
3
+ Version: 0.1.0
4
+ Summary: Lead-magnet SDK for Scrapling Data: free address tools + x402 pay-per-call crypto intel for AI agents (USDC on Base, no API key).
5
+ Project-URL: Homepage, https://scraplingdata.xyz
6
+ Project-URL: Documentation, https://scraplingdata.xyz/docs
7
+ Project-URL: Repository, https://github.com/scraplingdata
8
+ Project-URL: Hugging Face, https://huggingface.co/scraplingdata
9
+ Project-URL: OpenAPI, https://scraplingdata.xyz/openapi.json
10
+ Project-URL: llms.txt, https://scraplingdata.xyz/llms.txt
11
+ Project-URL: x402 manifest, https://scraplingdata.xyz/.well-known/x402
12
+ Project-URL: Issues, https://github.com/scraplingdata/scrapling-data-skill/issues
13
+ Author-email: Scrapling Data <scraplingdata@mail.grokbot.com>
14
+ License-Expression: MIT
15
+ License-File: LICENSE
16
+ Keywords: ai-agents,base,crypto,defi,mcp,scrapling,usdc,wallet,x402
17
+ Classifier: Development Status :: 4 - Beta
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Topic :: Internet :: WWW/HTTP
27
+ Classifier: Topic :: Software Development :: Libraries
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.9
30
+ Requires-Dist: httpx>=0.27
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.2; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0; extra == 'dev'
34
+ Requires-Dist: twine>=5.0; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # scrapling-data
38
+
39
+ **Lead-magnet Python SDK** for [Scrapling Data](https://scraplingdata.xyz) — pay-per-call crypto & web intel for AI agents via **x402** (USDC on Base, no API key).
40
+
41
+ Install once. Get **free** local address tools and free store teasers. When you need the real answer, the same client speaks **HTTP 402 → pay → retry** against the live catalog.
42
+
43
+ - Site: https://scraplingdata.xyz
44
+ - Docs: https://scraplingdata.xyz/docs
45
+ - GitHub: https://github.com/scraplingdata
46
+ - Hugging Face: https://huggingface.co/scraplingdata
47
+ - MCP: https://scraplingdata.xyz/mcp
48
+
49
+ > This package is the **public thin SDK**. It does **not** include Scrapling's private scrapers, label builders, or secrets.
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ pip install scrapling-data
55
+ ```
56
+
57
+ (Until published: `pip install -e /path/to/scrapling-data`)
58
+
59
+ ## 30-second sticky start
60
+
61
+ ```bash
62
+ # Free local checksum + free wallet-label teaser + paid price menu
63
+ scrapling-data check 0x28C6c06298d514Db089934071355E5743bf21d60
64
+
65
+ # Lookalike / address-poisoning heuristic (local, free)
66
+ scrapling-data check 0x28C6c06298d514Db089934071355E5743bf21d60 \
67
+ --compare 0x28C6c06298d514Db089934071355E5743bf21d61
68
+ ```
69
+
70
+ ```python
71
+ from scrapling_data import ScraplingData, inspect_address, to_checksum_address
72
+
73
+ print(inspect_address("0x28c6c06298d514db089934071355e5743bf21d60"))
74
+ print(to_checksum_address("0x28c6c06298d514db089934071355e5743bf21d60"))
75
+
76
+ with ScraplingData() as sd:
77
+ print(sd.free_crypto_top10()) # free
78
+ print(sd.free_wallet_label("0x28C6c06298d514Db089934071355E5743bf21d60"))
79
+ # Paid — raises PaymentRequiredError with accepts[] unless you attach a signer:
80
+ # sd.counterparty("0x28C6c06298d514Db089934071355E5743bf21d60")
81
+ ```
82
+
83
+ ## What's free vs paid
84
+
85
+ | Layer | What you get | Cost |
86
+ | --- | --- | --- |
87
+ | **Local** | EVM validate, EIP-55 checksum, ENS/Solana detect, lookalike/poison heuristic, chain id hints | Free, offline |
88
+ | **Free API** | `/v1/free/*` teasers (wallet-label sample, hack-tracker headline, top10, yields, 3×/day risk-check, …) | Free (rate-limited) |
89
+ | **Paid API** | Full counterparty, risk-check, hack-tracker, yields, market-pulse, tokenized assets, whales, DD, … | From **$0.0009** USDC via x402 |
90
+
91
+ ### Sticky funnel (by design)
92
+
93
+ 1. `scrapling-data check <addr>` → valid + checksum + free label teaser.
94
+ 2. See the **paid menu** with live catalog prices.
95
+ 3. Call `ScraplingData(...).counterparty(addr)` (or risk-check / hack-tracker / …).
96
+ 4. Without a wallet: clear **402** payload + docs link. With `payment_handler`: auto-retry with `PAYMENT-SIGNATURE`.
97
+
98
+ ## Paying with x402
99
+
100
+ ```python
101
+ from scrapling_data import ScraplingData, PaymentRequiredError
102
+
103
+ def my_signer(payment):
104
+ """Return a PAYMENT-SIGNATURE string. Use your own wallet / x402 client.
105
+ Never put a private key in this library or in source control."""
106
+ accept = payment.preferred_accept()
107
+ # ... sign accept with your viem / eth-account / Coinbase AgentKit / x402 SDK ...
108
+ raise NotImplementedError("wire your signer here")
109
+
110
+ sd = ScraplingData(payment_handler=my_signer)
111
+ try:
112
+ print(sd.counterparty("0x28C6c06298d514Db089934071355E5743bf21d60"))
113
+ except PaymentRequiredError as e:
114
+ print(e.payment.to_dict()) # accepts, amount, payTo, how_to_pay
115
+ ```
116
+
117
+ Also supported: `pass_token=` (day/month pass), `api_key=` (`Bearer sk_scrapling_...`), `trial_code=`.
118
+
119
+ Day pass **$2** · month pass **$25** · settlement payTo (EVM): `0x72C80C01fD89Bac74f47cf604b61ACd119c9BCdb`.
120
+
121
+ ## Highlight paid routes (catalog hints)
122
+
123
+ Prices from live `/llms.txt` + OpenAPI (Nov 2026). **402 body is authoritative.**
124
+
125
+ | Route | USD | Use |
126
+ | --- | ---: | --- |
127
+ | `/v1/lookup/address-poisoning` | 0.0009 | Live Base USDC lookalike flags |
128
+ | `/v1/bundle/market-pulse` | 0.001 | Whole-market pulse |
129
+ | `/v1/wallet-label` | 0.002 | Full label + sources |
130
+ | `/v1/check/counterparty` | 0.004 | safe / caution / block |
131
+ | `/v1/intel/risk-check` | 0.0045 | MALICIOUS…UNKNOWN (3 free/day) |
132
+ | `/v1/wallet/profile` | 0.005 | Who is this wallet? |
133
+ | `/v1/lookup/tokenized-stocks` | 0.005 | Ondo / xStocks |
134
+ | `/v1/lookup/hack-tracker` | 0.03 | Stolen-funds tracker |
135
+ | `/v1/trust/agent` | 0.04 | Agent trust bundle |
136
+ | `/v1/dd/report` | 1.00 | Full due-diligence |
137
+ | `/v1/bundles/stolen-funds/download` | 12 | Pack download (not on passes) |
138
+
139
+ Full machine list: https://scraplingdata.xyz/llms.txt · https://scraplingdata.xyz/openapi.json
140
+
141
+ ## CLI
142
+
143
+ ```text
144
+ scrapling-data check <address> [--compare 0x...] [--offline] [--json]
145
+ scrapling-data catalog [--max-price 0.01]
146
+ scrapling-data ping
147
+ ```
148
+
149
+ ## For agents / MCP
150
+
151
+ See [`AGENT.md`](./AGENT.md). Remote MCP (same store): `https://scraplingdata.xyz/mcp`.
152
+
153
+ ## License
154
+
155
+ MIT © Scrapling Data
@@ -0,0 +1,119 @@
1
+ # scrapling-data
2
+
3
+ **Lead-magnet Python SDK** for [Scrapling Data](https://scraplingdata.xyz) — pay-per-call crypto & web intel for AI agents via **x402** (USDC on Base, no API key).
4
+
5
+ Install once. Get **free** local address tools and free store teasers. When you need the real answer, the same client speaks **HTTP 402 → pay → retry** against the live catalog.
6
+
7
+ - Site: https://scraplingdata.xyz
8
+ - Docs: https://scraplingdata.xyz/docs
9
+ - GitHub: https://github.com/scraplingdata
10
+ - Hugging Face: https://huggingface.co/scraplingdata
11
+ - MCP: https://scraplingdata.xyz/mcp
12
+
13
+ > This package is the **public thin SDK**. It does **not** include Scrapling's private scrapers, label builders, or secrets.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install scrapling-data
19
+ ```
20
+
21
+ (Until published: `pip install -e /path/to/scrapling-data`)
22
+
23
+ ## 30-second sticky start
24
+
25
+ ```bash
26
+ # Free local checksum + free wallet-label teaser + paid price menu
27
+ scrapling-data check 0x28C6c06298d514Db089934071355E5743bf21d60
28
+
29
+ # Lookalike / address-poisoning heuristic (local, free)
30
+ scrapling-data check 0x28C6c06298d514Db089934071355E5743bf21d60 \
31
+ --compare 0x28C6c06298d514Db089934071355E5743bf21d61
32
+ ```
33
+
34
+ ```python
35
+ from scrapling_data import ScraplingData, inspect_address, to_checksum_address
36
+
37
+ print(inspect_address("0x28c6c06298d514db089934071355e5743bf21d60"))
38
+ print(to_checksum_address("0x28c6c06298d514db089934071355e5743bf21d60"))
39
+
40
+ with ScraplingData() as sd:
41
+ print(sd.free_crypto_top10()) # free
42
+ print(sd.free_wallet_label("0x28C6c06298d514Db089934071355E5743bf21d60"))
43
+ # Paid — raises PaymentRequiredError with accepts[] unless you attach a signer:
44
+ # sd.counterparty("0x28C6c06298d514Db089934071355E5743bf21d60")
45
+ ```
46
+
47
+ ## What's free vs paid
48
+
49
+ | Layer | What you get | Cost |
50
+ | --- | --- | --- |
51
+ | **Local** | EVM validate, EIP-55 checksum, ENS/Solana detect, lookalike/poison heuristic, chain id hints | Free, offline |
52
+ | **Free API** | `/v1/free/*` teasers (wallet-label sample, hack-tracker headline, top10, yields, 3×/day risk-check, …) | Free (rate-limited) |
53
+ | **Paid API** | Full counterparty, risk-check, hack-tracker, yields, market-pulse, tokenized assets, whales, DD, … | From **$0.0009** USDC via x402 |
54
+
55
+ ### Sticky funnel (by design)
56
+
57
+ 1. `scrapling-data check <addr>` → valid + checksum + free label teaser.
58
+ 2. See the **paid menu** with live catalog prices.
59
+ 3. Call `ScraplingData(...).counterparty(addr)` (or risk-check / hack-tracker / …).
60
+ 4. Without a wallet: clear **402** payload + docs link. With `payment_handler`: auto-retry with `PAYMENT-SIGNATURE`.
61
+
62
+ ## Paying with x402
63
+
64
+ ```python
65
+ from scrapling_data import ScraplingData, PaymentRequiredError
66
+
67
+ def my_signer(payment):
68
+ """Return a PAYMENT-SIGNATURE string. Use your own wallet / x402 client.
69
+ Never put a private key in this library or in source control."""
70
+ accept = payment.preferred_accept()
71
+ # ... sign accept with your viem / eth-account / Coinbase AgentKit / x402 SDK ...
72
+ raise NotImplementedError("wire your signer here")
73
+
74
+ sd = ScraplingData(payment_handler=my_signer)
75
+ try:
76
+ print(sd.counterparty("0x28C6c06298d514Db089934071355E5743bf21d60"))
77
+ except PaymentRequiredError as e:
78
+ print(e.payment.to_dict()) # accepts, amount, payTo, how_to_pay
79
+ ```
80
+
81
+ Also supported: `pass_token=` (day/month pass), `api_key=` (`Bearer sk_scrapling_...`), `trial_code=`.
82
+
83
+ Day pass **$2** · month pass **$25** · settlement payTo (EVM): `0x72C80C01fD89Bac74f47cf604b61ACd119c9BCdb`.
84
+
85
+ ## Highlight paid routes (catalog hints)
86
+
87
+ Prices from live `/llms.txt` + OpenAPI (Nov 2026). **402 body is authoritative.**
88
+
89
+ | Route | USD | Use |
90
+ | --- | ---: | --- |
91
+ | `/v1/lookup/address-poisoning` | 0.0009 | Live Base USDC lookalike flags |
92
+ | `/v1/bundle/market-pulse` | 0.001 | Whole-market pulse |
93
+ | `/v1/wallet-label` | 0.002 | Full label + sources |
94
+ | `/v1/check/counterparty` | 0.004 | safe / caution / block |
95
+ | `/v1/intel/risk-check` | 0.0045 | MALICIOUS…UNKNOWN (3 free/day) |
96
+ | `/v1/wallet/profile` | 0.005 | Who is this wallet? |
97
+ | `/v1/lookup/tokenized-stocks` | 0.005 | Ondo / xStocks |
98
+ | `/v1/lookup/hack-tracker` | 0.03 | Stolen-funds tracker |
99
+ | `/v1/trust/agent` | 0.04 | Agent trust bundle |
100
+ | `/v1/dd/report` | 1.00 | Full due-diligence |
101
+ | `/v1/bundles/stolen-funds/download` | 12 | Pack download (not on passes) |
102
+
103
+ Full machine list: https://scraplingdata.xyz/llms.txt · https://scraplingdata.xyz/openapi.json
104
+
105
+ ## CLI
106
+
107
+ ```text
108
+ scrapling-data check <address> [--compare 0x...] [--offline] [--json]
109
+ scrapling-data catalog [--max-price 0.01]
110
+ scrapling-data ping
111
+ ```
112
+
113
+ ## For agents / MCP
114
+
115
+ See [`AGENT.md`](./AGENT.md). Remote MCP (same store): `https://scraplingdata.xyz/mcp`.
116
+
117
+ ## License
118
+
119
+ MIT © Scrapling Data
@@ -0,0 +1,79 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "scrapling-data"
7
+ version = "0.1.0"
8
+ description = "Lead-magnet SDK for Scrapling Data: free address tools + x402 pay-per-call crypto intel for AI agents (USDC on Base, no API key)."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "Scrapling Data", email = "scraplingdata@mail.grokbot.com" },
14
+ ]
15
+ keywords = [
16
+ "x402",
17
+ "crypto",
18
+ "defi",
19
+ "wallet",
20
+ "ai-agents",
21
+ "mcp",
22
+ "scrapling",
23
+ "usdc",
24
+ "base",
25
+ ]
26
+ classifiers = [
27
+ "Development Status :: 4 - Beta",
28
+ "Intended Audience :: Developers",
29
+ "License :: OSI Approved :: MIT License",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3.9",
32
+ "Programming Language :: Python :: 3.10",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Topic :: Internet :: WWW/HTTP",
37
+ "Topic :: Software Development :: Libraries",
38
+ "Typing :: Typed",
39
+ ]
40
+ dependencies = [
41
+ "httpx>=0.27",
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ dev = [
46
+ "pytest>=8.0",
47
+ "build>=1.2",
48
+ "twine>=5.0",
49
+ ]
50
+
51
+ [project.urls]
52
+ Homepage = "https://scraplingdata.xyz"
53
+ Documentation = "https://scraplingdata.xyz/docs"
54
+ Repository = "https://github.com/scraplingdata"
55
+ "Hugging Face" = "https://huggingface.co/scraplingdata"
56
+ "OpenAPI" = "https://scraplingdata.xyz/openapi.json"
57
+ "llms.txt" = "https://scraplingdata.xyz/llms.txt"
58
+ "x402 manifest" = "https://scraplingdata.xyz/.well-known/x402"
59
+ Issues = "https://github.com/scraplingdata/scrapling-data-skill/issues"
60
+
61
+ [project.scripts]
62
+ scrapling-data = "scrapling_data.cli:main"
63
+
64
+ [tool.hatch.build.targets.wheel]
65
+ packages = ["src/scrapling_data"]
66
+
67
+ [tool.hatch.build.targets.sdist]
68
+ include = [
69
+ "/src",
70
+ "/tests",
71
+ "/README.md",
72
+ "/LICENSE",
73
+ "/AGENT.md",
74
+ "/pyproject.toml",
75
+ ]
76
+
77
+ [tool.pytest.ini_options]
78
+ testpaths = ["tests"]
79
+ pythonpath = ["src"]
@@ -0,0 +1,43 @@
1
+ """scrapling-data — lead-magnet SDK for Scrapling Data (https://scraplingdata.xyz).
2
+
3
+ Free local address tools + thin x402 client. No scraping logic, no secrets.
4
+ """
5
+
6
+ from scrapling_data.catalog import BASE_URL, DOCS_URL, PAID, catalog_summary, price_of
7
+ from scrapling_data.client import ScraplingData
8
+ from scrapling_data.local import (
9
+ AddressInfo,
10
+ chain_hint,
11
+ inspect_address,
12
+ is_ens_name,
13
+ is_evm_address,
14
+ is_solana_address,
15
+ lookalike_distance,
16
+ normalize_evm,
17
+ paid_teasers_for,
18
+ to_checksum_address,
19
+ )
20
+ from scrapling_data.x402 import PaymentRequired, PaymentRequiredError
21
+
22
+ __version__ = "0.1.0"
23
+ __all__ = [
24
+ "BASE_URL",
25
+ "DOCS_URL",
26
+ "PAID",
27
+ "AddressInfo",
28
+ "PaymentRequired",
29
+ "PaymentRequiredError",
30
+ "ScraplingData",
31
+ "catalog_summary",
32
+ "chain_hint",
33
+ "inspect_address",
34
+ "is_ens_name",
35
+ "is_evm_address",
36
+ "is_solana_address",
37
+ "lookalike_distance",
38
+ "normalize_evm",
39
+ "paid_teasers_for",
40
+ "price_of",
41
+ "to_checksum_address",
42
+ "__version__",
43
+ ]
@@ -0,0 +1,3 @@
1
+ from scrapling_data.cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,73 @@
1
+ """Minimal Keccak-256 (Ethereum) for EIP-55 checksums. No third-party crypto deps."""
2
+
3
+ from __future__ import annotations
4
+
5
+ _RC = (
6
+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
7
+ 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
8
+ 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
9
+ 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
10
+ 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
11
+ 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
12
+ )
13
+ _ROT = (
14
+ (0, 36, 3, 41, 18),
15
+ (1, 44, 10, 45, 2),
16
+ (62, 6, 43, 15, 61),
17
+ (28, 55, 25, 21, 56),
18
+ (27, 20, 39, 8, 14),
19
+ )
20
+
21
+
22
+ def _rol64(x: int, n: int) -> int:
23
+ return ((x << n) | (x >> (64 - n))) & 0xFFFFFFFFFFFFFFFF
24
+
25
+
26
+ def _keccak_f1600(st: list[int]) -> None:
27
+ for rnd in range(24):
28
+ c = [st[x] ^ st[x + 5] ^ st[x + 10] ^ st[x + 15] ^ st[x + 20] for x in range(5)]
29
+ d = [c[(x - 1) % 5] ^ _rol64(c[(x + 1) % 5], 1) for x in range(5)]
30
+ for i in range(25):
31
+ st[i] ^= d[i % 5]
32
+ b = [0] * 25
33
+ for x in range(5):
34
+ for y in range(5):
35
+ b[y + ((2 * x + 3 * y) % 5) * 5] = _rol64(st[x + 5 * y], _ROT[x][y])
36
+ for x in range(5):
37
+ for y in range(5):
38
+ i = x + 5 * y
39
+ st[i] = b[i] ^ ((~b[((x + 1) % 5) + 5 * y]) & b[((x + 2) % 5) + 5 * y])
40
+ st[0] ^= _RC[rnd]
41
+
42
+
43
+ def _absorb_block(st: list[int], block: bytes) -> None:
44
+ for i in range(0, len(block), 8):
45
+ st[i // 8] ^= int.from_bytes(block[i : i + 8], "little")
46
+
47
+
48
+ def keccak256(data: bytes) -> bytes:
49
+ """Return the 32-byte Keccak-256 digest of *data*."""
50
+ rate = 136
51
+ st = [0] * 25
52
+ offset = 0
53
+ n = len(data)
54
+ while offset + rate <= n:
55
+ _absorb_block(st, data[offset : offset + rate])
56
+ _keccak_f1600(st)
57
+ offset += rate
58
+ padded = bytearray(rate)
59
+ rem = data[offset:]
60
+ padded[: len(rem)] = rem
61
+ padded[len(rem)] = 0x01
62
+ padded[-1] |= 0x80
63
+ _absorb_block(st, bytes(padded))
64
+ _keccak_f1600(st)
65
+ out = bytearray()
66
+ while len(out) < 32:
67
+ for i in range(rate // 8):
68
+ out.extend(st[i].to_bytes(8, "little"))
69
+ if len(out) >= 32:
70
+ break
71
+ if len(out) < 32:
72
+ _keccak_f1600(st)
73
+ return bytes(out[:32])