20

伪代码简述 ECDSA 签名过程 | 联盟链开发(十一)

 4 years ago
source link: https://learnblockchain.cn/article/1038
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

程序员易懂的 ECDSA 原理简述

在《比特币极速入门指南》一书里,我阐述了公私钥究竟是什么:

  • 私钥的本质: 私钥的本质是一个数字,这个数字用 16 进制表示的话,长度是 64;转换为字节,是 32 字节。
  • 公钥的本质: 用私钥生成Secp256k1曲线上的一个点,将 x 与 y 拼接起来,再在开头加上 <<04>> 后得到一个数字,这个数字就是公钥。用 16进制表示的话,长度是 130;转换为字节,是 65 字节。

地址:

阅读版—— http://dwz.date/a8dY

互动版 —— https://xue.cn/hub/app/books/3

由于是「入门指南」,所以没有对 ECDSA 具体的签名过程进行详细阐述,只做黑箱处理。但是,对于进阶读者而言,了解 ECDSA 签名的实现逻辑还是有其必要的。

在一般介绍 ECDSA 原理的文章中,普遍使用数学语言。虽然非常严谨,但读起来还是比较费劲。所以,今天我在这里,通过伪代码的形式,介绍 ECDSA 的原理,以便大家更好的理解。

首先我们定义这件事儿里有几个角色:

  • 私钥小姐与公钥先生

    我们称其为 priv 与 pub。

  • 要加密的信息 m

    在区块链里一般 m = 交易,不过理论上只要是个东西就能加密。

  • G 点

    G.x0x79……98

    G.y0x48……B8

    G.order0xFF……41

    具体的数值我们可以从网上搜到,但在这里我们不用管它,只要知道 G 点有三个参数:x, y, order 就行了!

接着我们定义两个操作:

  • Point.mult(num, Point)

    点的乘法,参数是一个数字与一个 (x, y) 点,结果是一个点。我们可以把这个操作看做黑箱,而不用去深究这个操作究竟做了些啥。

  • calculate_rem(num1, num2)

    取余操作

  • hash_and_sth(m)

    我们对信息 m 做一些处理,具体咋处理的不用管,结果就是我们能拿 m 验证出来出来的内容是否正确,但不能拿处理出来的内容反推 m —— 传说中的 hash 函数。

我们现在来用伪代码愉快地生成数字签名吧!

数字签名生成过程

  1. gen_k()

我们首先用 gen_k() 函数生成一个取值范围为[1, order-1] 的随机数,称之为 k。

  1. Point.mult(k, G)

Point.mult(k, G) = Q_point = (x, y)。

  1. calculate_rem(x, order)

    calculate_rem(x, order) = r,如果 r 为 0,则回到第一步,重新生成 k。

  2. calculate_s(k, hash_and_sth(m), priv)

    calculate_s(k, hash_and_sth(m), priv) = s,如果 s 为 0,再次重新生成 k。

  3. v = 27 + calculate_rem(y, 2)

    有了 v,我们验签就更快了,不然要遍历好几个点去找哪一个点是对的。具体怎么做的可以暂且不理,有兴趣的话看:

    http://www.secg.org/sec1-v2.pdf
    
  4. r & s & v = signature

    把三个东西连起来,得到数字签名!

    和比特币存在差异,比特币在 ECDSA 签名后采用了 DER 编码模式,所以比特币的签名长度是不定的,在71 - 73 个字节之前。但是以太坊则使用的标准 ECDSA 流程,所以签名固定为 r(35字节)+ s(35字节)+v (1字节)=71字节。

    此处 1 字节为 8 个二进制位,即 2 个十六进制位,即 0x00 - 0xFF,用十进制表示则是 0 - 255。

    此外,由于签名中存在随机数 k,所以对同一信息用同一私钥,每次签出来的签名也是不一样的!

把上述过程用伪代码表示,则是:

@spec gen_sig(byte32, string) return byte71
def gen_sig(priv, m) do
	q_point=
   		 gen_k()
    		|> Point.mult(G)
  r = calculate_rem(q_point, G.order)

  s = calculate_s(k, hash_and_sth(m), priv)

  v = 27 + calculate_rem(q_point.y, 2)
  
  return r & s & v
end

数字签名验签过程……嗯,明日再谈吧(懒~

RB3UJfu.jpg!web

在《比特币极速入门指南》一书里,我阐述了公私钥究竟是什么:

  • 私钥的本质: 私钥的本质是一个数字,这个数字用 16 进制表示的话,长度是 64;转换为字节,是 32 字节。
  • 公钥的本质: 用私钥生成Secp256k1曲线上的一个点,将 x 与 y 拼接起来,再在开头加上 <<04>> 后得到一个数字,这个数字就是公钥。用 16进制表示的话,长度是 130;转换为字节,是 65 字节。

地址:

阅读版—— http://dwz.date/a8dY

互动版 —— https://xue.cn/hub/app/books/3

由于是「入门指南」,所以没有对 ECDSA 具体的签名过程进行详细阐述,只做黑箱处理。但是,对于进阶读者而言,了解 ECDSA 签名的实现逻辑还是有其必要的。

在一般介绍 ECDSA 原理的文章中,普遍使用数学语言。虽然非常严谨,但读起来还是比较费劲。所以,今天我在这里,通过伪代码的形式,介绍 ECDSA 的原理,以便大家更好的理解。

首先我们定义这件事儿里有几个角色:

  • 私钥小姐与公钥先生

    我们称其为 priv 与 pub。

  • 要加密的信息 m

    在区块链里一般 m = 交易,不过理论上只要是个东西就能加密。

  • G 点

    G.x0x79……98

    G.y0x48……B8

    G.order0xFF……41

    具体的数值我们可以从网上搜到,但在这里我们不用管它,只要知道 G 点有三个参数:x, y, order 就行了!

接着我们定义两个操作:

  • Point.mult(num, Point)

    点的乘法,参数是一个数字与一个 (x, y) 点,结果是一个点。我们可以把这个操作看做黑箱,而不用去深究这个操作究竟做了些啥。

  • calculate_rem(num1, num2)

    取余操作

  • hash_and_sth(m)

    我们对信息 m 做一些处理,具体咋处理的不用管,结果就是我们能拿 m 验证出来出来的内容是否正确,但不能拿处理出来的内容反推 m —— 传说中的 hash 函数。

我们现在来用伪代码愉快地生成数字签名吧!

数字签名生成过程

  1. gen_k()

我们首先用 gen_k() 函数生成一个取值范围为[1, order-1] 的随机数,称之为 k。

  1. Point.mult(k, G)

Point.mult(k, G) = Q_point = (x, y)。

  1. calculate_rem(x, order)

    calculate_rem(x, order) = r,如果 r 为 0,则回到第一步,重新生成 k。

  2. calculate_s(k, hash_and_sth(m), priv)

    calculate_s(k, hash_and_sth(m), priv) = s,如果 s 为 0,再次重新生成 k。

  3. v = 27 + calculate_rem(y, 2)

    有了 v,我们验签就更快了,不然要遍历好几个点去找哪一个点是对的。具体怎么做的可以暂且不理,有兴趣的话看:

    http://www.secg.org/sec1-v2.pdf

  4. r & s & v = signature

    把三个东西连起来,得到数字签名!

    和比特币存在差异,比特币在 ECDSA 签名后采用了 DER 编码模式,所以比特币的签名长度是不定的,在71 - 73 个字节之前。但是以太坊则使用的标准 ECDSA 流程,所以签名固定为 r(35字节)+ s(35字节)+v (1字节)=71字节。

    此处 1 字节为 8 个二进制位,即 2 个十六进制位,即 0x00 - 0xFF,用十进制表示则是 0 - 255。

    此外,由于签名中存在随机数 k,所以对同一信息用同一私钥,每次签出来的签名也是不一样的!

把上述过程用伪代码表示,则是:

@spec gen_sig(byte32, string) return byte71
def gen_sig(priv, m) do
    q_point=
         gen_k()
            |> Point.mult(G)
  r = calculate_rem(q_point, G.order)

  s = calculate_s(k, hash_and_sth(m), priv)

  v = 27 + calculate_rem(q_point.y, 2)

  return r & s & v
end

数字签名验签过程……嗯,明日再谈吧(懒~

RB3UJfu.jpg!web

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 28分钟前
  • 阅读 ( 9 )
  • 学分 ( 5 )
  • 分类:FISCO BCOS

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK