首页 技术 正文
技术 2022年11月21日
0 收藏 838 点赞 4,327 浏览 6370 个字

问题:内存数据mload时为什么从第32位开始

代码出处:https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d

pragma solidity ^0.4.;
library ECVerify {
// Duplicate Solidity's ecrecover, but catching the CALL return value
function safer_ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal returns (bool, address) {
// We do our own memory management here. Solidity uses memory offset
// 0x40 to store the current end of memory. We write past it (as
// writes are memory extensions), but don't update the offset so
// Solidity will reuse it. The memory used here is only needed for
// this context. // FIXME: inline assembly can't access return values
bool ret;
address addr; assembly {
let size := mload(0x40)
mstore(size, hash)
mstore(add(size, ), v)
mstore(add(size, ), r)
mstore(add(size, ), s) // NOTE: we can reuse the request memory because we deal with
// the return code
ret := call(, , , size, , size, )
addr := mload(size)
} return (ret, addr);
} function ecrecovery(bytes32 hash, bytes sig) public returns (bool, address) {
bytes32 r;
bytes32 s;
uint8 v; if (sig.length != )
return (false, ); // The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
assembly {
r := mload(add(sig, ))//????????????
s := mload(add(sig, )) // Here we are loading the last 32 bytes. We exploit the fact that
// 'mload' will pad with zeroes if we overread.
// There is no 'mload8' to do this, but that would be nicer.
v := byte(, mload(add(sig, ))) // Alternative solution:
// 'byte' is not working due to the Solidity parser, so lets
// use the second best option, 'and'
// v := and(mload(add(sig, 65)), 255)
} // albeit non-transactional signatures are not specified by the YP, one would expect it
// to match the YP range of [27, 28]
//
// geth uses [0, 1] and some clients have followed. This might change, see:
// https://github.com/ethereum/go-ethereum/issues/2053
if (v < )
v += ; if (v != && v != )
return (false, ); return safer_ecrecover(hash, v, r, s);
} function ecverify(bytes32 hash, bytes sig, address signer) public returns (bool,address) {
bool ret;
address addr;
(ret, addr) = ecrecovery(hash, sig);
return (ret == true && addr == signer,addr);
}
}contract ECVerifyTest {
function test_v0() public returns (bool,address) {
bytes32 hash = 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad;
bytes memory sig = "\xac\xa7\xda\x99\x7a\xd1\x77\xf0\x40\x24\x0c\xdc\xcf\x69\x05\xb7\x1a\xb1\x6b\x74\x43\x43\x88\xc3\xa7\x2f\x34\xfd\x25\xd6\x43\x93\x46\xb2\xba\xc2\x74\xff\x29\xb4\x8b\x3e\xa6\xe2\xd0\x4c\x13\x36\xea\xce\xaf\xda\x3c\x53\xab\x48\x3f\xc3\xff\x12\xfa\xc3\xeb\xf2\x00";
return ECVerify.ecverify(hash, sig, 0x0E5cB767Cce09A7F3CA594Df118aa519BE5e2b5A);
} function test_v1() public returns (bool,address) {
bytes32 hash = 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad;
bytes memory sig = "\xde\xba\xaa\x0c\xdd\xb3\x21\xb2\xdc\xaa\xf8\x46\xd3\x96\x05\xde\x7b\x97\xe7\x7b\xa6\x10\x65\x87\x85\x5b\x91\x06\xcb\x10\x42\x15\x61\xa2\x2d\x94\xfa\x8b\x8a\x68\x7f\xf9\xc9\x11\xc8\x44\xd1\xc0\x16\xd1\xa6\x85\xa9\x16\x68\x58\xf9\xc7\xc1\xbc\x85\x12\x8a\xca\x01";
return ECVerify.ecverify(hash, sig, 0x8743523D96A1B2CbE0c6909653a56da18ed484Af);
}
}

每当使用出现了使用到汇编语言时,我就一直很奇怪一个问题,就是r := mload(add(sig, 32))这里为什么要加32,后面通过测试发现,前32个字节存储的是数据的长度

测试过程:

1)先得到原代码取得的(v, r, s) :

pragma solidity ^0.4.;
library ECVerify {
function ecrecovery(bytes32 hash, bytes sig) public returns (uint8, bytes32, bytes32) {
bytes32 r;
bytes32 s;
uint8 v; if (sig.length != )
return (v, r, s); // The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
assembly {
r := mload(add(sig, ))
s := mload(add(sig, )) // Here we are loading the last 32 bytes. We exploit the fact that
// 'mload' will pad with zeroes if we overread.
// There is no 'mload8' to do this, but that would be nicer.
v := byte(, mload(add(sig, ))) // Alternative solution:
// 'byte' is not working due to the Solidity parser, so lets
// use the second best option, 'and'
// v := and(mload(add(sig, 65)), 255)
} // albeit non-transactional signatures are not specified by the YP, one would expect it
// to match the YP range of [27, 28]
//
// geth uses [0, 1] and some clients have followed. This might change, see:
// https://github.com/ethereum/go-ethereum/issues/2053
if (v < )
v += ; if (v != && v != )
return (v, r, s); return (v, r, s);
}}contract ECVerifyTest {
function test_v0() public returns (uint8,bytes32, bytes32) {
bytes32 hash = 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad;
bytes memory sig = "\xac\xa7\xda\x99\x7a\xd1\x77\xf0\x40\x24\x0c\xdc\xcf\x69\x05\xb7\x1a\xb1\x6b\x74\x43\x43\x88\xc3\xa7\x2f\x34\xfd\x25\xd6\x43\x93\x46\xb2\xba\xc2\x74\xff\x29\xb4\x8b\x3e\xa6\xe2\xd0\x4c\x13\x36\xea\xce\xaf\xda\x3c\x53\xab\x48\x3f\xc3\xff\x12\xfa\xc3\xeb\xf2\x00";
return ECVerify.ecrecovery(hash, sig);
} function test_v1() public returns(uint8,bytes32, bytes32) {
bytes32 hash = 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad;
bytes memory sig = "\xde\xba\xaa\x0c\xdd\xb3\x21\xb2\xdc\xaa\xf8\x46\xd3\x96\x05\xde\x7b\x97\xe7\x7b\xa6\x10\x65\x87\x85\x5b\x91\x06\xcb\x10\x42\x15\x61\xa2\x2d\x94\xfa\x8b\x8a\x68\x7f\xf9\xc9\x11\xc8\x44\xd1\xc0\x16\xd1\xa6\x85\xa9\x16\x68\x58\xf9\xc7\xc1\xbc\x85\x12\x8a\xca\x01";
return ECVerify.ecrecovery(hash, sig);
}
}

返回:

solidity 汇编语言问题——内存数据mload时为什么从第32位开始

solidity 汇编语言问题——内存数据mload时为什么从第32位开始

2)然后调用0位置的数据:

pragma solidity ^0.4.;
library ECVerify { function ecrecovery(bytes32 hash, bytes sig) public returns (uint8, bytes32, bytes32) {
bytes32 r;
bytes32 s;
uint8 v; if (sig.length != )
return (v, r, s); // The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
assembly {
r := mload(add(sig, ))
s := mload(add(sig, )) // Here we are loading the last 32 bytes. We exploit the fact that
// 'mload' will pad with zeroes if we overread.
// There is no 'mload8' to do this, but that would be nicer.
v := byte(, mload(add(sig, ))) // Alternative solution:
// 'byte' is not working due to the Solidity parser, so lets
// use the second best option, 'and'
// v := and(mload(add(sig, 65)), 255)
} return (v, r, s);
}}contract ECVerifyTest {
function test_v0() public returns (uint8,bytes32, bytes32) {
bytes32 hash = 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad;
bytes memory sig = "\xac\xa7\xda\x99\x7a\xd1\x77\xf0\x40\x24\x0c\xdc\xcf\x69\x05\xb7\x1a\xb1\x6b\x74\x43\x43\x88\xc3\xa7\x2f\x34\xfd\x25\xd6\x43\x93\x46\xb2\xba\xc2\x74\xff\x29\xb4\x8b\x3e\xa6\xe2\xd0\x4c\x13\x36\xea\xce\xaf\xda\x3c\x53\xab\x48\x3f\xc3\xff\x12\xfa\xc3\xeb\xf2\x00";
return ECVerify.ecrecovery(hash, sig);
} function test_v1() public returns(uint8,bytes32, bytes32) {
bytes32 hash = 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad;
bytes memory sig = "\xde\xba\xaa\x0c\xdd\xb3\x21\xb2\xdc\xaa\xf8\x46\xd3\x96\x05\xde\x7b\x97\xe7\x7b\xa6\x10\x65\x87\x85\x5b\x91\x06\xcb\x10\x42\x15\x61\xa2\x2d\x94\xfa\x8b\x8a\x68\x7f\xf9\xc9\x11\xc8\x44\xd1\xc0\x16\xd1\xa6\x85\xa9\x16\x68\x58\xf9\xc7\xc1\xbc\x85\x12\x8a\xca\x01";
return ECVerify.ecrecovery(hash, sig);
}
}

返回结果:

solidity 汇编语言问题——内存数据mload时为什么从第32位开始

0x41 = 65,所以能够得出结论,前32字节存储的是参数的长度

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,104
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,581
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,428
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,835
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,918