跳至主要内容
本页面使用机器翻译自英语,可能包含错误或不清楚的语言。如需最准确的信息,请参阅英文原文。由于更新频繁,部分内容可能与英文原文有出入。请加入我们在 Crowdin 上的努力,帮助我们改进本页面的翻译。 (Crowdin translation page, Contributing guide)

预编合同

Kaia 提供了几种有用的预编译合同,这些合同都不会改变国家。 这些合约作为原生实现在平台本身中实施,这意味着它们是 Kaia 客户端规范的一部分。 从地址 0x01 到 0x0A 的预编译合约与以太坊中的合约相同。 预编译的功用可分为四大类: 。 椭圆曲线数字签名恢复 . 哈希方法 . 存储器复制 . 为 zk 证明启用椭圆曲线数学的方法。 Kaia 还实现了从 0x3FD 到 0x3FF 的预编译合约,以支持新的 Kaia 功能。

备注

伊斯坦布尔 EVM 硬分叉前部署的合同应使用原始地址。

  • 情况 1)Kairos 中块号为 #75373310 的合约将 0x09、0x0a 和 0x0b 分别作为 vmLog、feePayer 和 validateSender 的地址,因此无法使用 blake2f。
  • 案例 2)Kairos 中块号为 #75373314 的合约将 0x09 识别为 blake2f 的地址,并将 0x3fd、0x3fe 和 0xff 识别为 vmLog、feePayer 和 validateSender 的地址。

预编译的合同相关硬分叉变更可在本页底部找到。 转到 Hardfork Changes

地址 0x01: ecrecover(hash, v, r, s)

地址 0x01 实现了 ecrecover。 它通过计算 ECDSA 的恢复函数来返回给定签名的地址。 它是唯一带有 solidity 封装的预编译器。 其功能原型如下


function ecRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public view returns (address) {
address r = ecrecover(hash, v, r, s); // prototype function
require(r != address(0), "signature is invalid");
}// 实体封装

地址 0x02: sha256(data)

地址 0x02 实现了 SHA256 散列。 它根据给定数据返回 SHA256 哈希值。 它主要用于比特币和 Zcash,而以太坊则使用 Keccak256。 其功能原型如下


function sha256(uint256 numberToHash) public view returns (bytes32 hash) {
(bool ok, bytes memory hashData) = address(0x02).staticcall(abi.encode(numberToHash));
require(ok);
hash = abi.decode(hashData, (bytes32));
}

在 Yul / Inline Assembly 中的使用:


function sha256Yul(uint256 numberToHash) public view returns (bytes32) {
assembly {
mstore(0, numberToHash) // store number in zeroth memory word
let ok := staticcall(gas(), 2, 0, 32, 0, 32)
if iszero(ok) {
revert(0,0)
}
return(0, 32)
}
}

地址 0x03: ripemd160(data)

地址 0x03 实现了 RIPEMD160 哈希算法。 它根据给定数据返回 RIPEMD160 哈希值。 其功能原型如下


函数 RIPEMD160(bytes calldata data) 公共视图返回 (bytes20 h) {
(bool ok, bytes memory out) = address(0x03).staticcall(data);
require(ok);
h = bytes20(abi.decode(out, (bytes32))<< 96);
}

地址 0x04: datacopy(data)

地址 0x04 实现了数据复制(即身份识别功能)。 它直接返回输入数据,不做任何修改。 Solidity 编译器不支持这种预编译合同。 可以使用以下带有内联程序集的代码来调用这个预编译合同。


function callDatacopy(bytes memory data) public returns (bytes memory) {
bytes memory ret = new bytes(data.length);
assembly {
let len := mload(data)
if iszero(call(gas, 0x04, 0, add(data, 0x20), len, add(ret,0x20), len)) {
invalid()
}
}
return ret;
}

地址 0x05: bigModExp(base, exp, mod)

地址 0x05 实现了公式base**exp%mod。 它根据给定数据返回结果。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。 请注意,尽管预编译合同支持任意长度的输入,但下面的代码以固定长度的输入为例。


function callBigModExp(bytes32 base, bytes32 exponent, bytes32 modulus) public returns (bytes32 result) {
assembly {
// free memory pointer
let memPtr := mload(0x40)
// length of base, exponent, modulus
mstore(memPtr, 0x20)
mstore(add(memPtr, 0x20), 0x20)
mstore(add(memPtr, 0x40), 0x20)
// assign base, exponent, modulus
mstore(add(memPtr, 0x60), base)
mstore(add(memPtr, 0x80), exponent)
mstore(add(memPtr, 0xa0), modulus)
// call the precompiled contract BigModExp (0x05)
let success := call(gas, 0x05, 0x0, memPtr, 0xc0, memPtr, 0x20)
switch success
case 0 {
revert(0x0, 0x0)
} default {
result := mload(memPtr)
}
}
}

地址 0x06: bn256Add(ax, ay, bx, by)

地址 0x06 实现了本地椭圆曲线点加法。 它返回一个代表 (ax, ay) + (bx, by) 的椭圆曲线点,这样 (ax, ay) 和 (bx, by) 是曲线 bn256 上的有效点。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) public returns (bytes32[2] memory result) {
bytes32[4] memory input;
input[0] = ax;
input[1] = ay;
input[2] = bx;
input[3] = by;
assembly {
let success := call(gas, 0x06, 0, input, 0x80, result, 0x40)
switch success
case 0 {
revert(0,0)
}
}
}

地址 0x07: bn256ScalarMul(x, y, scalar)

地址 0x07 实现了与标量值的本地椭圆曲线乘法。 它返回一个代表 scalar * (x, y),并且 (x, y) 是 bn256 曲线上一个有效曲线点的椭圆曲线点。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar) public returns (bytes32[2] memory result) {
bytes32[3] memory input;
input[0] = x;
input[1] = y;
input[2] = scalar;
assembly {
let success := call(gas, 0x07, 0, input, 0x60, result, 0x40)
switch success
case 0 {
revert(0,0)
}
}
}

地址 0x08: bn256Pairing(a1, b1, a2, b2, a3, b3, ..., ak, bk)

地址 0x08 实现了椭圆曲线解析操作,以执行 zkSNARK 验证。 更多信息,请参见 EIP-197。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function callBn256Pairing(bytes memory input) public returns (bytes32 result) {
// input is a serialized bytes stream of (a1, b1, a2, b2, ..., ak, bk) from (G_1 x G_2)^k
uint256 len = input.length;
require(len % 192 == 0);
assembly {
let memPtr := mload(0x40)
let success := call(gas, 0x08, 0, add(input, 0x20), len, memPtr, 0x20)
switch success
case 0 {
revert(0,0)
} default {
result := mload(memPtr)
}
}
}

Address 0x09: blake2F(rounds, h, m, t, f)

地址 0x09 实现了 BLAKE2b F 压缩功能。 更多信息,请参阅 EIP-152。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function callBlake2F(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, bytes8[2] memory t, bool f) public view returns (bytes32[2] memory) {
bytes32[2] memory output;
bytes memory args = abi.encodePacked(rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f);
assembly {
if iszero(staticcall(not(0), 0x09, add(args, 32), 0xd5, output, 0x40)) {
revert(0, 0)
}
}
return output;
}

Address 0x0A: kzg(data)

地址 0x0A 实现了 KZG 验证,在给定点验证到给定值。 更多信息,请参阅 EIP-4844。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function callKzg(bytes memory data) public returns (bytes memory) {
bytes memory ret;
assembly {
let len := mload(data)
if iszero(call(gas(), 0x0a, 0, add(data, 0x20), len, 0, 0)) {
revert (0,0)
}
}
return ret;
}

地址 0x0B:bls12381G1Add(input)

地址 0x0B 实现了 BLS12381 G1 添加选项操作。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381add() public returns (bytes memory) {
bytes memory input =hex"0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f560000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee000000000000000000000000000000000001101098f5c39893765766af4512a0c74e1bb89bc7e6fdf14e3e7337d257cc0f94658179d83320b99f31ff94cd2bac0000000000000000000000000000000003e1a9f9f44ca2cdab4f43a1a3ee3470fdf90b2fc228eb3b709fcd72f014838ac82a6d797aeefed9a0804b22ed1ce8f7";
(bool ok, bytes memory output) = address(0x0b).call(input);
require(ok, "bls12381 G1 add operation failed");
return output;
}

地址 0x0C:bls12381G1MultiExp(input)

地址 0x0C 实现了 BLS12381 G1 的乘法运算。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381mul() public returns (bytes memory) {
bytes memory input =hex"00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002";
(bool ok, bytes memory output) = address(0x0c).call(input);
require(ok, "bls12381 G1 muloperation failed");
return output;
}
function bls12381multiexp() public returns (bytes memory) {
bytes memory input =hex"0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000e12039459c60491672b6a6282355d8765ba6272387fb91a3e9604fa2a81450cf16b870bb446fc3a3e0a187fff6f89450000000000000000000000000000000018b6c1ed9f45d3cbc0b01b9d038dcecacbd702eb26469a0eb3905bd421461712f67f782b4735849644c1772c93fe3d09000000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000147b327c8a15b39634a426af70c062b50632a744eddd41b5a4686414ef4cd9746bb11d0a53c6c2ff21bbcf331e07ac9200000000000000000000000000000000078c2e9782fa5d9ab4e728684382717aa2b8fad61b5f5e7cf3baa0bc9465f57342bb7c6d7b232e70eebcdbf70f903a450000000000000000000000000000000000000000000000000000000000000034";
(bool ok, bytes memory output) = address(0x0c).call(input);
require(ok, "bls12381 G1 multiexp operation failed");
return output;
}

地址 0x0D:bls12381G2Add(input)

地址 0x0D 实现 BLS12381 G2 加法运算。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381g2add() public returns (bytes memory) {
bytes memory input =hex"000000000000000000000000000000000149704960cccf9d5ea414c73871e896b1d4cf0a946b0db72f5f2c5df98d2ec4f3adbbc14c78047961bc9620cb6cfb5900000000000000000000000000000000140c5d25e534fb1bfdc19ba4cecaabe619f6e0cd3d60b0f17dafd7bcd27b286d4f4477d00c5e1af22ee1a0c67fbf177c00000000000000000000000000000000029a1727041590b8459890de736df15c00d80ab007c3aee692ddcdf75790c9806d198e9f4502bec2f0a623491c3f877d0000000000000000000000000000000008a94c98baa9409151030d4fae2bd4a64c6f11ea3c99b9661fdaed226b9a7c2a7d609be34afda5d18b8911b6e015bf49000000000000000000000000000000000286f09f931c07507ba4aafb7d43befe0b1d25b27ecc9199b19a9dc20bc7ec0329479ef224e00dece67ec0d61f1ca5ae0000000000000000000000000000000014e6ed154b5552be5c463b730b2134f83e0071dcdadfaa68e6c7c7f6e17dabb7daf06e409177bc4b38cfdb8248157618000000000000000000000000000000000f145e998dc6eb0c2b2be87db62949c7bfa63e8b01c8634248010fd623cfaec5d6c6c193331440957d333bf0c988b7b10000000000000000000000000000000002a1ab3eea343cfdea5779f64b3bddbf0769aded60e54a7507338f044310ba239430663394f110e560594d6042a9
(bool ok, bytes memory output) = address(0x0d).call(input);
require(ok, "bls12381 G2 add operation failed");
return output;
}

地址 0x0E:bls12381G2MultiExp(input)

地址 0x0E 实现了 BLS12381 G2 的乘法运算。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381g2mul() public returns (bytes memory) {
bytes memory input =hex"00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3";
(bool ok, bytes memory output) = address(0x0e).call(input);
require(ok, "bls12381 G2 mul 操作失败");
return output;
}
function bls12381g2multiexp() public returns (bytes memory) {
bytes memory input =hex"0000000000000000000000000000000010d48bf523f3909cf90aa58a9517ef5421f1212accd5e8a0f830aeb15a587e215ca9c340bb846b1d0474e43840b2af79000000000000000000000000000000000cc1a3976caf97b9d59f448f6d9f413eef8904f360c0cf912fe942b38d7fcc637a17038973a133608ae769d3e389b18a00000000000000000000000000000000069a6122c6f0ec68834b7617c755a7eb33a80a25acf95859da5ff03316447182f122d20d993b04e79b6fe859b7adf5a8000000000000000000000000000000000058c6f8c297524319bae6722e0a957d1ba0f75ee3a8aaf06148641c67925d15780e419a38ed7e07410e82769da74f2d070e7e2ae2751a1f71962726a31f77553c2da38f4fecda435b6e5459d5e833b400000000000000000000000000000000156ca5e80be8c8c03a5506ce9abd22a9d4958c372678c0caf6f1329898507dfcb1f06a9464cf080bc6881fa5b7df1ebe00000000000000000000000000000000088174d486b4086b931010da298a399e15b60a113e08f571e096d3a4e94b57b3a684711318796eeca9319119b201abb30000000000000000000000000000000000b96ff68505c088cc03a1c2dc363b05bc8544728a12b29569bed137780523123eb17e68f4632383c252d81bca0c5ca9000000000000000000000000000000000486fc6e5224c5fad56234c41856
(bool ok, bytes memory output) = address(0x0e).call(input);
require(ok, "bls12381 G2 multiexp 操作失败");
return output;
}

地址 0x0F: bls12381Pairing(input)

地址 0x0F 实现 BLS12381 配对操作。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381pairing() public returns (bytes memory) {
bytes memory input =hex"0000000000000000000000000000000019c822a4d44ac22f6fbaef356c37ceff93c1d6933e8c8f3b55784cfe62e5705930be48607c3f7a4a2ca146945cad6242000000000000000000000000000000000353d6521a17474856ad69582ce225f27d60f5a8319bea8cefded2c3f6b862d76fe633c77ed8ccdf99d2b10430253fc8000000000000000000000000000000000805892f21889cab3cfe62226eaff6a8d3586d4396692b379efc7e90b0eaad4c9afbdf0f56b30f0c07ae0bc4013343b30000000000000000000000000000000007853f0e75c8dee034c2444299da58c98f22de367a90550dbc635fb52c9a8f61ccc100f70f10208944e48d09507fdce100000000000000000000000000000000064afd6b3ef7ff7ec34f1fa330877b42958a46a7698c6d21adf73bfdfcab7793b312e21e5988652e655f2d42edb8a673000000000000000000000000000000000ea8a2217c3dbcc0f6e562de9cb2f334c896577d0b3a7108d96b1aba2d705dbf531e870d4023cec2c0533455013242330000000000000000000000000000000019c822a4d44ac22f6fbaef356c37ceff93c1d6933e8c8f3b55784cfe62e5705930be48607c3f7a4a2ca146945cad62420000000000000000000000000000000016ad3b981f689f51f46e3e5e166986e4e71655dcc1e928327751ffdcfff8934caec5cc37327b3320202c4efbcfda
(bool ok, bytes memory output) = address(0x0f).call(input);
require(ok, "bls12381 配对操作失败");
return output;
}

地址 0x10: bls12381MapG1(input)

地址 0x10 实现 BLS12381 Map G1 操作。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381mapg1() public returns (bytes memory) {
bytes memory input = hex "0000000000000000000000001443e61dbf14b6c6ed99e1917ecfbe5a4a23ab9bdd3bb089fb76d795d715d9d2e3c7d8db0b7a9434ad691b68bad3b2";
(bool ok, bytes memory output) = address(0x10).call(input);
require(ok, "bls12381 G1 映射操作失败");
return output;
}

地址 0x11: bls12381MapG2(input)

地址 0x11 实现 BLS12381 Map G2 操作。 更多信息,请参阅 EIP-2537。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function bls12381mapg2() public returns (bytes memory) {
bytes memory input =hex"0000000000000000000000000000000010e53fe9fa94ca622cfa370129c1619b2426bd9d50f4b5eb8a3f681479128dbe92adde15477ad8a4463b08f1a02a62d50000000000000000000000000000000014d10a90709789b25369f0376f39b16860aee1ddc3a4340542abff0077a4af8da946cc29fb6afd9930b872ea98749be5";
(bool ok,字节内存输出)= address(0x11)。call(input);
require(ok, "bls12381 G2 映射操作失败");
return output;
}

地址 0x3fd: vmLog(str)

地址 0x3FD 将指定的字符串 str 打印到特定文件或传递给日志记录器模块。 更多信息,请参阅 debug_setVMLogTarget。 请注意,该预编译合约只能用于调试目的,并且需要在 Kaia 节点启动时启用 --vmlog 选项。 此外,Kaia 节点的日志级别应为 4 或更高,以便查看 vmLog 的输出。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function callVmLog(bytes memory str) public {
address(0x3fd).call(str);
}

地址 0x3fe: feePayer()

地址 0x3FE 返回执行交易的付费方。 Solidity 编译器不支持这种预编译合同。 下面的代码可以用来调用这个预编译合同。


function feePayer() internal returns (address addr) {
assembly {
let freemem := mload(0x40)
let start_addr := add(freemem, 12)
if iszero(call(gas, 0x3fe, 0, 0, 0, start_addr, 20)) {
invalid()
}
addr := mload(freemem)
}
}

地址 0x3ff: validateSender()

地址 0x3FF 验证发件人与报文的签名。 由于 Kaia 将密钥对与地址解耦,因此需要验证签名是否由相应的发送方正确签名。 为此,这份预编译合同会收到三个参数:

  • 用于获取公钥的发件人地址
  • 用于生成签名的信息哈希值
  • 由发送者私钥和给定信息哈希值签名的签名

预编译合同验证给定签名是否由发送者的私钥正确签名。 请注意,Kaia 本机支持多签名,这意味着可以有多个签名。 签名长度必须为 65 字节。


function ValidateSender(address sender, bytes32 msgHash, bytes sigs) public returns (bool) {
require(sigs.length % 65 == 0);
bytes memory data = new bytes(20+32+sigs.length);
uint idx = 0;
uint i;
for( i = 0; i < 20; i++) {
data[idx++] = (bytes20)(sender)[i];
}
for( i = 0; i < 32; i++ ) {
data[idx++] = msgHash[i];
}
for( i = 0; i < sigs.length; i++) {
data[idx++] = sigs[i];
}
assembly {
// skip length header.
let ptr := add(data, 0x20)
if iszero(call(gas, 0x3ff, 0, ptr, idx, 31, 1)) {
invalid()
}
return(0, 32)
}
}

硬叉变化

硬叉新项目变化
坎昆 EVMkzg (0x0a) 预编译合同
韩国modExp (0x05) 预编译合同使用新的气体
计算逻辑。 计算成本也受到影响。
更加准确。
伊斯坦布尔 EVMblake2f (0x09) 预编译合同
kaia 预编译合同地址已从 0x09,0x0A,0x0B移动
至 0x3FD,0x3FE,0x3FF。详情请参见下面的 预编译合同地址更改表

预编合同地址变更

预编合同伊斯坦布尔 EVM 硬分叉前**地址地址 伊斯坦布尔 EVM 硬叉子
vmLog0x090x3fd
feePayer0x0a0x3fe
验证发件人0x0b0x3ff
让这个页面变得更好