Skip to content

Conversation

@unnawut
Copy link
Collaborator

@unnawut unnawut commented Nov 25, 2025

🗒️ Description

Adding test vectors for verifying signatures in SignedBlockWithAttestation

Some notes:

  • Since it heavily resembles other fixtures, I used claude code heavily, but also took a lot of effort to clean it up.

Still pending:

  • [] Production signatures Will be done in the next PR

Usage

Feed signedBlockWithAttestation and anchorState into SignedBlockWithAttestation.verify_signatures(), the function should return true. When expectedException is provided, expect that the signature verification should throw an exception.

The generated vectors look like this:

{
    "tests/consensus/devnet/verify_signature/test_valid_signatures.py::test_proposer_and_attester_signatures[fork_Devnet][fork_Devnet-verify_signature_test]": {
        "network": "Devnet",
        "anchorState": {
            "config": {
                "genesisTime": 0
            },
            "slot": 0,
            "latestBlockHeader": {
                "slot": 0,
                "proposerIndex": 0,
                "parentRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
                "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
                "bodyRoot": "0xdba9671bac9513c9482f1416a53aabd2c6ce90d5a5f865ce5a55c775325c9136"
            },
            "latestJustified": {
                "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                "slot": 0
            },
            "latestFinalized": {
                "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                "slot": 0
            },
            "historicalBlockHashes": {
                "data": []
            },
            "justifiedSlots": {
                "data": []
            },
            "validators": {
                "data": [
                    {
                        "pubkey": "0xb40ec9783b56572d99965130ad1cec4f066df43a0fd89d22d420535c62b52711cdaf7f5f696c6b1e4df66a6bab48bb51abcdd77e",
                        "index": 0
                    },
                    {
                        "pubkey": "0xc5ed4b6fa46e83281e29201b878ad52b4a9b8a2f3c9d8017cfd9b81e8097e1372a097e62be37194c39e2f36f76e8906d2e818238",
                        "index": 1
                    },
                    {
                        "pubkey": "0x0cc8a378cdeb1a3c4b87156bcba3e87d31fb8c5f1c3ce74b4370001086b8bd5a502ea12d0878536b19cb6769b7285e1c0504fb3e",
                        "index": 2
                    }
                ]
            },
            "justificationsRoots": {
                "data": []
            },
            "justificationsValidators": {
                "data": []
            }
        },
        "signedBlockWithAttestation": {
            "message": {
                "block": {
                    "slot": 1,
                    "proposerIndex": 1,
                    "parentRoot": "0x9e3b89451933da29e3697c588770a4d63c900e0a8af56e2a4e0777abdd355450",
                    "stateRoot": "0x85222dc92460f8b51fe414fb34ef9f35247653eb6036b1268261a91ba617cda8",
                    "body": {
                        "attestations": {
                            "data": [
                                {
                                    "validatorId": 0,
                                    "data": {
                                        "slot": 1,
                                        "head": {
                                            "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                                            "slot": 0
                                        },
                                        "target": {
                                            "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                                            "slot": 0
                                        },
                                        "source": {
                                            "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                                            "slot": 0
                                        }
                                    }
                                },
                                {
                                    "validatorId": 2,
                                    "data": {
                                        "slot": 1,
                                        "head": {
                                            "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                                            "slot": 0
                                        },
                                        "target": {
                                            "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                                            "slot": 0
                                        },
                                        "source": {
                                            "root": "0x0000000000000000000000000000000000000000000000000000000000000000",
                                            "slot": 0
                                        }
                                    }
                                }
                            ]
                        }
                    }
                },
                "proposerAttestation": {
                    "validatorId": 1,
                    "data": {
                        "slot": 1,
                        "head": {
                            "root": "0xde28efe59b19913717bb76a32611fe839ad69a4b3c0915d79c8304b35b57ddf7",
                            "slot": 1
                        },
                        "target": {
                            "root": "0xde28efe59b19913717bb76a32611fe839ad69a4b3c0915d79c8304b35b57ddf7",
                            "slot": 1
                        },
                        "source": {
                            "root": "0x9e3b89451933da29e3697c588770a4d63c900e0a8af56e2a4e0777abdd355450",
                            "slot": 0
                        }
                    }
                }
            },
            "signature": {
                "data": [
                    {
                        "path": {
                            "siblings": {
                                "data": [
                                    {
                                        "data": [
                                            1715018400,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            318044943,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            1468833114,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            1266260145,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            298307958,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            1430973325,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            1056622773,
                                            ...
                                        ]
                                    },
                                    {
                                        "data": [
                                            483358618,
                                            ...
                                        ]
                                    }
                                ]
                            }
                        },
                        "rho": {
                            "data": [
                                1133244814,
                                ...
                            ]
                        },
                        "hashes": {
                            "data": [
                                {
                                    "data": [
                                        780469602,
                                        ...
                                    ]
                                },
                                {
                                    "data": [
                                        1605769376,
                                        ...
                                    ]
                                },
                                {
                                    "data": [
                                        1181134299,
                                        ...
                                    ]
                                },
                                {
                                    "data": [
                                        1347741188,
                                        ...
                                    ]
                                }
                            ]
                        }
                    },
                    ... (2 more signatures truncated)
                ]
            }
        },
        "_info": {
            "hash": "0x85747e3680f0686a8ee60ad657c0ea06878219df31e568b1d6ae6c58e5007fe7",
            "comment": "`leanSpec` generated test",
            "testId": "tests/consensus/devnet/verify_signature/test_valid_signatures.py::test_proposer_and_attester_signatures[fork_Devnet]",
            "description": "Test valid proposer and attester signatures in SignedBlockWithAttestation.\n\nScenario\n--------\n- Single block at slot 1\n- 3 validators in the genesis state\n- 2 additional attestations from validators 0 and 2 (in addition to proposer)\n- Verifies that all signatures are generated correctly\n\nExpected Behavior\n-----------------\n1. Proposer's signature in SignedBlockWithAttestation can be verified against\n   the validator's pubkey in the state\n2. Attester's signatures in SignedBlockWithAttestation can be verified against\n   the validator's pubkey in the state\n\nWhy This Matters\n----------------\nThis test verifies multi-validator signature scenarios:\n- Multiple XMSS keys are generated for different validators\n- Attestations from non-proposer validators are correctly verified\n- Signature aggregation works with multiple attestations (signature positions are correct)",
            "fixtureFormat": "verify_signature_test"
        }
    }
}

🔗 Related Issues or PRs

✅ Checklist

  • Ran tox checks to avoid unnecessary CI fails:
    uvx tox
  • Considered adding appropriate tests for the changes.
  • Considered updating the online docs in the ./docs/ directory.

@unnawut
Copy link
Collaborator Author

unnawut commented Nov 25, 2025

This PR still needs:

  1. Production signatures?
  2. A way for client to retrieve the same validator private keys that generated these signatures

@fselmo
Copy link
Contributor

fselmo commented Nov 25, 2025

Just flying by and noticed that fields are still not all lowerCamelCase in the fixtures. Is this still an issue? I wonder if we need to standardize what is in #157 and maybe add tests for this so it doesn't slip by. Whatever uses model_dump needs to use by_alias=True but we should switch to using a common method that makes this the default (as is done in that PR with to_json()).

@unnawut
Copy link
Collaborator Author

unnawut commented Nov 25, 2025

Just flying by and noticed that fields are still not all lowerCamelCase in the fixtures. Is this still an issue? I wonder if we need to standardize what is in #157 and maybe add tests for this so it doesn't slip by. Whatever uses model_dump needs to use by_alias=True but we should switch to using a common method that makes this the default (as is done in that PR with to_json()).

Right I'll adopt #157's way once it's merged done

@unnawut unnawut force-pushed the signed-block-vectors branch from 2cd8e1a to bdd7ca6 Compare December 2, 2025 04:13
KolbyML
KolbyML previously approved these changes Dec 3, 2025
Copy link
Contributor

@KolbyML KolbyML left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: looks good

@KolbyML KolbyML dismissed their stale review December 3, 2025 05:41

I meant to approve the other spec pr I was reviewing, this one is in draft myb

@unnawut unnawut force-pushed the signed-block-vectors branch from bdd7ca6 to 3205db8 Compare December 4, 2025 13:35
@unnawut unnawut changed the title test(signatures): SignedBlockWithAttestation test(signatures): verify signatures in SignedBlockWithAttestation Dec 4, 2025
@unnawut
Copy link
Collaborator Author

unnawut commented Dec 4, 2025

Waiting to rebase once #218 is merged. This PR will be a lot cleaner after the rebase.

@unnawut unnawut force-pushed the signed-block-vectors branch from a00b724 to 11d88a0 Compare December 9, 2025 05:06
@unnawut
Copy link
Collaborator Author

unnawut commented Dec 9, 2025

I've slimmed down this PR to use the default test signatures just so the PR review can focus on these signature verification tests and get one thing discussed & merged at a time

Some stuff that'll be in separate PRs:

  1. Use of prod signatures -> Another PR based on unnawut/leanSpec@signed-block-vectors...prod-signatures framework: ability to use test or prod signature scheme in tests #230
  2. There's some redundant fixture code across ForkChoiceTest, StateTransitionTest and VerifySignaturesTest, e.g. expect_exception handling and get_shared_key_manger(), that could be moved to BaseConsensusFixture -> Another PR based on unnawut/leanSpec@signed-block-vectors...refactor-base-consensus-fixture

@unnawut unnawut marked this pull request as ready for review December 9, 2025 05:52
@unnawut unnawut requested review from g11tech and tcoratger December 9, 2025 05:52
@unnawut unnawut added the tests Scope: Changes to the spec tests label Dec 9, 2025
@unnawut unnawut added this to the pq-devnet-2 milestone Dec 9, 2025
Copy link
Collaborator

@tcoratger tcoratger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, very minot nits, otherwise looks good to me.

@unnawut unnawut merged commit d6cec9b into leanEthereum:main Dec 10, 2025
10 checks passed
@unnawut unnawut deleted the signed-block-vectors branch December 10, 2025 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tests Scope: Changes to the spec tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants