BCSkill (Block chain skill )
区块链中文技术社区

只讨论区块链底层技术
遵守一切相关法律政策!

比特币,以太坊,EOS 公私钥生成以及签名 BlockchainWallet-Crypto

BlockchainWallet-Crypto

简介

这个库到底能干什么
  1. 生成比特币公私钥地址
  2. 生成以太坊公私钥地址
  3. 根据 UTXO 信息打包比特币交易
  4. 根据 nonce 信息打包以太坊交易
  5. 对比特币交易进行签名
  6. 对以太坊交易进行签名
  7. 支持 BIP39 助记词
  8. 支持 BIP32 子私钥
  9. 支持 BIP44 多币种管理
  10. 支持 BIP38 加密私钥导入导出
  11. 支持以太坊 keystore 导入导出
  12. 生成以太坊调用智能合约的参数
  13. 生成 EOS 公私钥

EOS 从助记词生成私钥

现在 EOS 从助记词生成私钥有两种方式

  1. 12 个助记词之间用空格隔开拼接成字符串,然后 Hash 得到私钥
  2. 采用 Bip44 标准的生成方案,EOS 的币种序号详见最下方⎡相关资料⎦中的⎡Bip44 注册币种列表⎦

经过国内大部分钱包商议统一使用第二种方案解决 EOS 从助记词生成私钥的问题

欢迎给位提设计上的 lssues 和 pr

引入项目

allprojects {
  repositories {
    ...
        maven { url 'https://jitpack.io' }
  }
}

dependencies {
  implementation 'com.github.QuincySx:BlockchainWallet-Crypto:last-version'
}

使用说明

简单使用说明

相关资料

Bip44 注册币种列表

LICENSE

开源协议

github:https://github.com/QuincySx/BlockchainWallet-Crypto

ScatterDesktop Backup

BackService 调用 saveFile

export default class BackupService {

    static async setBackupStrategy(strategy){
        const scatter = store.state.scatter.clone();
        scatter.settings.autoBackup = strategy;
        return store.dispatch(Actions.SET_SCATTER, scatter);
    }

    static async createBackup(){
        const location = getFolderLocation();
        if(! location) return false;

        await saveFile(location[0]);
    }

    static async setBackupLocation(){
        const location = getFolderLocation();
        if(!location) return false;
        const scatter = store.state.scatter.clone();
        scatter.settings.backupLocation = location[0];
        return store.dispatch(Actions.SET_SCATTER, scatter);
    }

    static async createAutoBackup(){
        if(!store.state.scatter || !store.state.scatter.settings) return;
        const strategy = store.state.scatter.settings.autoBackup;
        if(!strategy || !strategy.length || strategy === BACKUP_STRATEGIES.MANUAL) return;

        const backupLocation = store.state.scatter.settings.backupLocation;
        if(!backupLocation || !backupLocation.length) return false;


        await saveFile(backupLocation);
    }

}

写入备份文件

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/BackupService.js#L12:18

const saveFile = (filepath) => {
    return new Promise(resolve => {
        const scatter = getLatestScatter();
        const date = new Date();
        const month = date.getUTCMonth();
        const year = date.getUTCFullYear();
        const salt = StorageService.getSalt();
        const file = scatter + '|SLT|' + salt;
        const name = `${filepath}/scatter__${store.state.scatter.hash.substr(0,4)}-${store.state.scatter.hash.slice(-4)}__${store.state.scatter.meta.version}__${month}-${year}.json`;
        try {
            fs.writeFileSync(name, file, 'utf-8');
            resolve(true);
        }
        catch(e) {
            console.error('Error saving file', e);
            resolve(false);
        }
    })
};

备份文件的内容

const scatter = getLatestScatter();
const salt = StorageService.getSalt();
const file = scatter + '|SLT|' + salt;
const getLatestScatter = () => StorageService.getScatter();

StorageService

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/StorageService.js#L93

export default class StorageService {

    constructor(){}

    static async setScatter(scatter){
        return new Promise(async resolve => {
            clearSaveTimeouts();
            saveResolvers.push(resolve);
            safeSetScatter(scatter, resolve);
        })
    };

    static getScatter() {
        return scatterStorage().get('scatter');
    }

actions

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/store/actions.js#L91

[Actions.SET_SCATTER]:async ({commit, state}, scatter) => {
        return new Promise(async resolve => {
            const process = Process.savingData();

            const seed = await ipcAsync('seed');
            const savable = AES.encrypt(scatter.savable(seed), seed);
            StorageService.setLocalScatter(savable);
            process.updateProgress(50);
            StorageService.setScatter(savable).then(() => {
                BackupService.createAutoBackup()
            });

            commit(Actions.SET_SCATTER, scatter);
            resolve(scatter);
            process.updateProgress(100);
        })
    },

其中的

const seed = await ipcAsync('seed');

是从

 [Actions.SET_SEED]:({commit}, password) => {
        return new Promise(async (resolve, reject) => {
            const [mnemonic, seed] = await PasswordService.seedPassword(password, true);
            resolve(mnemonic);
        })
    },

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/PasswordService.js#L48

static async seedPassword(password, setToState = true){
        return new Promise(async (resolve, reject) => {
            try {
                let seed, mnemonic;
                if(password.split(' ').length >= 12) {
                    seed = await Mnemonic.mnemonicToSeed(password);
                    mnemonic = password;
                } else {
                    const [m, s] = await Mnemonic.generateMnemonic(password);
                    seed = s;
                    mnemonic = m;
                }

                if(setToState) ipcFaF('seeding', seed);
                resolve([mnemonic, seed]);
            } catch(e){
                resolve([null, null]);
            }
        })
    }

Scatter

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop/-/blob/src/models/Scatter.js#L76:1

savable(seed){
        this.keychain.keypairs.map(keypair => keypair.encrypt(seed));

        const clone = this.clone();
        clone.keychain.identities.map(id => id.encrypt(seed));

        // Keychain is always stored encrypted.
        clone.encrypt(seed);

        return clone;
    }

Keychain

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/models/Keychain.js#L20:1

static fromJson(json){
        let p = Object.assign(this.placeholder(), json);
        if(json.hasOwnProperty('keypairs')) p.keypairs = json.keypairs.map(x => Keypair.fromJson(x));
        if(json.hasOwnProperty('accounts')) p.accounts = json.accounts.map(x => Account.fromJson(x));
        if(json.hasOwnProperty('identities')) p.identities = json.identities.map(x => Identity.fromJson(x));
        if(json.hasOwnProperty('permissions')) p.permissions = json.permissions.map(x => Permission.fromJson(x));
        if(json.hasOwnProperty('apps')) p.apps = json.apps.map(x => AuthorizedApp.fromJson(x));
        return p;
    }

nodeos 输出log方式

https://github.com/EOSIO/fc/blob/a6f94bae0b2b4a0b68dc1db2677331cafa4716a5/src/log/logger_config.cpp#L24

 bool configure_logging( const logging_config& cfg )
   {
      try {
      static bool reg_console_appender = appender::register_appender<console_appender>( "console" );
      static bool reg_gelf_appender = appender::register_appender<gelf_appender>( "gelf" );
      get_logger_map().clear();
      get_appender_map().clear();

支持输出到 console 和 gelf 两种方式

gelf
https://sourcegraph.com/github.com/EOSIO/fc@a6f94bae0b2b4a0b68dc1db2677331cafa4716a5/-/blob/include/fc/log/gelf_appender.hpp

namespace fc 
{
  // Log appender that sends log messages in JSON format over UDP
  // https://www.graylog2.org/resources/gelf/specification
  class gelf_appender final : public appender 
  {
  public:
    struct config 
    {
      string endpoint = "127.0.0.1:12201";
      string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server)
    };

类似 https://github.com/mattwcole/gelf-extensions-logging

EOS 代币命名规则

constexpr explicit symbol_code( std::string_view str )
      :value(0)
      {
         if( str.size() > 7 ) {
            eosio::check( false, "string is too long to be a valid symbol_code" );
         }
         for( auto itr = str.rbegin(); itr != str.rend(); ++itr ) {
            if( *itr < 'A' || *itr > 'Z') {
               eosio::check( false, "only uppercase letters allowed in symbol_code string" );
            }
            value <<= 8;
            value |= *itr;
         }
      }

格式

<=7位,A-Z