如何使用metamask密钥签署Hyperledger-Sawtooth交易?

问题描述

超级账本锯齿使用secp256k1 ECDSA签署交易: https://sawtooth.hyperledger.org/docs/core/releases/1.2.5/_autogen/txn_submit_tutorial.html?highlight=transaction%20sign

显然,以太坊使用相同类型的签名: https://hackernoon.com/a-closer-look-at-ethereum-signatures-5784c14abecc

因此,似乎因为Metamask与以太坊一起使用,它也可以与锯齿一起使用。但是,我还没有找到这样的示例,尽管我尝试使用Metamask与web3.js和ethers.js签署交易,但这些签名被Sawtooth拒绝。

解决方法

这是可能的,这是我使用web3:0.20.7制作的一个示例: https://github.com/le99/sawtooth-with-metamask-signatures/blob/master/src/App.js

重要的功能是onClick()

import './App.css';
import React,{ useState } from 'react';

var ethUtil = require('ethereumjs-util')
const secp256k1 = require('secp256k1')
const CryptoJS = require('crypto-js');
const axios = require('axios').default;
const cbor = require('cbor')
const Web3 = require('web3');

//https://github.com/ethereum/web3.js/blob/0.20.7/DOCUMENTATION.md
// let web3 = new Web3(Web3.givenProvider || "ws://localhost:8545");
let web3;
if (typeof window.web3 !== 'undefined') {
  web3 = new Web3(window.web3.currentProvider);
} else {
  // set the provider you want from Web3.providers
  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}

const hash = (x) =>
  CryptoJS.SHA512(x).toString(CryptoJS.enc.Hex)

// https://stackoverflow.com/questions/33914764/how-to-read-a-binary-file-with-filereader-in-order-to-hash-it-with-sha-256-in-cr
function arrayBufferToWordArray(ab) {
  var i8a = new Uint8Array(ab);
  var a = [];
  for (var i = 0; i < i8a.length; i += 4) {
    a.push(i8a[i] << 24 | i8a[i + 1] << 16 | i8a[i + 2] << 8 | i8a[i + 3]);
  }
  return CryptoJS.lib.WordArray.create(a,i8a.length);
}


async function onClick(){
    const ethereum = window.ethereum;

    var from = web3.eth.accounts[0]

    // var msgHash = ethUtil.keccak256(Buffer.from('An amazing message,for use with MetaMask!'))
    var msgHash = Buffer.from('8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede','hex');
    console.log(from);
    
    
    let signature1 = await new Promise((resolve,reject)=>{
      web3.eth.sign(from,msgHash,function (err,result) {
        if (err) return reject(err)
        return resolve(result)
      })
    });

    const rpk3 = secp256k1.ecdsaRecover(Uint8Array.from(Buffer.from(signature1.slice(2,-2),'hex')),parseInt(signature1.slice(-2),16) - 27,Uint8Array.from(msgHash));
    let publicKey = Buffer.from(rpk3,'hex').toString('hex')

    console.log(msgHash.toString('hex'));
    console.log(signature1);
    console.log(publicKey);

    console.log();


    const INT_KEY_FAMILY = 'intkey'
    const INT_KEY_NAMESPACE = hash(INT_KEY_FAMILY).substring(0,6)
    const address = INT_KEY_NAMESPACE + hash('foo').slice(-64)
    console.log('address:',address);
    const payload = {
      Verb: 'set',Name: 'foo',Value: 41
    }

    console.log('public:',publicKey);

    const payloadBytes = cbor.encode(payload)

    const protobuf = require('sawtooth-sdk/protobuf')
    const transactionHeaderBytes = protobuf.TransactionHeader.encode({
      familyName: 'intkey',familyVersion: '1.0',inputs: [address],outputs: [address],signerPublicKey: publicKey,// In this example,we're signing the batch with the same private key,// but the batch can be signed by another party,in which case,the
      // public key will need to be associated with that key.
      batcherPublicKey: publicKey,there are no dependencies.  This list should include
      // an previous transaction header signatures that must be applied for
      // this transaction to successfully commit.
      // For example,// dependencies: ['540a6803971d1880ec73a96cb97815a95d374cbad5d865925e5aa0432fcf1931539afe10310c122c5eaae15df61236079abbf4f258889359c4d175516934484a'],dependencies: [],payloadSha512: CryptoJS.SHA512(arrayBufferToWordArray(payloadBytes)).toString(CryptoJS.enc.Hex),nonce:"hey4"
    }).finish()


    let sss=CryptoJS.SHA256(arrayBufferToWordArray(transactionHeaderBytes)).toString(CryptoJS.enc.Hex);
    let dataHash=Uint8Array.from(Buffer.from(sss,'hex'));

    let signature = await new Promise((resolve,dataHash,result) {
        if (err) return reject(err)
        return resolve(result)
      })
    });
    signature = signature.slice(2,-2)

    console.log('sha1:',CryptoJS.SHA512(arrayBufferToWordArray(transactionHeaderBytes)).toString(CryptoJS.enc.Hex))
    console.log('signature1:',signature)

    const transaction = protobuf.Transaction.create({
      header: transactionHeaderBytes,headerSignature: signature,payload: payloadBytes
    })
  
    //--------------------------------------
    //Optional
    //If sending to sign outside
    
    const txnListBytes = protobuf.TransactionList.encode({transactions:[
      transaction
    ]}).finish()
    
    //const txnBytes2 = transaction.finish()
    
    let transactions = protobuf.TransactionList.decode(txnListBytes).transactions;
    
    //----------------------------------------
    
    //transactions = [transaction]
    
    const batchHeaderBytes = protobuf.BatchHeader.encode({
      signerPublicKey: publicKey,transactionIds: transactions.map((txn) => txn.headerSignature),}).finish()
    
    //
    sss=CryptoJS.SHA256(arrayBufferToWordArray(batchHeaderBytes)).toString(CryptoJS.enc.Hex);
    dataHash=Uint8Array.from(Buffer.from(sss,'hex'));


    signature = await new Promise((resolve,-2)


    const batch = protobuf.Batch.create({
      header: batchHeaderBytes,transactions: transactions
    })
    
    const batchListBytes = protobuf.BatchList.encode({
      batches: [batch]
    }).finish()
    
    console.log(Buffer.from(batchListBytes).toString('hex'));

    console.log('batchListBytes has the batch bytes that ca be sent to sawtooth')
    // axios.post(`${HOST}/batches`,batchListBytes,{
    //   headers: {'Content-Type': 'application/octet-stream'}
    // })
    //   .then((response) => {
    //     console.log(response.data);
    //   })
    //   .catch((err)=>{
    //     console.log(err);
    //   });

      
  }


该示例基于: https://sawtooth.hyperledger.org/docs/core/releases/1.2.6/_autogen/sdk_submit_tutorial_js.html

有很多低级内容,超级账本和Metamask表示签名略有不同。同样,大多数用于Metamask的库会自动包装数据(https://web3js.readthedocs.io/en/v1.2.11/web3-eth-accounts.html#sign),然后使用keccak256对数据进行哈希处理,并且该哈希值是使用secp256k1最终签名的,而不是您需要Sawtooth。

不使用任何包装或中介进行签名的示例是:https://github.com/danfinlay/js-eth-personal-sign-examples/blob/master/index.js

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...