diff --git a/.gitmodules b/.gitmodules index c65a5965..8171b7f5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "contracts/lib/forge-std"] path = contracts/lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "contracts/lib/telepathy-contracts"] + path = contracts/lib/telepathy-contracts + url = https://github.com/succinctlabs/telepathy-contracts diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 7074473c..2f1b5f16 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -5,7 +5,7 @@ ffi = true libs = ['lib'] optimizer = true optimizer_runs = 1_000_000_000 -solc = "0.8.19" +solc = "0.8.16" fs_permissions = [{ access = "read", path = "./test/data/"}] [profile.default.optimizer_details] diff --git a/contracts/lib/telepathy-contracts b/contracts/lib/telepathy-contracts new file mode 160000 index 00000000..0f3c6812 --- /dev/null +++ b/contracts/lib/telepathy-contracts @@ -0,0 +1 @@ +Subproject commit 0f3c6812d6bda96dde6ab7bdd8f8391c47bf5d0b diff --git a/contracts/remappings.txt b/contracts/remappings.txt index 1076a425..9825df7c 100644 --- a/contracts/remappings.txt +++ b/contracts/remappings.txt @@ -1,2 +1,3 @@ ds-test/=lib/forge-std/lib/ds-test/src/ -forge-std/=lib/forge-std/src/ \ No newline at end of file +forge-std/=lib/forge-std/src/ +telepathy-libs/=lib/telepathy-contracts/src/libraries/ \ No newline at end of file diff --git a/contracts/script/SpectreDeployLocal.s.sol b/contracts/script/SpectreDeployLocal.s.sol index 91c64873..cc27f680 100644 --- a/contracts/script/SpectreDeployLocal.s.sol +++ b/contracts/script/SpectreDeployLocal.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.19; +pragma solidity 0.8.16; import "forge-std/Script.sol"; import "forge-std/safeconsole.sol"; diff --git a/contracts/script/SpectreDeployYulLocal.s.sol b/contracts/script/SpectreDeployYulLocal.s.sol index eed3ee43..42bf177e 100644 --- a/contracts/script/SpectreDeployYulLocal.s.sol +++ b/contracts/script/SpectreDeployYulLocal.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.19; +pragma solidity 0.8.16; import "forge-std/Script.sol"; import "forge-std/safeconsole.sol"; diff --git a/contracts/snark-verifiers/committee_update_aggregated.sol b/contracts/snark-verifiers/committee_update_aggregated.sol index edd5e9f6..239463a9 100644 --- a/contracts/snark-verifiers/committee_update_aggregated.sol +++ b/contracts/snark-verifiers/committee_update_aggregated.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity 0.8.16; contract Verifier { diff --git a/contracts/snark-verifiers/sync_step.sol b/contracts/snark-verifiers/sync_step.sol index 4e6f52d2..107ca332 100644 --- a/contracts/snark-verifiers/sync_step.sol +++ b/contracts/snark-verifiers/sync_step.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity 0.8.16; contract Verifier { diff --git a/contracts/src/Spectre.sol b/contracts/src/Spectre.sol index 5ddd50f8..03bfbbdb 100644 --- a/contracts/src/Spectre.sol +++ b/contracts/src/Spectre.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.16; import { SyncStep } from "./SyncStep.sol"; diff --git a/contracts/src/SyncStep.sol b/contracts/src/SyncStep.sol index ac571902..28142982 100644 --- a/contracts/src/SyncStep.sol +++ b/contracts/src/SyncStep.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.16; + +import {SSZ} from "telepathy-libs/SimpleSerialize.sol"; +import "forge-std/console.sol"; -library SyncStep { - bytes32 constant DOMAIN = keccak256("sync-step"); // TODO: Fix this to the actual domain used for the given network +library SyncStep { struct SyncStepArgs { uint256 attestedSlot; uint256 finalizedSlot; @@ -17,17 +19,19 @@ library SyncStep { * This must always match the prodecure used in lightclient-circuits/src/sync_step_circuit.rs - SyncStepCircuit::instance() * @param args The arguments for the sync step * @param keysPoseidonCommitment The commitment to the keys used in the sync step + * @return comm The public input commitment that can be sent to the verifier contract. */ - function toInputCommitment(SyncStepArgs memory args, bytes32 keysPoseidonCommitment) internal pure returns (uint256 comm) { - // May need to convert to LE - bytes32 attestedSlotBytes = bytes32(args.attestedSlot); - bytes32 finalizedSlotBytes = bytes32(args.finalizedSlot); - bytes32 participationBytes = bytes32(args.participation); + function toInputCommitment(SyncStepArgs memory args, bytes32 keysPoseidonCommitment) internal view returns (uint256) { + bytes32 attestedSlotBytes = SSZ.toLittleEndian(args.attestedSlot); + bytes32 finalizedSlotBytes = SSZ.toLittleEndian(args.finalizedSlot); + bytes32 participationBytes = SSZ.toLittleEndian(args.participation); bytes32 h = sha256(bytes.concat(attestedSlotBytes, finalizedSlotBytes)); - h = sha256(bytes.concat(participationBytes, h)); - h = sha256(bytes.concat(args.executionPayloadRoot, h)); - h = sha256(bytes.concat(keysPoseidonCommitment, h)); - comm = uint256(h) & ((uint256(1) << 253) - 1); // truncate to 253 bits + h = sha256(bytes.concat(h, participationBytes)); + h = sha256(bytes.concat(h, args.executionPayloadRoot)); + h = sha256(bytes.concat(h, keysPoseidonCommitment)); + + uint256 commitment = uint256(SSZ.toLittleEndian(uint256(h))); + return commitment & ((uint256(1) << 253) - 1); // truncated to 253 bits } } diff --git a/contracts/test/SpectreSyncStep.sol b/contracts/test/SpectreSyncStep.sol index 3a50e7a0..c8945aab 100644 --- a/contracts/test/SpectreSyncStep.sol +++ b/contracts/test/SpectreSyncStep.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.19; +pragma solidity 0.8.16; import "forge-std/Script.sol"; import "forge-std/safeconsole.sol"; diff --git a/contracts/test/SyncStep.t.sol b/contracts/test/SyncStep.t.sol new file mode 100644 index 00000000..89cd4372 --- /dev/null +++ b/contracts/test/SyncStep.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +import {SSZ} from "telepathy-libs/SimpleSerialize.sol"; +import {SyncStep} from "../src/SyncStep.sol"; + +contract SyncStepInputEncoding is Test { + using SyncStep for SyncStep.SyncStepArgs; + + // attested_slot: 40 + // finalized_slot: 24 + // participation: 32 + // executionPayloadRoot: d11151b7c53e3ed79401bcdbb74845bc99ed0de99d32ebee241fc58c1e8c68cb + // keys poseidon commitment: 02b0a3b579953718463ac4baa9987225c5d74b0a7b4193e51ae091f5a0aa1c11 + // input_commitment: 8d387254c3f6a8074f1f4d78f99eec52a2a93104494d69ac6f52884780426019 + + function testToInputCommitment() public { + SyncStep.SyncStepArgs memory args = SyncStep.SyncStepArgs({ + attestedSlot: 40, + finalizedSlot: 24, + participation: 32, + executionPayloadRoot: 0xd11151b7c53e3ed79401bcdbb74845bc99ed0de99d32ebee241fc58c1e8c68cb + }); + bytes32 keysPoseidonCommitment = 0x02b0a3b579953718463ac4baa9987225c5d74b0a7b4193e51ae091f5a0aa1c11; + + uint256 comm = args.toInputCommitment(keysPoseidonCommitment); + + // expected commitment as a little endian bit integer expressed as hex + bytes32 expected = 0x8d387254c3f6a8074f1f4d78f99eec52a2a93104494d69ac6f52884780426019; + + assertEq(SSZ.toLittleEndian(comm), expected, "Input commitment does not match"); + } +}