主页 > imtoken钱包不能安装 > 以太坊 ETH 转账

以太坊 ETH 转账

imtoken钱包不能安装 2023-06-16 05:22:45

本文介绍以太坊(Ethereum)的转账,它是基于web3j库实现的。

概念介绍

DSA是一种公钥算法,不能用于加密,只能用于数字签名。参考

ECDSA Elliptic Curve Digital Signature Algorithm (ECDSA)是一种使用椭圆曲线密码术(ECC)的数字签名算法(DSA)加密。生成的r,s签名值参考

1.解码钱包

即根据用户密码从钱包中读取keystore信息。 这基本上是钱包生成的逆过程。

1、根据scrypt算法,用用户密码重新生成derivedKey。 如下图红框所示,对比一下create()

2.根据derivedKey调用performCipherOperation()解密方法得到私钥。如下图蓝框所示,与create()对比

3. 将私钥传递给ECKeyPair::create() 再次获取公钥。 有兴趣调用Sign::publicKeyFromPrivate():BigInteger的可以关注看看。

4、根据ECKeyPair生成Credentials类,主要包括ECKeyPair和钱包地址。

这里需要注意的是,钱包地址是根据公钥重新生成的,而不是从文件中读取的。

想一想,这样做有什么好处呢? (安全,这不是p字吗?万一在文件里被篡改了怎么办。)

sitebihu.com 以太以太坊价格_以太坊团队持有以太比例_以太坊密钥

解密.jpg

具体代码

//Wallet.java内解码钱包
public static ECKeyPair decrypt(String password, WalletFile walletFile)throws CipherException {
    validate(walletFile);
    WalletFile.Crypto crypto = walletFile.getCrypto();
    byte[] mac = Numeric.hexStringToByteArray(crypto.getMac());
    byte[] iv = Numeric.hexStringToByteArray(crypto.getCipherparams().getIv());
    byte[] cipherText = Numeric.hexStringToByteArray(crypto.getCiphertext());
    byte[] derivedKey;
    //获得scrypt加密的相关参数,并解码用户密码。
    WalletFile.KdfParams kdfParams = crypto.getKdfparams();
    if (kdfParams instanceof WalletFile.ScryptKdfParams) {
        WalletFile.ScryptKdfParams scryptKdfParams =
                (WalletFile.ScryptKdfParams) crypto.getKdfparams();
        int dklen = scryptKdfParams.getDklen();
        int n = scryptKdfParams.getN();
        int p = scryptKdfParams.getP();
        int r = scryptKdfParams.getR();
        byte[] salt = Numeric.hexStringToByteArray(scryptKdfParams.getSalt());
        derivedKey = generateDerivedScryptKey(
                password.getBytes(Charset.forName("UTF-8")), salt, n, r, p, dklen);
    } else if (kdfParams instanceof WalletFile.Aes128CtrKdfParams) {
        WalletFile.Aes128CtrKdfParams aes128CtrKdfParams =
                (WalletFile.Aes128CtrKdfParams) crypto.getKdfparams();
        int c = aes128CtrKdfParams.getC();

sitebihu.com 以太以太坊价格_以太坊密钥_以太坊团队持有以太比例

String prf = aes128CtrKdfParams.getPrf(); byte[] salt = Numeric.hexStringToByteArray(aes128CtrKdfParams.getSalt()); derivedKey = generateAes128CtrDerivedKey( password.getBytes(Charset.forName("UTF-8")), salt, c, prf); } else { throw new CipherException("Unable to deserialize params: " + crypto.getKdf()); } byte[] derivedMac = generateMac(derivedKey, cipherText); if (!Arrays.equals(derivedMac, mac)) { throw new CipherException("Invalid password provided"); } byte[] encryptKey = Arrays.copyOfRange(derivedKey, 0, 16); //根据用户密码生成的encryptKey解码cipherText获得私钥 byte[] privateKey = performCipherOperation(Cipher.DECRYPT_MODE, iv, encryptKey, cipherText); return ECKeyPair.create(privateKey); } //Credentials.java内,根据ECKeyPair参数重新获取地址并保存到当前类内。 public static Credentials create(ECKeyPair ecKeyPair) { String address = Numeric.prependHexPrefix(Keys.getAddress(ecKeyPair)); return new Credentials(ecKeyPair, address); }

经过以上步骤以太坊密钥以太坊密钥,我们已经对钱包进行了解码,接下来我们就可以根据这些信息进行转账功能了。

2.获取随机数

nonce:整数类型,会随着账户下的交易不断累加。 作用是“防止事务重放攻击”。

我们通过调用ethscan的相关接口查询上一笔交易的nonce值,从0开始。

3.代码处理

在开始之前,引入一个r、s、v的概念,其中r、s为ECDSA签名值。 v 是链号。

1.根据nonce、gasPrice、gasLimit等初始化RawTransaction类

即交易描述文件。

原始交易。 创建交易()

2.根据描述文件生成字节文件。 事务编码器。 签名消息()

该文件是通过网络传输的文件。 此步骤将根据 ECDSA 进行数字签名和加密。

3.调用api?action=eth_sendRawTransaction将描述文件发送到相关服务器。

4、服务器将该文件广播到ETH公链。

接口调用代码,详见Github中的TransactionService.kt类

class TransactionService : IntentService("Transaction Service") {

sitebihu.com 以太以太坊价格_以太坊团队持有以太比例_以太坊密钥

private var builder: NotificationCompat.Builder? = null internal val mNotificationId = 153 override fun onHandleIntent(intent: Intent?) { sendNotification() try { val fromAddress = intent!!.getStringExtra("FROM_ADDRESS") val toAddress = intent.getStringExtra("TO_ADDRESS") val amount = intent.getStringExtra("AMOUNT") val gas_price = intent.getStringExtra("GAS_PRICE") val gas_limit = intent.getStringExtra("GAS_LIMIT") val data = intent.getStringExtra("DATA") val password = intent.getStringExtra("PASSWORD") val keys = WalletStorage.getInstance(applicationContext).getFullWallet(applicationContext, password, fromAddress) EtherscanAPI.INSTANCE.getNonceForAddress(fromAddress) .subscribe( object : SingleObserver { override fun onSuccess(t: NonceForAddress) { if (t.result.length < 2) return val nonce = BigInteger(t.result.substring(2), 16) val tx = RawTransaction.createTransaction( nonce, BigInteger(gas_price), BigInteger(gas_limit), toAddress, BigDecimal(amount).multiply(ExchangeCalculator.ONE_ETHER).toBigInteger(), data ) Log.d("Aaron", "Nonce: " + tx.nonce + "\n" + "gasPrice: " + tx.gasPrice + "\n" + "gasLimit: " + tx.gasLimit + "\n" +

以太坊密钥_sitebihu.com 以太以太坊价格_以太坊团队持有以太比例

"To: " + tx.to + "\n" + "Amount: " + tx.value + "\n" + "Data: " + tx.data ) val signed = TransactionEncoder.signMessage(tx, 1.toByte(), keys) forwardTX(signed) } override fun onSubscribe(d: Disposable) { } override fun onError(e: Throwable) { error("Can't connect to network, retry it later") } } ) } catch (e: Exception) { error("Invalid Wallet Password!") e.printStackTrace() } } @Throws(IOException::class) private fun forwardTX(signed: ByteArray) { EtherscanAPI.INSTANCE.forwardTransaction("0x" + Hex.toHexString(signed)) .subscribe( object : SingleObserver { override fun onSuccess(t: ForwardTX) { if (!TextUtils.isEmpty(t.result)) { suc(t.result) } else { var errormsg = t.error.message

sitebihu.com 以太以太坊价格_以太坊团队持有以太比例_以太坊密钥

if (errormsg.indexOf(".") > 0) errormsg = errormsg.substring(0, errormsg.indexOf(".")) error(errormsg) // f.E Insufficient funds } } override fun onSubscribe(d: Disposable) { } override fun onError(e: Throwable) { error("Can't connect to network, retry it later") } } ) } private fun suc(hash: String) { builder!! .setContentTitle(getString(R.string.notification_transfersuc)) .setProgress(100, 100, false) .setOngoing(false) .setAutoCancel(true) .setContentText("") val main = Intent(this, MainActivity::class.java) main.putExtra("STARTAT", 2) main.putExtra("TXHASH", hash) val contentIntent = PendingIntent.getActivity(this, 0, main, PendingIntent.FLAG_UPDATE_CURRENT) builder!!.setContentIntent(contentIntent) val mNotifyMgr = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager mNotifyMgr.notify(mNotificationId, builder!!.build()) }

以太坊团队持有以太比例_以太坊密钥_sitebihu.com 以太以太坊价格

private fun error(err: String) { builder!! .setContentTitle(getString(R.string.notification_transferfail)) .setProgress(100, 100, false) .setOngoing(false) .setAutoCancel(true) .setContentText(err) val main = Intent(this, MainActivity::class.java) main.putExtra("STARTAT", 2) val contentIntent = PendingIntent.getActivity(this, 0, main, PendingIntent.FLAG_UPDATE_CURRENT) builder!!.setContentIntent(contentIntent) val mNotifyMgr = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager mNotifyMgr.notify(mNotificationId, builder!!.build()) } private fun sendNotification() { builder = NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_notification) .setColor(0x2d435c) .setTicker(getString(R.string.notification_transferingticker)) .setContentTitle(getString(R.string.notification_transfering_title)) .setContentText(getString(R.string.notification_might_take_a_minute)) .setOngoing(true) .setProgress(0, 0, true) val mNotifyMgr = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager mNotifyMgr.notify(mNotificationId, builder!!.build()) } }

混帐地址: