草庐IT

Solidity--如何实现椭圆算法签名(ECDSA)

Zeke Luo 2023-08-06 原文

椭圆算法签名

椭圆曲线算法签名(ECDSA)是一种数字签名算法,其基于椭圆曲线密码学(ECC)。它是一种非对称密码算法,即发送方和接收方都有不同的密钥。在数字签名中,发送方使用它的私钥对数据进行签名,以证明数据的完整性和发送方身份。接收方可以使用发送方的公钥验证签名,以确认数据没有被篡改。

ECDSA在许多方面都优于其他数字签名算法,例如RSA,因为它更加安全且计算效率更高。然而,它也有一些缺点,例如密钥长度必须比RSA大得多,以达到相同的安全级别。因此,选择使用ECDSA或其他签名算法取决于特定的使用情况和安全要求

场景

我目前举个项目中的例子

项目介绍:

L1如何保证链下提交的数据是真实有效性,并且防止被途中篡改?

解决办法:

使用椭圆算法签名,链上验证提交的数据是否真实并且是否是节点提交的.

主要的机制:

用于证明数字信息或文件真实性的数学方案。有效的数字签名使收件人有理由相信该信息是由已知的发件人(认证)创建的,发件人不能否认已发送的信息(不可否认),并且信息在传输过程中未被更改(完整性)

如何工作

数字签名是一种数学签名,由两部分组成。第一部分是使用私钥(签名密钥)从消息(交易)中 创建签名的算法。第二部分是允许任何人仅使用消息和公钥来验证签名的算法

第一步创建数字签名:

在以太坊实现的ECDSA中,被签名的“消息”是交易,或者更确切地说,来自交易的RLP编码数据的Keccak256哈希。签名密钥是EOA的私钥。结果是签名:

\(\(Sig = F_{sig}(F_{keccak256}(m), k)\)\)

其中:

  • _k_是签名私钥

  • _m_是RLP编码的交易

  • F**keccak256 是Keccak256哈希函数

  • F**sig 是签名算法

  • Sig 是由此产生的签名

函数 F**sig

产生一个由两个值组成的签名+Sig+,通常称为+R+和+S+:Sig = (R, S)

第二步验证签名:

要验证签名,必须有签名(R+和+S),序列化交易和公钥(与用于创建签名的私钥对应)。实质上,对签名的验证意味着“只有生成此公钥的私钥的所有者才能在此交易上产生此签名

签名验证算法采用消息(交易的散列或其部分),签名者的公钥和签名(+R+和+S+值),如果签名对此消息和公钥有效,则返回TRUE。

三种用途

  • 签名证明私钥的所有者,暗示着以太坊账户的所有者,已经授权支付ether或执行合约

  • 授权的证明是_undeniable_(不可否认)

  • 签名证明交易数据在交易签名后没有也不能被任何人修改

实现

  • 签名(前端)

	let prefix = "\\x19Ethereum Signed Message:\\n32";    
	let messageHash = ethers.utils.solidityKeccak256(
      ["string", "address", "uint32", "address", "uint32", "bool"],
      ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
        "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
        100000,
        "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
        1,
        false
      ]
    );

   let msg = ethers.utils.keccak256(
      ethers.utils.solidityPack(
        ["string", "bytes32"],
        [prefix, messageHash]
      )
    );

    let signingKey = new ethers.utils.SigningKey("0x");
    let signature = await signingKey.signDigest(msg);
    let { v, r, s } = signature;
     
    //verifyEcrecover(bytes32  messageHash, uint8 v, bytes32 r, bytes32 s)
    let MeshData = await lock.verifyEcrecover(messageHash, v, r, s);
 }
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

代码详分:

  1. 首先,通过 ethers.utils.solidityKeccak256 函数生成了一个消息哈希,该哈希是使用 Solidity 中的 keccak256 哈希函数生成的。

  1. 然后,生成了一个前缀字符串 "\\x19Ethereum Signed Message:\\n32",该字符串是用于标识该消息哈希是通过 Ethereum 数字签名算法签名的。

  1. 使用 ethers.utils.keccak256 函数对前缀字符串和消息哈希进行组合,生成一个最终的消息。

  1. 使用 ethers.utils.SigningKey 生成一个签名密钥,并使用该签名密钥签名最终的消息,生成签名(即 signature)。

  1. 最后,使用 lock.verifyEcrecover 函数验证签名是否有效,如果有效,则返回一个可信的数据(即 MeshData)。

总的来说,该代码的目的是生成并验证一个数字签名,以保证消息的完整性和不可更改性

  • 验签(合约)

**function hashMessage(bytes memory message) public view returns (bytes32 messageHash) {
    messageHash = keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\\n32", message));
    return messageHash;
}

function verifyEcrecover(bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public view returns (address recoveredAddress) {
    return  ecrecover(messageHash, v, r, s);
}**

代码详分:

这段代码执行了两个 Solidity 函数:hashMessageverifyEcrecover

  1. hashMessage 函数接收一个字节数组作为参数,并返回一个经过哈希处理后的字节数组的哈希值。该函数使用 keccak256 哈希函数对消息进行哈希处理,并使用 abi.encodePacked 函数将前缀 "\\x19Ethereum Signed Message:\\n32" 和消息一起打包。

  1. verifyEcrecover 函数接收四个参数:消息哈希,V 值,R 值和 S 值。该函数使用 ecrecover 函数从数字签名中恢复地址,并返回恢复的地址。

总的来说,该代码的目的是使用 Ethereum 椭圆曲线数字签名算法(ECDSA)验证数字签名的有效性

为什么要加 ” \x19Ethereum Signed Message:\n3”

这段字符串是在 Ethereum 中使用的椭圆算法签名的前缀,其目的是为了防止签名消息的修改。

在 Ethereum 中,使用的椭圆算法(ECDSA)是不安全的,因为签名消息可以被篡改。为了防止消息被修改,引入了这个前缀。前缀的作用是在签名之前,将原始消息加上前缀,这样在验证签名时,需要将原始消息加上前缀再验证,从而防止消息被篡改。

因此,椭圆算法签名验证中加上 "\x19Ethereum Signed Message:\n3" 这个前缀的目的是为了防止签名消息的修改,保证签名的安全性

扩展:

Hash

Hash 是一种数字摘要算法,用于将任意长度的数据映射为固定长度的数字。这个映射的结果称为散列值或哈希值。

Hash 算法的特点:

  1. 唯一性:对于不同的输入数据,hash 算法生成的散列值是不同的。

  1. 抗修改性:一个小的变更会导致散列值的大幅改变。

  1. 不可逆性:通过散列值不能推出原始数据

Hash种类

哈希算法有很多种,其中包括:

  • MD5 (Message-Digest Algorithm 5)

  • SHA-1 (Secure Hash Algorithm 1)

  • SHA-224

  • SHA-256

  • SHA-384

  • SHA-512

  • SHA-3

  • BLAKE2

  • HMAC (Hash-based Message Authentication Code)

  • RIPEMD (RACE Integrity Primitives Evaluation Message Digest)

  • Tiger

这些算法的安全性和效率各不相同,有的已经被攻破,不再被推荐使用,因此选择哈希算法时,需要考虑多方面的因素,包括安全性、效率、支持性等。

用途

为了隐藏起某些信息,且保证这些信息不被篡改,需要用到哈希算法。keccak256算法则可以将任意长度的输入压缩成64位16进制的数,且哈希碰撞的概率近乎为0

如果有遇到不懂得或者有疑问欢迎联系本人进行交流

WC:luo425116243

有关Solidity--如何实现椭圆算法签名(ECDSA)的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  8. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  9. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  10. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

随机推荐