vlambda博客
学习文章列表

区块链如何应用非对称加密

前两篇讲了对称加密、非对称加密,进一步地,对非对称加密的两个典型应用:数字签名、数字证书进行了介绍。


那么,区块链是如何应用非对称加密技术的呢?


在百度搜索这个问题,除了广告,大多都是解释非对称加密原理的文章,暂时没有发现讲解区块链是如何使用非对称加密技术的。

知乎搜了一下,找到一个该问题的提问,但目前还没有回答。

好吧,我也似懂非懂,模棱两可,这个问题该怎么解决呢?


看源代码!


于是,我找了一个区块链的项目,找到了非对称加密这部分的代码,接下来,结合代码,讲解一下区块链是如何应用非对称加密的。



以 Python 代码为例,我们先看主要函数。

def client ( a, m, f, t, p ):
if a:
if a == "n":
public_key, private_key = generate_ECDSA_keys()
click.echo("")
click.echo("address:{0}".format(public_key))
click.echo("")
click.echo("private_key:{0}".format(private_key))
click.echo("")
print("ok!")
if a == "s":
if ( m and f and t and p ):
print(send_transaction(f, t, m, p))

这一部分是生成一个公钥和私钥。公钥和私钥是非对称加密中的一对密钥,但公钥是公开的,私钥是私自持有的。经公钥加密后的密文,可以通过私钥解开。


公钥是全范围广播发布的。打个比方,公钥类似于银行卡号,私钥就类似于银行卡密码。



我们先看公钥和私钥的生成函数。

def generate_ECDSA_keys():
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
private_key = sk.to_string().hex()
vk = sk.get_verifying_key()
public_key = vk.to_string().hex()
public_key = base64.b64encode(bytes.fromhex(public_key))
return public_key.decode(),private_key


可以看出,sk 是一个签名,私钥 pricate_key 是通过签名转化而来。

其中,这句代码表示公钥是由私钥得出的。

vk = sk.get_verifying_key()


是怎么得出的呢?我们看看 get_verifying_key 函数。

def get_verifying_key(self):
"""
Return the VerifyingKey associated with this private key.
Equivalent to reading the `verifying_key` field of an instance.
:return: a public key that can be used to verify the signatures made
with this SigningKey
:rtype: VerifyingKey
"""


可以看出,这个函数的返回值是指:

A public key that can be used to verify the signatures made with this SigningKey

一个可验证使用此签名密钥生成签名的公钥。


因此,应该能够明白私钥和公钥的产生原理了吧。


generate_ECDSA_keys 函数输出的内容类似如下:

address:Z/qsNWOAAWULpqvtM/OMHmJE+6PG0oPUsOMGk2ySYgrUB5noaZsD6b0NbbPgslr1cdninkqYKcJ+sx74/Mhn2A==
private_key:196f72bf05e307458a0691ca73a2981d859e499ef9fc264183feddde5bd47217


接下来,需要启节点,查看区块链的信息。

if __name__ == '__main__':
make_a_genesis_block()
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=8080, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port
app.run(debug=True, host='0.0.0.0', port=port)


@click.option('-f', help='from address')
@click.option('-t', help='to address')
@click.option('-p', help='private_key')


然后,我们具体看看如何上链的。

if a == "s":
if ( m and f and t and p ):
print(send_transaction(f, t, m, p))


可以看出,send_transcation 函数是对消息进行上链的函数,即发送交易信息函数,接下来我们进入这个函数。

def send_transaction(from_address, to_address, memo, private_key, private_key_own):
if private_key == private_key_own:
        signature, message = sign_ECDSA_msg(private_key)
url = "http://localhost:8080/post"
d = {"from_address": from_address, "to_address": to_address,"memo":memo,
"signature":signature,"message":message}
r = requests.post(url, data=d)
return r.text
else:
return ("Wrong address or key length! Verify and try again.")


大体分析一下这个函数的设计思想。

    if private_key == private_key_own:

这里就是验证接收到的私钥与所持有的私钥是否吻合的环节。如果不吻合,直接跳到 else,无法进行上链操作。


如果吻合,则 sign_ECDSA_msg 函数执行。


当私钥 private_key 解开加密信息后,会产生 signature 和 message,即签名与信息。那么私钥解密的函数,就是 sign_ECDSA_msg 这个函数。进一步地,我们进入这个函数,看看私钥是如何解密的。

def sign_ECDSA_msg(private_key):
message = str(round(time()))
bmessage = message.encode()
sk = ecdsa.SigningKey.from_string(bytes.fromhex(private_key),
curve=ecdsa.SECP256k1)
signature = base64.b64encode(sk.sign(bmessage))
return signature, message


我们看到,message 是得到一个时间序列。这里边的核心函数是 from_string 函数,这是引入的第三方库里的函数,我们看一下这个函数的解释。

def from_string(cls, string, curve=NIST192p, hashfunc=sha1):
"""
Decode the private key from :term:`raw encoding`.
Note: the name of this method is a misnomer coming from days of
Python 2, when binary strings and character strings shared a type.
In Python 3, the expected type is `bytes`.
:param string: the raw encoding of the private key
:type string: bytes like object
:param curve: The curve on which the point needs to reside
:type curve: ecdsa.curves.Curve
:param hashfunc: The default hash function that will be used for
signing, needs to implement the same interface
as hashlib.sha1
:type hashfunc: callable
:raises MalformedPointError: if the length of encoding doesn't match
the provided curve or the encoded values is too large
:raises RuntimeError: if the generation of public key from private
key failed
:return: Initialised SigningKey object
:rtype: SigningKey
"""


可以看出,输入的是密钥,输出的是一个签名,具体是什么签名,这里不用深入研究,因为这个输出还会输入到下一个函数 b64encode 函数。进一步地,我们看看这个函数的作用。

def b64encode(s, altchars=None):
"""Encode the bytes-like object s using Base64 and return a bytes object.
Optional altchars should be a byte string of length 2 which specifies an
alternative alphabet for the '+' and '/' characters. This allows an
application to e.g. generate url or filesystem safe Base64 strings.
"""


可以看出,这是一个对字节编码的函数。也就是说,通过 sign_ECDSA_msg 函数得到了存储信息和签名。


然后,在 send_transcation 中,对 sign_ECDSA_msg 函数得到的信息进行上链,节点是 8080。


就这样,区块链中的公钥、私钥以及非对称加密技术的工作机制,就能理清了。


当然,这个代码比较简单,介绍的最基础的区块链原理,大家在学习的过程中也可以循序渐进,了解更复杂的区块链技术。