Skip to content

Commit

Permalink
rename proxyKey to commitmentKey to match specs
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonVranek committed Nov 7, 2024
1 parent 8e04c9b commit 8f97f05
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 227 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

[Registry.sol](src/Registry.sol)
- [x] Reduce `MIN_COLLATERAL` to 0.1 ETH. It needs to be non-zero to incentivize people to slash bad registrations.
- [ ] Optimistically accept an `OperatorCommitment` hash. It can be proven as fraudulent by generating the merkle tree in the fraud proof.
- [ ] Rename `proxyKey` to `commitmentKey`.
- [ ] ~~Optimistically accept an `OperatorCommitment` hash. It can be proven as fraudulent by generating the merkle tree in the fraud proof.~~
- [ ] Make the unregistration delay parameterizable by the proposer but requires it to be at least `TWO_EPOCHS`.
- [ ] Spec out the `Registration` message signed by a Validator BLS key.
- [ ] Make sure no one can overwrite an `OperatorCommitment`
Expand All @@ -14,10 +15,11 @@


[BytecodeSlasher.sol](src/BytecodeSlasher.sol)
- [ ] Update the `BytecodeSlasher` interface to include the slashing evidence, signed bytecode, operator commitment, proxy key, and function selector.
- [x] If we want to support 'stateful' slashing contracts we should consider signing `slasherAddress || functionSelector` and invoking that instead of deploying and executing bytecode.
- [ ] Replace BytecodeSlasher concept with a way to call a `Slasher` contract address.
- [ ] Update the `Slasher` interface to include the slashing evidence, signed bytecode, operator commitment, proxy key, and function selector.
- [ ] Any additional modifiers needed?
- [ ] Verify the `Delegation` signature inside the `BytecodeSlasher`
- [ ] If we want to support 'stateful' slashing contracts we should consider signing `slasherAddress || functionSelector` and invoking that instead of deploying and executing bytecode.
- [ ] Verify the `Commitment` signature inside the `Slasher`


## Schemas
Expand Down
241 changes: 18 additions & 223 deletions src/Registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,28 @@ contract Registry {

struct Registration {
uint256[2] pubkey; // compressed bls pubkey
uint256[8] signature; // flattened registration signature
uint256[8] signature; // flattened Registration signature
}

struct Operator {
bytes32 proxyKey; // compressed ecdsa key without prefix
bytes32 commitmentKey; // compressed ecdsa key without prefix
address operator; // msg.sender can be a multisig
uint72 collateral;
uint72 collateral; // todo save as GWEI
uint32 registeredAt;
uint32 unregisteredAt;
// anything else?
}

struct Leaf {
uint256[2] pubkey; // compressed pubkey
bytes32 registrationCommitment; // sha256(signature || proxyKey)
bytes32 registrationCommitment; // sha256(signature || commitmentKey)
}

mapping(bytes32 operatorCommitment => Operator) public commitments;

// Constants
uint256 constant MIN_COLLATERAL = 1 ether;
uint256 constant TWO_EPOCHS = 64;
uint256 constant MIN_COLLATERAL = 0.1 ether;
uint256 constant TWO_EPOCHS = 64; // parameterize when you join

// Errors
error InsufficientCollateral();
Expand All @@ -50,7 +51,7 @@ contract Registry {

function register(
Registration[] calldata registrations,
bytes32 proxyKey,
bytes32 commitmentKey,
uint256 height
) external payable {
// check collateral
Expand All @@ -61,15 +62,15 @@ contract Registry {
// operatorCommitment hash = merklize registrations
bytes32 operatorCommitment = createCommitment(
registrations,
proxyKey,
commitmentKey,
height
);

// add operatorCommitment to mapping
commitments[operatorCommitment] = Operator({
operator: msg.sender,
proxyKey: proxyKey,
collateral: uint72(msg.value),
commitmentKey: commitmentKey,
collateral: uint72(msg.value), // todo save as GWEI
registeredAt: uint32(block.number),
unregisteredAt: 0
});
Expand All @@ -79,7 +80,7 @@ contract Registry {

function createCommitment(
Registration[] calldata registrations,
bytes32 proxyKey,
bytes32 commitmentKey,
uint256 height
) internal view returns (bytes32 operatorCommitment) {
uint256 batchSize = 1 << height; // guaranteed pow of 2
Expand All @@ -95,7 +96,7 @@ contract Registry {
for (uint256 i = 0; i < registrations.length; i++) {
// Create registration commitment by hashing signature and metadata
bytes32 registrationCommitment = sha256(
abi.encodePacked(registrations[i].signature, proxyKey)
abi.encodePacked(registrations[i].signature, commitmentKey)
);

// Create leaf node by hashing pubkey and commitment
Expand All @@ -122,7 +123,7 @@ contract Registry {
bytes32 operatorCommitment,
BLS12381.G1Point calldata pubkey,
BLS12381.G2Point calldata signature,
bytes32 proxyKey,
bytes32 commitmentKey,
bytes32[] calldata proof,
uint256 leafIndex
) external {
Expand All @@ -134,15 +135,16 @@ contract Registry {
// reconstruct leaf
bytes32 leaf = sha256(abi.encodePacked(
pubkeyBytes,
sha256(abi.encodePacked(signatureBytes, proxyKey))
sha256(abi.encodePacked(signatureBytes, commitmentKey))
));

// verify proof against operatorCommitment
if (MerkleUtils.verifyProof(proof, operatorCommitment, leaf, leafIndex)) {
revert FraudProofMerklePathInvalid();
}

// reconstruct message todo
// reconstruct message
// todo what exactly are they signing?
bytes memory message = bytes("");

// verify signature
Expand Down Expand Up @@ -218,211 +220,4 @@ contract Registry {
// Return the pairing check that denotes the correctness of the signature
return BLS12381.pairing(pubkey, msgG2, BLS12381.negGeneratorG1(), sig);
}
}

// contract Registry2 {
// struct Validator {
// BLS12381.G1Point pubkey;
// BLS12381.G2Point signature;
// address operator;
// uint64 registeredAt;
// }

// struct Registration {
// BLS12381.G1Point pubkey;
// BLS12381.G2Point signature;
// }

// // Pack operator info into a struct that fits in one storage slot
// struct OperatorInfo {
// uint64 validatorCount;
// uint64 unregisteredAt; // 0 means not unregistered
// uint128 collateral; // Using uint128 since 1 ether fits easily
// }

// mapping(address => OperatorInfo) public operatorInfo;
// mapping(address => mapping(uint256 => Validator))
// public operatorToValidator;

// // Constants
// uint256 constant MIN_COLLATERAL = 1 ether;
// uint256 constant TWO_EPOCHS = 64;

// // Errors
// error InsufficientCollateral(uint256 sent);
// error NotUnregistered();
// error UnregistrationDelayNotMet();
// error AlreadyUnregistered();
// error NoCollateralToClaim();
// error SignatureWasValid();
// error WrongPubkey();
// error WrongSignature();

// // Events
// event ValidatorRegistered(
// address indexed operator,
// BLS12381.G1Point pubkey,
// BLS12381.G2Point signature,
// uint64 activeAfter
// );
// event CollateralAdded(address indexed operator, uint256 amount);
// event CollateralRemoved(address indexed operator, uint256 amount);
// event OperatorUnregistered(address indexed operator, uint64 unregisteredAt);
// event ValidatorRegistrationSlashed(
// address indexed operator,
// uint256 index,
// BLS12381.G1Point pubkey
// );

// function register(Registration[] calldata validators) external payable {
// OperatorInfo storage info = operatorInfo[msg.sender];

// // Ensure operator isn't already unregistering
// if (info.unregisteredAt != 0) {
// // todo but should we allow re-registering?
// revert AlreadyUnregistered();
// }

// uint256 newCollateral = info.collateral + msg.value;

// // Check collateral requirement
// if (newCollateral < MIN_COLLATERAL) {
// revert InsufficientCollateral(newCollateral);
// }

// // Register each validator
// uint64 timestamp = uint64(block.timestamp);
// uint64 activeAfterTime = timestamp + 1 days;

// for (uint256 i = 0; i < validators.length; i++) {
// operatorToValidator[msg.sender][
// info.validatorCount + i
// ] = Validator({
// pubkey: validators[i].pubkey,
// signatureHash: _hashSignature(validators[i].signature),
// registeredAt: timestamp,
// activeAfter: activeAfterTime
// });

// emit ValidatorRegistered(
// msg.sender,
// validators[i].pubkey,
// validators[i].signature,
// activeAfterTime
// );
// }

// // Update operator info
// info.validatorCount += uint64(validators.length);
// info.collateral = uint128(newCollateral);

// emit CollateralAdded(msg.sender, msg.value);
// }

// function unregister() external {
// OperatorInfo storage info = operatorInfo[msg.sender];

// // Check that they haven't already unregistered
// if (info.unregisteredAt != 0) {
// revert AlreadyUnregistered();
// }

// // Set unregistration timestamp
// info.unregisteredAt = uint64(block.number);

// emit OperatorUnregistered(msg.sender, info.unregisteredAt);
// }

// function claimCollateral() external {
// OperatorInfo storage info = operatorInfo[msg.sender];

// // Check that they've unregistered
// if (info.unregisteredAt == 0) {
// revert NotUnregistered();
// }

// // Check that enough time has passed
// if (block.number < info.unregisteredAt + TWO_EPOCHS) {
// revert UnregistrationDelayNotMet();
// }

// // Check there's collateral to claim
// if (info.collateral == 0) {
// revert NoCollateralToClaim();
// }

// // Store amount to return
// uint256 amountToReturn = info.collateral;

// // Clear operator info
// delete operatorInfo[msg.sender];

// // TODO safe transfer for rentrancy
// (bool success, ) = msg.sender.call{value: amountToReturn}("");
// require(success, "Transfer failed");

// emit CollateralRemoved(msg.sender, amountToReturn);
// }

// function slashRegistration(
// address operator,
// uint256 index,
// BLS12381.G1Point calldata pubkey,
// BLS12381.G2Point calldata signature
// ) external {
// Validator memory validator = operatorToValidator[msg.sender][index];

// // Verify the supplied calldata matches what has been committed
// if (_hashBLSPubKey(validator.pubkey) != _hashBLSPubKey(pubkey)) {
// revert WrongPubkey();
// }

// if (validator.signatureHash != _hashSignature(signature)) {
// revert WrongSignature();
// }

// // Verify the signature
// bytes memory message = abi.encodePacked(operator);
// if (_verifySignature(message, signature, pubkey)) {
// revert SignatureWasValid();
// }

// // todo slash the validator collateral
// // todo do we pay the msg.sender?

// emit ValidatorRegistrationSlashed(operator, index, pubkey);
// }

// /**
// * @notice Returns `true` if the BLS signature on the message matches against the public key
// * @param message The message bytes
// * @param sig The BLS signature
// * @param pubkey The BLS public key of the expected signer
// */
// function _verifySignature(
// bytes memory message,
// BLS12381.G2Point memory sig,
// BLS12381.G1Point memory pubkey
// ) internal view returns (bool) {
// bytes memory domainSeparator = bytes("Proposer Commitment Registry");
// // Hash the message bytes into a G2 point
// BLS12381.G2Point memory msgG2 = message.hashToCurveG2(domainSeparator);

// // Return the pairing check that denotes the correctness of the signature
// return BLS12381.pairing(pubkey, msgG2, BLS12381.negGeneratorG1(), sig);
// }

// function _hashBLSPubKey(
// BLS12381.G1Point memory pubkey
// ) internal pure returns (bytes32) {
// uint256[2] memory compressedPubKey = pubkey.compress();
// return keccak256(abi.encodePacked(compressedPubKey));
// }

// function _hashSignature(
// BLS12381.G2Point memory signature
// ) internal pure returns (bytes32) {
// uint256[8] memory flattenedSignature = signature.flatten();
// return keccak256(abi.encodePacked(flattenedSignature));
// }
// }
}

0 comments on commit 8f97f05

Please sign in to comment.