密码学相关函数
密码学相关的函数在crypto.codon
中定义,可以通过像下面的方式导入:
from chain.crypto import sha256
或者只导入crypto模块:
from chain import crypto
然后通过像crypto.sha256
的方式来调用内部函数。
sha256
sha256算法hash函数
def sha256(data: bytes) -> Checksum256:
用于检测hash256值是否正常,不正确会直接抛出异常
def assert_sha256(data: bytes, hash: Checksum256):
sha1
sha1算法hash函数
def sha1(data: bytes) -> Checksum160:
用于检测sha1 hash值是否正常,不正确会直接抛出异常
def assert_sha1(data: bytes, hash: Checksum160):
sha512
sha512算法hash函数
def sha512(data: bytes) -> Checksum512:
用于检测hash512值是否正常,不正确会直接抛出异常
def assert_sha512(data: bytes, hash: Checksum512):
ripemd160
ripemd160算法hash函数
def ripemd160(data: bytes) -> Checksum160:
用于检测ripemd160算法的hash值是否正常,不正确会直接抛出异常
def assert_ripemd160(data: bytes, hash: Checksum160):
recover_key
用于从digest和signture中恢复出公钥
def recover_key(digest: Checksum256, sig: Signature) -> PublicKey:
检查签名是否正常,不正常会抛出异常
def assert_recover_key(digest: Checksum256, sig: Signature, pub: PublicKey):
示例:
# crypto_example.codon
from chain.contract import Contract
from chain.crypto import sha256, assert_sha256, sha512, assert_sha512, sha1, assert_sha1, ripemd160, assert_ripemd160
from chain.crypto import recover_key, assert_recover_key
from chain.crypto import Signature, Checksum256, PublicKey
@contract(main=True)
class MyContract(Contract):
def __init__(self):
super().__init__()
@action('testcrypto')
def test_crypto(self):
assert_sha256(b"hello", sha256(b"hello"))
assert_sha1(b"hello", sha1(b"hello"))
assert_sha512(b"hello", sha512(b"hello"))
assert_ripemd160(b"hello", ripemd160(b"hello"))
@action('testrecover')
def test_recover(self, msg: bytes, digest: Checksum256, sig: Signature, k1: PublicKey):
_digest = sha256(msg)
assert _digest == digest
_pubkey = recover_key(digest, sig)
assert _pubkey == k1, "_pubkey == k1"
assert_recover_key(digest, sig, k1)
print('done!')
测试代码:
def test_crypto():
t = init_test('crypto_example')
args = {}
ret = t.push_action('hello', 'testcrypto', args, {'hello': 'active'})
t.produce_block()
logger.info("++++++++++%s\n", ret['elapsed'])
def test_recover():
t = init_test('crypto_example')
msg = b'hello,world'
# key pair
public_key = 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV'
private_key = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3'
h = hashlib.sha256()
h.update(msg)
digest = h.hexdigest()
logger.info('++++digest: %s', digest)
#sign with private key
sig = eosapi.sign_digest(digest, private_key)
logger.info('++++signature: %s', sig)
args = {
"msg": msg.hex(),
"digest": digest,
"sig": sig,
"k1": public_key,
}
ret = t.push_action('hello', 'testrecover', args, {'hello': 'active'})
t.produce_block()
logger.info("++++++++++%s\n", ret['elapsed'])
编译:
python-contract build crypto_example.codon
测试:
ipyeos -m pytest -s -x test.py -k test_crypto
ipyeos -m pytest -s -x test.py -k test_recover
在这个示例代码中,分别演示了常用的hash函数的用法以及recover_key
和assert_recover_key
的用法。hash函数的用法比较简单,这里解释一下recover_key的测试代码:
recover_key接受二个参数,分别是digest
和signature
,digest是对一个二进制数据进行sha256运行的结果。在上面的代码中是通过对hello,world
进行sha256算法的hash计算。
h = hashlib.sha256()
h.update(b'hello,world')
digest = h.hexdigest()
运算出的结果作为参数传给action.
下面是对testrecover
的解释:
@action('testrecover')
def test_recover(self, msg: bytes, digest: Checksum256, sig: Signature, k1: PublicKey):
_digest = sha256(msg)
assert _digest == digest #判断digest是否对msg进行hash256算法的hash结果
_pubkey = recover_key(digest, sig)
assert _pubkey == k1, "_pubkey == k1" #判断public key是否正确
assert_recover_key(digest, sig, k1) #作用相当于上面两行代码
print('done!')
在发送的Transaction中也是需要包含用户对Transaction的签名的,以表示用户授权了这个Transaction。然后在智能合约,就可以调用的require_auth
函数来判断Transaction是否进行过特定用户的授权。
在实际的智能合约的应用中,如果要在智能合约里判断某段二进制数据是否是用特定的私钥进行的签名也可以用上面的办法。过程如下:
- 首先用户用自己的私钥对数据进行签名
- 合约中保存用户的公钥
- 用户将数据,以及对应的签名传给智能合约
- 智能合约可以调用
RecoverKey
从用户数据,以及对数据的签名中还原出公钥 - 智能合约读取保存在链上的用户公钥,与通过调用
RecoverKey
还原出的公钥进行比较,相同即可以确定数据是对应的用户签的名