Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 20 additions & 49 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,38 @@ readme = "README.md"
authors = [
{ name = "Ethereum Foundation", email = "[email protected]" },
]
keywords = ["lean", "beam", "ethereum", "specifications", "protocol", "consensus"]
keywords = [
"lean",
"beam",
"ethereum",
"specifications",
"protocol",
"consensus",
]
classifiers = [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
requires-python = ">=3.12"
dependencies = [
"pydantic>=2.9.2,<3",
"typing-extensions>=4.4",
]
dependencies = ["pydantic>=2.9.2,<3", "typing-extensions>=4.4"]

[project.license]
file = "LICENSE"

[project.optional-dependencies]
test = [
"pytest>=8.3.3,<9",
"pytest-cov>=6.0.0,<7",
"pytest-xdist>=3.6.1,<4",
]
lint = [
"ruff>=0.11.8,<1",
]
typecheck = [
"mypy>=1.15.0,<1.16",
]
test = ["pytest>=8.3.3,<9", "pytest-cov>=6.0.0,<7", "pytest-xdist>=3.6.1,<4"]
lint = ["ruff>=0.11.8,<1"]
typecheck = ["mypy>=1.15.0,<1.16"]
docs = [
"mkdocs>=1.6.1,<2",
"mkdocs-material>=9.5.45,<10",
"mkdocstrings[python]>=0.27.0,<1",
"codespell>=2.4.1,<3",
"pyspelling>=2.8.2,<3",
]
dev = [
"lean-spec[test,lint,typecheck,docs]",
"tox>=4.23.0,<5",
]
dev = ["lean-spec[test,lint,typecheck,docs]", "tox>=4.23.0,<5"]

[project.urls]
Homepage = "https://github.com/leanEthereum/lean-spec"
Expand All @@ -59,35 +52,21 @@ Issues = "https://github.com/leanEthereum/lean-spec/issues"
allow-direct-references = true

[tool.hatch.build]
exclude = [
".*",
"tests/",
"docs/",
]
exclude = [".*", "tests/", "docs/"]

[tool.hatch.build.targets.wheel]
packages = [
"src/lean_spec",
]
packages = ["src/lean_spec"]

[tool.ruff]
line-length = 79
line-length = 100

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint]
select = ["E", "F", "B", "W", "I", "A", "N", "D", "C"]
fixable = ["I", "B", "E", "F", "W", "D", "C"]
ignore = [
"D205",
"D203",
"D212",
"D415",
"C901",
"A005",
"C420"
]
ignore = ["D205", "D203", "D212", "D415", "C901", "A005", "C420"]

[tool.ruff.lint.pydocstyle]
convention = "google"
Expand All @@ -97,11 +76,7 @@ force-single-line = false
known-first-party = ["lean_spec"]

[tool.ruff.lint.per-file-ignores]
"tests/**" = [
"D",
"F401",
"F403",
]
"tests/**" = ["D", "F401", "F403"]

[tool.mypy]
python_version = "3.12"
Expand All @@ -126,14 +101,10 @@ addopts = [
"--cov-report=html",
"--cov-branch",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
]
markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"]

[tool.coverage.run]
source = [
"src",
]
source = ["src"]
branch = true

[tool.uv]
Expand Down
5 changes: 1 addition & 4 deletions src/lean_spec/subspecs/containers/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ class State(StrictBaseModel):
justifications_validators: Annotated[
list[bool],
Field(
max_length=(
DEVNET_CONFIG.historical_roots_limit
* DEVNET_CONFIG.historical_roots_limit
)
max_length=(DEVNET_CONFIG.historical_roots_limit * DEVNET_CONFIG.historical_roots_limit)
),
]
"""A bitlist of validators who participated in justifications."""
Expand Down
4 changes: 1 addition & 3 deletions src/lean_spec/subspecs/koalabear/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,7 @@ class Fp(BaseModel):

model_config = ConfigDict(frozen=True)

value: int = Field(
ge=0, lt=P, description="Field element value in the range [0, P)"
)
value: int = Field(ge=0, lt=P, description="Field element value in the range [0, P)")

@field_validator("value", mode="before")
@classmethod
Expand Down
4 changes: 1 addition & 3 deletions src/lean_spec/subspecs/networking/gossipsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ class GossipsubParameters(StrictBaseModel):
"""The number of history windows to gossip about."""

seen_ttl_secs: int = (
DEVNET_CONFIG.second_per_slot
* DEVNET_CONFIG.justification_lookback_slots
* 2
DEVNET_CONFIG.second_per_slot * DEVNET_CONFIG.justification_lookback_slots * 2
)
"""
The expiry time in seconds for the cache of seen message IDs.
Expand Down
43 changes: 10 additions & 33 deletions src/lean_spec/subspecs/poseidon2/permutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,10 @@ class Poseidon2Params(BaseModel):

width: int = Field(gt=0, description="The size of the state (t).")
rounds_f: int = Field(gt=0, description="Total number of 'full' rounds.")
rounds_p: int = Field(
ge=0, description="Total number of 'partial' rounds."
)
rounds_p: int = Field(ge=0, description="Total number of 'partial' rounds.")
internal_diag_vectors: List[Fp] = Field(
min_length=1,
description=(
"Diagonal vectors for the efficient "
"internal linear layer matrix (M_I)."
),
description=("Diagonal vectors for the efficient internal linear layer matrix (M_I)."),
)
round_constants: List[Fp] = Field(
min_length=1,
Expand All @@ -56,9 +51,7 @@ class Poseidon2Params(BaseModel):
def check_lengths(self) -> "Poseidon2Params":
"""Ensures vector lengths match the configuration."""
if len(self.internal_diag_vectors) != self.width:
raise ValueError(
"Length of internal_diag_vectors must equal width."
)
raise ValueError("Length of internal_diag_vectors must equal width.")

expected_constants = (self.rounds_f * self.width) + self.rounds_p
if len(self.round_constants) != expected_constants:
Expand Down Expand Up @@ -183,9 +176,7 @@ def external_linear_layer(state: List[Fp], width: int) -> List[Fp]:
#
# This provides strong local diffusion within each block.
state_after_m4 = list(
chain.from_iterable(
_apply_m4(state[i : i + 4]) for i in range(0, width, 4)
)
chain.from_iterable(_apply_m4(state[i : i + 4]) for i in range(0, width, 4))
)

# Apply the outer circulant structure for global diffusion.
Expand All @@ -196,22 +187,15 @@ def external_linear_layer(state: List[Fp], width: int) -> List[Fp]:
# We precompute the four sums of elements at the same offset in each chunk.
# For each k in 0..4:
# sums[k] = state[k] + state[4 + k] + state[8 + k] + ... up to width
sums = [
sum((state_after_m4[j + k] for j in range(0, width, 4)), Fp(value=0))
for k in range(4)
]
sums = [sum((state_after_m4[j + k] for j in range(0, width, 4)), Fp(value=0)) for k in range(4)]

# Add the corresponding sum to each element of the state.
state_after_circulant = [
s + sums[i % 4] for i, s in enumerate(state_after_m4)
]
state_after_circulant = [s + sums[i % 4] for i, s in enumerate(state_after_m4)]

return state_after_circulant


def internal_linear_layer(
state: List[Fp], params: Poseidon2Params
) -> List[Fp]:
def internal_linear_layer(state: List[Fp], params: Poseidon2Params) -> List[Fp]:
"""
Applies the internal linear layer (M_I).

Expand All @@ -233,10 +217,7 @@ def internal_linear_layer(
s_sum = sum(state, Fp(value=0))
# For each element s_i, compute s_i' = d_i * s_i + sum(s).
# This is the efficient computation of (J + D)s.
new_state = [
s * d + s_sum
for s, d in zip(state, params.internal_diag_vectors, strict=False)
]
new_state = [s * d + s_sum for s, d in zip(state, params.internal_diag_vectors, strict=False)]
return new_state


Expand Down Expand Up @@ -279,9 +260,7 @@ def permute(state: List[Fp], params: Poseidon2Params) -> List[Fp]:
# 2. First Half of Full Rounds (R_F / 2)
for _r in range(half_rounds_f):
# Add round constants to the entire state.
state = [
s + round_constants[const_idx + i] for i, s in enumerate(state)
]
state = [s + round_constants[const_idx + i] for i, s in enumerate(state)]
const_idx += params.width
# Apply the S-box (x -> x^d) to the full state.
state = [s**S_BOX_DEGREE for s in state]
Expand All @@ -303,9 +282,7 @@ def permute(state: List[Fp], params: Poseidon2Params) -> List[Fp]:
# 4. Second Half of Full Rounds (R_F / 2)
for _r in range(half_rounds_f):
# Add round constants to the entire state.
state = [
s + round_constants[const_idx + i] for i, s in enumerate(state)
]
state = [s + round_constants[const_idx + i] for i, s in enumerate(state)]
const_idx += params.width
# Apply the S-box to the full state.
state = [s**S_BOX_DEGREE for s in state]
Expand Down
Loading
Loading