Files
zeekay 54ecf86beb feat(contracts): WarpZapDigest — on-chain D byte-identical to Go warp (lockstep)
Solidity library computing D = keccak256("LUX-WARP-ZAP-CORE-v1" || core), the
canonical Warp ZAP message digest, byte-for-byte identical to the Go reference
(luxfi/warp message.go marshalZAP + teleport/payload.go ComputeMessageHash).
core = 0x01||u32(networkId)||srcChain32||0x0(32)||u64(0)||u64(0)||u32(11)
"Pulsar-SHA3"||u32(90)||payload; payload(90)=u8(3)||u64(dest)||token(20)||
u256(amount)||recip(20)||u8(vaultIsZero)||u64(nonce). Proven against all 5
luxfi/warp sol_compatible fixtures via forge (test/forge/WarpZapDigest.t.sol,
foundry.toml scoped to the lib so it coexists with the Hardhat/OZ suite).
This is the on-chain half of the warp RLP->ZAP lockstep; BridgeV2.burn/claim
wire to it next (+ Envelope source-lineage fields).
2026-06-26 18:09:40 -07:00

54 lines
2.3 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {WarpZapDigest} from "../../contracts/lib/WarpZapDigest.sol";
/// Byte-equality oracle: every D below is the Go reference output from
/// github.com/luxfi/warp/teleport/fixtures (the "sol_compatible_*" vectors).
/// If Solidity computeD matches all of them, the on-chain digest is byte-
/// identical to what the validator set signs.
contract WarpZapDigestTest {
/// 20-byte address with every byte == b (the fixtures use all-same-byte
/// addresses; building them avoids EIP-55 address-literal ambiguity).
function rep(uint8 b) internal pure returns (address) {
uint160 x = 0;
for (uint256 i = 0; i < 20; i++) { x = (x << 8) | uint160(b); }
return address(x);
}
function test_small_burn() public pure {
bytes32 d = WarpZapDigest.computeD(
96369, bytes32(uint256(0x17871)), 1,
rep(0x11), 1000000000000000000, rep(0x22), true, 0);
require(d == 0x6fc798dfa7a7ac7012a02aca8d689aa582987131092301df58827fa5231b5ab9, "small_burn");
}
function test_large_vault() public pure {
bytes32 d = WarpZapDigest.computeD(
96369, bytes32(uint256(0x17871)), 42,
rep(0xaa), 123456789000000000000000000, rep(0xbb), false, 1);
require(d == 0x211990725d2020531f401e6480d292bab3054637863f61f4faa21f143cbc42f8, "large_vault");
}
function test_uint256_max() public pure {
bytes32 d = WarpZapDigest.computeD(
1, bytes32(uint256(1)), 96369,
rep(0xcc), type(uint256).max, rep(0xdd), false, type(uint64).max);
require(d == 0x653ec7199df29d151b6a8ac3681e9160b77987b4d5a06aa13a6afd286d858651, "uint256_max");
}
function test_one_wei() public pure {
bytes32 d = WarpZapDigest.computeD(
3, bytes32(uint256(3)), 7,
rep(0xee), 1, rep(0xff), true, 99);
require(d == 0xd385a6faf34a8ff1f7dd6edbb6b3aab14cf5237b07121916e99e2c7740245e8a, "one_wei");
}
function test_repeated_ab() public pure {
bytes32 d = WarpZapDigest.computeD(
96369, 0xabababababababababababababababababababababababababababababababab, 1,
rep(0x11), 1000000000000000000, rep(0x22), true, 0);
require(d == 0x72063ff81c4da92d7c4aacb4131452230bc0d8cfba2953af76d533c8abd34d84, "repeated_ab");
}
}