Skip to content

lay2dev/pw-lock

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
c
 
 
 
 
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

pw-lock

Forked from CKB's system scripts, and currently supports signature generated by personalSign and signTypedData from ethereum wallets.

The CKB system script secp256k1_blake160_sighash_all uses blake2b to calculate the hash, and secp256k1_ecdsa_recover for signature verification. The main difference between CKB and the Ethereum signature verification is the hash calculation method. Ethereum uses keccak256 instead of blake2b to calculate the hash.

Quick Start

git submodule init
git submodule update
make install-tools
make all-via-docker
cargo test --all

Script Implementation

In view of the fact that EIP712 can show users more intuitive and safe information, pw-lock preferentially supports EIP712 related signature method eth_signTypedData_v4. However, currently only a few ETH wallets can fully support EIP712. In order to fully support the Ethereum ecosystem, pw-lock also adapts to the personalSign signature currently supported by most Ethereum wallets.

pw-lock script provides two signature verification methods: eth_personalSign and eth_signTypedData_v4.

eth_personalSign

hash calculation

The same hash calculation process is the same as the CKB system lock script [secp256k1_blake160_sighash_all.c] (https://github.com/nervosnetwork/ckb-system-scripts/blob/master/c/secp256k1_blake160_sighash_all.c), but replace blake2b into keccak256.

signature verification

// pseudo code, the actual code is written in C language
const newHash = hashPersonalMessage(hash)

/*
hashPersonalMessage = function(message: Buffer): Buffer {
  const prefix = Buffer.from(
    `\u0019Ethereum Signed Message:\n${message.length.toString()}`,
    'utf-8',
  )
  return keccak(Buffer.concat([prefix, message]))
}
*/

const pubkey = secp256k1_ecdsa_recover(signature, newHash)
if (pubkey.slice(12, 32) === lock.args){
    return 0;
}
  1. Use the ECDSA_RECOVER algorithm to calculate the 32-byte pubkey from the personalHash and signature.
  2. Check if the last 20 bytes of pubkey are equal to lock args (that is, Ethereum address).

eth_signTypedData_v4

hash calculation

The hash calculation process is the same as the CKB system lock script, except that blake2b is replaced by keccak256.

signature verification

// pseudo code, the actual code is written in C language
const newHash = hashPersonalMessage(hash)
const typedData = {
    domain: {
      chainId: 1,
      name: 'ckb.pw',
      verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
      version: '1'
    },

    message: {
      hash:
        '0x545529d4464064d8394c557afb06f489e7044a63984c6113385431d93dcffa1b',
      fee: '0.00100000CKB',
      'input-sum': '100.00000000CKB',
      to: [
        {
          address: 'ckb1qyqv4yga3pgw2h92hcnur7lepdfzmvg8wj7qwstnwm',
          amount: '100.00000000CKB'
        },
        {
          address:
            'ckb1qftyhqxwuxdzp5zk4rctscnrr6stjrmfjdx54v05q8t3ad3493m6mhcekrn0vk575h44ql9ry53z3gzhtc2exudxcyg',
          amount: '799.99800000CKB'
        }
      ]
    },
    primaryType: 'CKBTransaction',
    types: {
      EIP712Domain: [
        { name: 'name', type: 'string' },
        { name: 'version', type: 'string' },
        { name: 'chainId', type: 'uint256' },
        { name: 'verifyingContract', type: 'address' }
      ],
      CKBTransaction: [
        { name: 'hash', type: 'bytes32' },
        { name: 'fee', type: 'string' },
        { name: 'input-sum', type: 'string' },
        { name: 'to', type: 'Output[]' }
      ],
      Output: [
        { name: 'address', type: 'string' },
        { name: 'amount', type: 'string' }
      ]
    }
}

typedData.message.hash = newHash
typedData.message['input-sum'] = total_input_amount(tx)
typedData.message.fee = total_input_amount(tx) - total_output_amount(tx)
typedData.message.to = extractTxOutputsInfo(tx)

According to the CKB transaction information, input-sum / fee / to related informations are calculated and assigned to the corresponding attribute of typedData.

signature verification

// pseudo code, the actual code is written in C language

const sigUtil = require('eth-sig-util')

const typedHash =  sigUtil.TypedDataUtils.sign(typedData)
const pubkey = secp256k1_ecdsa_recover(signature, typedHash) 
if( pubkey.slice(12,32) === lock.args){
    return 0;
}
  1. Calculate typedHash by typedData, and use ECDSA_RECOVER algorithm to calculate 32-byte pubkey from typedHash and signature.
  2. Check if the last 20 bytes of pubkey are equal to lock args (that is, Ethereum address).

Anyone-can-pay Support

pw-lock also integrates the features of anyone-can-pay, which is consistent with the official anyone-can-pay

About

A ckb lock script which can make use of other blockchain wallets as ckb wallets.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published