Skip to content

Functions Related to Cryptography

The cryptographic related functions are defined in the crypto.ts in the asm-chain package, which can be imported as follows:

import {
    ripemd160,
    sha1,
    sha256,
    sha512,

    assertRipemd160,
    assertSha1,
    assertSha256,
    assertSha512,

    Signature,
    PublicKey,

    recoverKey,
    assertRecoverKey,
} from "asm-chain";

sha256

sha256 hash function

function sha256(data: u8[]): Checksum256

Used to check if the hash256 value is normal, if incorrect, it will throw an exception directly

function assertSha256(data: u8[], hash: Checksum256): void

sha1

sha1 hash function

function sha1(data: u8[]): Checksum160

Used to check if the sha1 hash value is normal, if incorrect, it will throw an exception directly

function assertSha1(data: u8[], hash: Checksum160): void

sha512

sha512 hash function

function sha512(data: u8[]): Checksum512

Used to check if the hash512 value is normal, if incorrect, it will throw an exception directly

function assertSha512(data: u8[], hash: Checksum512): void

ripemd160

ripemd160 hash function

function ripemd160(data: u8[]): Checksum160

Used to check if the hash value of ripemd160 is normal, if incorrect, it will throw an exception directly

function assertRipemd160(data: u8[], hash: Checksum160): void

recoverKey

Used to recover the public key from digest and signature

function recoverKey(digest: Checksum256, sig: Signature): PublicKey

Check if the signature is normal, if abnormal, it will throw an exception

function assertRecoverKey(digest: Checksum256, sig: Signature, pub: PublicKey): void

Example:

Complete Example Code

import {
    Name,
    Contract,

    ripemd160,
    sha1,
    sha256,
    sha512,

    assertRipemd160,
    assertSha1,
    assertSha256,
    assertSha512,

    Signature,
    PublicKey,
    recoverKey,
    assertRecoverKey,

    print,
    check,
} from "asm-chain";

@contract
class MyContract extends Contract {
    constructor(receiver: Name, firstReceiver: Name, action: Name) {
        super(receiver, firstReceiver, action);
    }

    @action("testhash")
    testhash(data: u8[]): void {
        print(`+++++++${data}\n`)
        assertRipemd160(data, ripemd160(data));
        assertSha1(data, sha1(data));
        assertSha256(data, sha256(data));
        assertSha512(data, sha512(data));
        print("+++++done!");
    }

    @action("testrecover")
    test_recover(msg: u8[], sig: Signature, pub_key: PublicKey): void {
        let digest = sha256(msg);
        let _pub_key = recoverKey(digest, sig);
        check(pub_key == _pub_key, "invalid public key");

        assertRecoverKey(digest, sig, pub_key);
        print("++++++++test_recover done!");
    }
}

Test code:

@chain_test
def test_hash(tester):
    deploy_contract(tester, 'test')
    r = tester.push_action('hello', 'testhash', {}, {'hello': 'active'})
    logger.info('++++++elapsed: %s', r['elapsed'])
    tester.produce_block()

@chain_test
def test_recover_key(tester):
    deploy_contract(tester, 'test')
    key = eos.create_key()
    pub = key['public']
    priv = key['private']

    msg = b'hello, world'
    h = hashlib.sha256()
    h.update(msg)
    sig = eos.sign_digest(h.hexdigest(), priv)

    args = {
        'msg': msg.hex(),
        'sig': sig,
        'pub_key': pub,
    }
    r = tester.push_action('hello', 'testrecover', args, {'hello': 'active'})
    logger.info('++++++elapsed: %s', r['elapsed'])
    tester.produce_block()

Compilation:

cd examples/cryptotest
yarn
yarn build

Testing:

ipyeos -m pytest -s -x test.py -k test_hash
ipyeos -m pytest -s -x test.py -k test_recover_key

In this example code, it demonstrates the usage of common hash functions as well as recoverKey and assertRecoverKey. The usage of hash functions is pretty straightforward, here is an explanation for the recoverKey test code: recoverKey accepts two parameters, digest and signature. The digest is the result of running sha256 on a binary data. In the above code, the hash calculation is done on hello, world through sha256, as shown in the following code:

msg = b'hello, world'
h = hashlib.sha256()
h.update(msg)
sig = eos.sign_digest(h.hexdigest(), priv)

eos.sign_digest is used to sign the data.

Here is an explanation for testrecover:

@action("testrecover")
test_recover(msg: u8[], sig: Signature, pub_key: PublicKey): void {
    let digest = sha256(msg);
    let _pub_key = recoverKey(digest, sig);
    check(pub_key == _pub_key, "invalid public key");

    assertRecoverKey(digest, sig, pub_key);
    print("++++++++test_recover done!");
}

The principle of recoverKey is the same as the verification of signatures in Transactions by nodes, which is to sign the digest and then verify it with a public key. In actual smart contract applications, if you want to determine whether a piece of binary data is signed with a specific private key in a smart contract, you can use the above method. The process is as follows:

  • The contract saves the public key corresponding to a user's private key
  • The user signs the data with their own private key
  • The user sends the data and its corresponding signature to the smart contract
  • The smart contract can call RecoverKey to restore the public key from the user's data and its signature
  • The smart contract reads the user's public key saved on the chain, and compares it with the public key restored by calling RecoverKey. If they match, it can be confirmed that the data is signed by the corresponding user.

Comments