Java Solana生成离线地址

一、Solana介绍

Solana是一个新兴的高性能的公链,它提供了快速、便宜且可扩展的交易体验,每秒能够处理数千笔交易,并且出块时间达到了亚秒级。它通过拜占庭容错(BFT)共识机制实现了这一点,该机制利用了一种历史证明(PoH)的创新的密码学函数。并且它还支持使用Rust,C++和C语言来编写智能合约。
官网:https://solana.com/zh

之前开了btc、eth、tron等的钱包,现在空闲记录下solana生成离线地址。

钱包

  • BIP32:定义 Hierarchical Deterministic wallet (简称 “HD Wallet”),是一个系统可以从单一个 seed 产生一树状结构储存多组 keypairs(私钥和公钥)。好处是可以方便的备份、转移到其他相容装置(因为都只需要 seed),以及分层的权限控制等。

  • BIP39:将 seed 用方便记忆和书写的单字表示。一般由 12 个单字组成,称为 mnemonic code(phrase),中文称为助记词或助记码。例如:

soldier dish answer treat exhibit blade diary glory arrange shoe ocean card
  • BIP44:基于 BIP32 的系统,赋予树状结构中的各层特殊的意义。让同一个 seed 可以支援多币种、多帐户等。各层定义如下:
  m / purpose' / coin_type' / account' / change / address_index
  
  //purporse': 固定值44', 代表是BIP44
  //coin_type': 这个代表的是币种, 可以兼容很多种币, 比如BTC是0, ETH是60,TRX是195
  //account: 代表这个币的账户索引,从0开始
  //change: 常量0用于外部(收款地址),常量1用于内部(也称为找零地址)。外部用于在钱包外可见的地址(例如,用于接收付款)。内部链用于在钱包外部不可见的地址,用于返回交易变更。 (所以一般使用0)
  //address_index: 地址索引,从0开始,代表生成第几个地址
  //btc一般是 m/44'/0'/0'/0
  //eth一般是 m/44'/60'/0'/0
  //trx一般是 m/44'/195'/0'/0

币种类型列表

依赖

<!-- https://mvnrepository.com/artifact/com.portto.solana/web3 -->
<dependency>
    <groupId>com.portto.solana</groupId>
    <artifactId>web3</artifactId>
    <version>0.1.3</version>
</dependency>

依赖库编译时遇到的问题:卸载2019版本的idea,装了2022版本😤

// This class file was compiled with different version of Kotlin compiler and can't be decompiled.
//
// Current compiler ABI version is 1.1.15
// File ABI version is 1.6.0

生成地址及私钥

byte[] seed = MnemonicUtils.generateSeed(mnemonic, "");
SolanaBip44 solanaBip44 = new SolanaBip44();
//M/44H/501H/0H/0H
byte[] privateKeyFromSeed = solanaBip44.getPrivateKeyFromSeed(seed, DerivableType.BIP44CHANGE);
TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(privateKeyFromSeed);
System.out.println("地址0:" + Base58.encode(keyPair.getPublicKey()));
System.out.println("私钥0:" + Base58.encode(keyPair.getSecretKey()));
Account account = new Account(keyPair);
System.out.println("Account地址0:" + account.getPublicKey());
System.out.println("Account私钥0:" + Base58.encode(account.getSecretKey()));

BIP44助记词生成N个地址

//拆解 getPrivateKeyFromSeed(seed, DerivableType.BIP44CHANGE);
for (int i = 0; i < 10; i++) {
    HdKeyGenerator hdKeyGenerator = new HdKeyGenerator();
    SolanaCoin solanaCoin = new SolanaCoin();
    HdAddress masterAddress = hdKeyGenerator.getAddressFromSeed(seed, solanaCoin);
    HdAddress purposeAddress = hdKeyGenerator.getAddress(masterAddress, solanaCoin.getPurpose(), solanaCoin.getAlwaysHardened());// 44H
    HdAddress coinTypeAddress = hdKeyGenerator.getAddress(purposeAddress, solanaCoin.getCoinType(), solanaCoin.getAlwaysHardened());// 501H
    HdAddress accountAddress = hdKeyGenerator.getAddress(coinTypeAddress, i, solanaCoin.getAlwaysHardened());//0H
    HdAddress changeAddress = hdKeyGenerator.getAddress(accountAddress, 0L, solanaCoin.getAlwaysHardened()); //0H
    Account account1 = new Account(TweetNaclFast.Signature.keyPair_fromSeed(changeAddress.getPrivateKey().getPrivateKey()));
    System.out.println("Account地址" + i + ":" + account1.getPublicKey());
    System.out.println("Account私钥" + i + ":" + Base58.encode(account1.getSecretKey()));
}

私钥转换地址

package com.hlf.test.solana;

import com.portto.solana.web3.Account;
import com.portto.solana.web3.util.TweetNaclFast;
import org.bitcoinj.core.Base58;

/**
 * @ClassName: PrivateKeyAddress
 * @Author: huanglefei
 * @CreateDate: 2022/4/2 8:29 PM
 * @Description:
 * @Version: 1.0
 **/
public class PrivateKeyAddress {
    //地址0:2Hyaw6rryApLpffVYZxvT2BTAAARoJzoCBSs6Zy3bVow
    //私钥0:3WWsrp38veGfPJcdfmPDwGwqgaGGFQ7uZrk61rcYCbGyKjFXLYWid6CJgBUXTA8Ls2vSS8gMGhjtFrGSLYuAtZ4D
    public static void main(String[] args) {
        String privateKey = "3WWsrp38veGfPJcdfmPDwGwqgaGGFQ7uZrk61rcYCbGyKjFXLYWid6CJgBUXTA8Ls2vSS8gMGhjtFrGSLYuAtZ4D";

        byte[] decode = Base58.decode(privateKey);
        Account account1 = new Account(TweetNaclFast.Signature.keyPair_fromSecretKey(decode));
        Account account2 = new Account(TweetNaclFast.Signature.keyPair_fromSeed(decode));
        System.out.println("私钥转换地址:" + account1.getPublicKey());
        System.out.println("私钥转换地址-私钥:" + Base58.encode(account1.getSecretKey()));
    }
}

示例代码

package com.hlf.test.solana;

import com.portto.solana.web3.Account;
import com.portto.solana.web3.util.TweetNaclFast;
import com.portto.solana.web3.wallet.*;
import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.Base58;
import org.web3j.crypto.*;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;

/**
 * @ClassName: MnemonicAddress
 * @Author: huanglefei
 * @CreateDate: 2022/4/2 8:19 PM
 * @Description:
 * @Version: 1.0
 **/
public class MnemonicAddress {
    private static final String KEYSTORE_PATH = "/Users/huanglefei/Downloads/";

    public static void main(String[] args) {
        String mnemonic = "soldier dish answer treat exhibit blade diary glory arrange shoe ocean card";

        if (StringUtils.isBlank(mnemonic)) {
            try {
                // generate Mnemonic and keystone File
                Bip39Wallet bip39Wallet = generateBip44Wallet("hlf", KEYSTORE_PATH);
                //助记词
                mnemonic = bip39Wallet.getMnemonic();
                System.out.println("助记词:" + mnemonic);
            } catch (CipherException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        byte[] seed = MnemonicUtils.generateSeed(mnemonic, "");
        SolanaBip44 solanaBip44 = new SolanaBip44();
        //M/44H/501H/0H/0H
        byte[] privateKeyFromSeed = solanaBip44.getPrivateKeyFromSeed(seed, DerivableType.BIP44CHANGE);
        TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(privateKeyFromSeed);
        System.out.println("地址0:" + Base58.encode(keyPair.getPublicKey()));
        System.out.println("私钥0:" + Base58.encode(keyPair.getSecretKey()));
        Account account = new Account(keyPair);
        System.out.println("Account地址0:" + account.getPublicKey());
        System.out.println("Account私钥0:" + Base58.encode(account.getSecretKey()));

        System.out.println();
        //M/44H/501H/0H/0H
        //通过助记词生成n个地址及私钥
        //拆解 getPrivateKeyFromSeed(seed, DerivableType.BIP44CHANGE);
        for (int i = 0; i < 10; i++) {
            HdKeyGenerator hdKeyGenerator = new HdKeyGenerator();
            SolanaCoin solanaCoin = new SolanaCoin();
            HdAddress masterAddress = hdKeyGenerator.getAddressFromSeed(seed, solanaCoin);
            HdAddress purposeAddress = hdKeyGenerator.getAddress(masterAddress, solanaCoin.getPurpose(), solanaCoin.getAlwaysHardened());// 44H
            HdAddress coinTypeAddress = hdKeyGenerator.getAddress(purposeAddress, solanaCoin.getCoinType(), solanaCoin.getAlwaysHardened());// 501H
            HdAddress accountAddress = hdKeyGenerator.getAddress(coinTypeAddress, i, solanaCoin.getAlwaysHardened());//0H
            HdAddress changeAddress = hdKeyGenerator.getAddress(accountAddress, 0L, solanaCoin.getAlwaysHardened()); //0H
            Account account1 = new Account(TweetNaclFast.Signature.keyPair_fromSeed(changeAddress.getPrivateKey().getPrivateKey()));
            System.out.println("Account地址" + i + ":" + account1.getPublicKey());
            System.out.println("Account私钥" + i + ":" + Base58.encode(account1.getSecretKey()));
        }

    }

    public static Bip39Wallet generateBip44Wallet(String pwd, String dirPath) throws CipherException, IOException {
        File dir = new File(dirPath);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                throw new RuntimeException("make wallet dir error");
            }
        }
        return Bip44WalletUtils.generateBip44Wallet(pwd, dir);
    }

    public static String generateMnemonicFile(String pwd, String mnemonic, String dirPath) throws CipherException, IOException {
        // make dir
        File dir = new File(dirPath);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                throw new RuntimeException("make wallet dir error");
            }
        }
        // string to pk
        byte[] entBytes = MnemonicUtils.generateEntropy(mnemonic);
        BigInteger entBigInteger = new BigInteger(entBytes);
        ECKeyPair entEcKeyPair = ECKeyPair.create(entBigInteger);
        return WalletUtils.generateWalletFile(pwd, entEcKeyPair, dir, false);
    }
}

控制台

Connected to the target VM, address: '127.0.0.1:56354', transport: 'socket'
地址0:2Hyaw6rryApLpffVYZxvT2BTAAARoJzoCBSs6Zy3bVow
私钥0:3WWsrp38veGfPJcdfmPDwGwqgaGGFQ7uZrk61rcYCbGyKjFXLYWid6CJgBUXTA8Ls2vSS8gMGhjtFrGSLYuAtZ4D
Account地址0:2Hyaw6rryApLpffVYZxvT2BTAAARoJzoCBSs6Zy3bVow
Account私钥0:3WWsrp38veGfPJcdfmPDwGwqgaGGFQ7uZrk61rcYCbGyKjFXLYWid6CJgBUXTA8Ls2vSS8gMGhjtFrGSLYuAtZ4D

Account地址0:2Hyaw6rryApLpffVYZxvT2BTAAARoJzoCBSs6Zy3bVow
Account私钥0:3WWsrp38veGfPJcdfmPDwGwqgaGGFQ7uZrk61rcYCbGyKjFXLYWid6CJgBUXTA8Ls2vSS8gMGhjtFrGSLYuAtZ4D
Account地址1:HwKQF8979cc1pwpGD8xD1GppJJTbvzbSXxQgjP5hmjCE
Account私钥1:4JAgHSGvBnSeNNiwk17eqHMdLXFqw53mmiRL8ef9rpL1ZXzVJ4GUPgYbWcRhpaZnohpt7fYe45thJKJfEed8FMrA
Account地址2:5iCnsERHGXMHApMC1J4EsTnEqcWfSew2yGmAGEjsr12Z
Account私钥2:2V9wRtqRZYAeyTHx99sKN3BNxpbVgt82TrejpmBLNR593ZqnxhteC2m9mWQuiEg9VFbttBhE4YzmxZSxZdQwaVrq
Account地址3:22ogk3ArAet5SL43zVYT4Ej8FaBfgZyFwFG8biJx9VBb
Account私钥3:3dEwx6otjGzvmXm4dB518dHpGX1cxdfnm5E4V9r1Hw4gjyDPWRARariQ293TNdojbGRWbhawLgWET58HF5dZufkq
Account地址4:CnmxbaWTKqKWvCnMSJgaAP8axfxL3udy7kLkgAU32qVM
Account私钥4:2JSvZYqaxxg92VxfpTBNonR8xQUjKoADudjzquZ33FSiMbhcdk2dfawgWMBF2NXtGReLXiz3D1678EEPsnGsaQXd
Account地址5:5gMkZhETUgBMVRVxzdZarHSTLvFFCziCkSkKrSurWTWj
Account私钥5:4DiUbrs7vcFYMCyqe4dMehiNQBhx2iRbGKsW6nmBJLzyyPuRMRdorqcEq2yME1wM7skxTMRpcYcA9dCkSduQGmUf
Account地址6:5t1DS9h3tvCGCQfWSg4MP8bpZDPZp4Gavu2w5p7hymyz
Account私钥6:2hAst5LWJuBpeqE5C4H3MvTQb2BzC4mGCrfSi9QRHA7G322KgFmp4kVEcssry1wvLVMFv7WaUUDkFosuXeWnz8tx
Account地址7:DLYHSMwPodh5Qms93JcHJL17vfFsqiqJ7SBEVShqdYR8
Account私钥7:tpn1HxEWXoChunYWeixisxJ5DefhGzMhySu5M2VGUWCiaieYBUGPVJWSXfPqcxPyxqjbwEypHAktVsPbAB4tJ8J
Account地址8:DoBeV5gBojXEF9WjmwVAd2Ukd5PZrxFLL8taC4h4Yynu
Account私钥8:PbkuETqeHWuCHcrYSWPVDHvmD57D25CLdSUfYe3d1FpXK3qDBZj6UWT9mcy6LWvHimHmY4ciVdR14dmk7EWPAJH
Account地址9:6V5TdtRzBMNFAbbfZUQ6y7cQzk7Eg1HPnWPJuENSmcku
Account私钥9:4D9sM3zcQyTjrTtnfruNYLpA4HDRtU9PBkxVmCzYBLVnmjjKBPutumS3Q4MQP2whBJGM4jLhMvp31MJEaVPWQEAh
Disconnected from the target VM, address: '127.0.0.1:56354', transport: 'socket'

Process finished with exit code 0

Phantom钱包对比

solana生态钱包中生成的地址。


d67c3c31b5b749b097b394edcae5793f.png

参考资料:

https://github.com/portto/solana-web3.kotlin

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342