在ethereumjs-util和solidity中,ecrecover方法是前提,除非这些工作分别在客户端和区块链中。 在以太坊论坛上,chriseth给出了ecrecover的以下有用解释: ecrecover的思想是,可以计算对应于用于创建ECDSA签名的私钥的公钥,这两个额外的字节通常是由签名提供的。 注意:Solidity的ecrecover返回一个地址,而ethereumjs-utils的ecrecover返回一个公钥。 注:研究期间,我发现了一些有趣的StackExchange的问题主题。 在大量的资料查询研究和大量的开发调试之后,我成功地实现了PHP中的ecrecover功能。 虽然我知道如何做到这一点,我写了一些“笔记”,我整理和包含在下面的内容,希望能帮助别人了解正确的方向。 然后,我会模仿PHP中的ecrecover方法的代码路径,然后像宏播放一样执行,直到从签名返回的输出公共密钥与原始签名帐户匹配。 所以… 在Node中,缓存 Buffers 是无符号8位整数的数组。
正如我们所说的,服务器端,我们将使用两种不同的方式从签名中恢复公钥:在一个中我们将使用JSON RPC 接口中的web3.personal.ecrecover(web3.personal.sign对应) ;在另一个中,我们将使用底层的ecrecover离线功能。 根据文档,web3.personal.sign使用底层签名函数来签署hash和前缀消息,因此,为了使用底层ecrecover对应,我们还需要计算并将此hash发送到令牌端点。 MessageSigner.EcRecover是Nethereum提供的离线功能。 缺点: 你需要处理web3.personal.sign实现才能正确恢复帐户。 也许Infura某天决定允许web3.personal.ecrecover :-)
= 0 { miner, err := ecrecover(chain.CurrentHeader(), c.signatures) if err ! 奖励 state.AddBalance(miner, uint256.NewInt(chain.Config().Clique.Reward*1e18)) }}在这段代码中,我们通过ecrecover 对于验证者节点,需要手动指定miner地址,但如果新节点的配置与现有节点不同,ecrecover函数返回的矿工地址也会不同,造成同步失败。 修改Finalize方法获取奖励地址接下来,我们需要修改Finalize方法,使其从创世区块的配置中动态获取出块奖励地址,而不是依赖etherbase或ecrecover。
未作0地址判断 简单介绍 keccak256()和 ecrecover()都是内嵌的函数,keccak256()可以用于计算公钥的签名,ecrecover()可以用来恢复签名公钥,传值正确的情况下,可以利用这两个函数来验证地址 : //ecrecover接口,利用椭圆曲线签名恢复与公钥相关的地址,错误返回零。 = ecrecover(hash,_v,_r,_s)) revert(); 当ecrecover传入错误参数(例如_v = 29,),函数返回0地址,如果合约函数传入的校验地址也为零地址,那么将通过断言 = ecrecover(h,_v,_r,_s)) revert(); ... = ecrecover(h,_v,_r,_s)) revert(); ...
服务器端调用对应的JSON RPC以从签名中检索帐户:web3.personal.ecrecover。 3.签名将发送到API层,该层通过JSON RPC的web3.personal.ecrecover验证帐户。 4.验证后,API层将发布JWT。 authenticate the user recovering the Ethereum address from signature using the Geth RPC web3.personal.ecrecover This method will authenticate the user recovering his Ethereum address through underlaying offline ecrecover name public string Email { get; set; } // The user Email } Authenticate方法将Signature和Message属性作为ecRecover
文章前言 以太坊合约中的加密签名实现通常假定签名是唯一的,但是可以在不具备私钥的情况下实现对签名的更改,并且签名仍然有效,在EVM规范定义了几个"预编译"合约,其中一个合约ecrecover主要用于执行椭圆曲线公钥恢复 = 28) return address(0); return ecrecover(hash, v, r, s); } } 防御措施 在检查消息是否之前已由合约处理时,在消息哈希中不应包含签名 = 28) return address(0); return ecrecover(hash, v, r, s); } } 修改前后的代码差异对比如下: ?
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address): 通过椭圆曲线签名来恢复与公钥关联的地址,或者在错误时返回零 ecrecover函数需要四个参数,需要被签名数据的哈希结果值,r,s,v分别来自签名结果串。 )和keccak256(0x12345678) == keccak256(uint32(0x12345678)) 在私链(private blockchain)上运行sha256,ripemd160或ecrecover
可以跳转到下面ecrecover函数的源码分析。 if err ! = 0 { return errInvalidDifficulty } return nil } ecrecover函数的源码分析: // ecrecover函数从一个签名的区块头中解压出以太坊账户地址 pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature)// 具体源码见下方 if err ! sigcache.Add(hash, signer)//加入缓存 return signer, nil } crypto包的Ecrecover函数: func Ecrecover(hash, sig []byte) ([]byte, error) { return secp256k1.RecoverPubkey(hash, sig) } Ecrecover函数是使用secp256k1来解密公钥
common.Bytes2Hex(sig)) // recover the public key from the signature pub, err := crypto.Ecrecover 41c4a2eb073e6df89c3f467b3516e9c313590d8d57f7c217fe7e72a7b4a6b8ed5f20a758396a5e681ce1ab4cec749f8560e28c9eb91072ec7a8acc002a11bb1d00•②,调用加密包中的Ecrecover
r = signature[0:64] s = signature[64:128] v = signature[128:130] 需要注意的是,如果你使用ecrecover,这里的v值是00或01,所以如果你想使用他们
总结这个块,它所做的是,由于我们的msg(包含nonce)和我们signature的ecrecover函数输出用于签名的公共地址msg。 We // can perform an elliptic curve signature verification with ecrecover const msgBuffer = ethUtil.toBuffer signature); const signatureParams = ethUtil.fromRpcSig(signatureBuffer); const publicKey = ethUtil.ecrecover ethUtil.bufferToHex(addressBuffer); // The signature verification is successful if the address found with // ecrecover
你的合约需要能够做同样的事情,以便用ecrecover来确定是哪个地址签名的,你需要在 Solidity 合约代码中复制这个格式化/哈希函数。这可能是最棘手的一步,所以要非常小心。 address signer, Bid memory bid, sigR, sigS, sigV) public pure returns (bool) { return signer == ecrecover 如果你将它复制粘贴到 Remix IDE[12],选择 JavaScript VM 环境,然后运行verify功能,Remix 将在代码中运行ecrecover获取签名者的地址,将结果与钱包地址比较,如果匹配则返回
isVerifiedCoupon(bytes32 digest, Coupon memory coupon) internal view returns (bool) { address signer = ecrecover 我们使用 solidity 的内置 ecrecover 函数通过以下方式获取此公钥(signer)将摘要(即优惠券类型和调用者地址的 32 字节哈希值)与优惠券本身一起传递。 如果你有兴趣深入了解,这篇 (3)[7] 文章非常有助于解释 ecrecover 如何在后台工作的复杂性。 nft-merkle-drop/slides/20210506%20-%20Lazy%20minting%20workshop.pdf (3) https://soliditydeveloper.com/ecrecover nft-merkle-drop/slides/20210506%20-%20Lazy%20minting%20workshop.pdf [7] (3): https://soliditydeveloper.com/ecrecover
= 0 {miner, err := ecrecover(chain.CurrentHeader(), c.signatures)if err ! "err", err)return}// 奖励state.AddBalance(miner, uint256.NewInt(chain.Config().Clique.Reward*1e18))}}ecrecover
内建(built-in)函数 keccak256,sha256,ripemd160,ecrecover,addmod 和 mulmod 是允许的(即使他们确实会调用外部合约)。
所以在r,s之前插入v即可,之后验证公钥的有效性,,之后返回地址: // filedir:go-ethereum-1.10.2\core\vm\contracts.go L167 func (c *ecrecover common.RightPadBytes(input, ecRecoverInputLength) // "input" is (hash, v, r, s), each 32 bytes // but for ecrecover input[64:128]) sig[64] = v // v needs to be at the end for libsecp256k1 pubKey, err := crypto.Ecrecover PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover
errRecentlySigned = errors.New("recently signed") ) 地址提取 ecrecover函数用于从签名头中提取以太坊账户地址信息: // ecrecover extracts the Ethereum account address from a signed header. func ecrecover(header *types.Header, sigcache , signatures: signatures, proposals: make(map[common.Address]bool), } } 矿工地址 Author函数通过调用ecrecover fine tune behavior sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover { return err } // Resolve the authorization key and check against signers signer, err := ecrecover
PERMIT_TYPEHASH, holder, spender, nonce, expiry, allowed )) )); 使用ecrecover 如何对不上,就拒绝这个签名: require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit"); 这个地方需要注意。
总结这部分的作用,对于给出的msg(包含nonce)和signature信息,ecrecover函数输出用于签名msg的钱包地址。 We // can perform an elliptic curve signature verification with ecrecover const msgBuffer = ethUtil.toBuffer signature); const signatureParams = ethUtil.fromRpcSig(signatureBuffer); const publicKey = ethUtil.ecrecover ethUtil.bufferToHex(addressBuffer); // The signature verification is successful if the address found with // ecrecover
signature) { var split = ethereumjs.Util.fromRpcSig(signature); var publicKey = ethereumjs.Util.ecrecover v; bytes32 r; bytes32 s; (v, r, s) = splitSignature(sig); return ecrecover