iOS开发-BIP39的实现

今天来说一下区块链-比特币中的一个概念,并且在iOS中将它实现。

首先介绍一下什么是BIP,BIP全称是Bitcoin Improvement Proposals,是用来提出Bitcoin的新功能或改进措施的文件。可以由任何人提出,经过审核后会公布在bitcoin/bips中。

其中BIP32、BIP39和BID44又是HD wallet中使用的核心概念。

BIP-39 介绍

HD wallet具有管理多个密钥和地址的机制,我们可以使用一个随机字符串seed通过BIP32或BIP44协议创建一个HD wallet,但是一串字符串的记忆成本太高,而且摘抄下来也会很麻烦。所以BIP39协议应运而生,他是可以使用12-24单字(可以是英文、中文、日文等等语言)来帮助用户更好的保存seed。一般我们使用长度为12个的英文单词来生成BIP39的内容,这串单词被称为mnemonic code,中文名叫助记词。

BIP-39 词典

可以在bitcoin/bips下的bip-0039中来获取助记词字典,现在已经支持简体中文、繁体中文、英文、法文、意大利文、日文、韩文、西班牙文每种2048个词来生成助记词。

## BIP-39 生成助记词流程

助记词钱包是通过BIP-39中定义的标准化过程自动生成的,钱包从熵源开始,增加校验和,然后将熵映射到字典列表中。

  • 1.创建一个128-256位的随机序列(熵)

  • 2.提出SHA256哈希的前几位(熵长/32),就可以创建一个随机序列的校验和。

  • 3.将校验和添加到随机序列的末尾。

  • 4.将序列划分为包含11位的不同部分。

  • 5.将每个包含11位部分的值与一个预先定义的2048个单词的字典做对应。

  • 6.生成的有顺序的单词组就是助记词。

BIP39_1.PNG

| 熵(bits) | 校验和(bits) | 熵+校验和(bits) | 助记词长度(单词个数)|

| --- | --- | --- | --- |

| 128 | 4 | 132 | 12 |

| 160 | 5 | 165 | 15 |

| 192 | 6 | 198 | 18 |

| 224 | 7 | 231 | 21 |

| 256 | 8 | 264 | 24 |

使用OS代码生成BIP-39 助记词

引入库

首先肯定是引入iOS中哈希需要用到的库


#import <CommonCrypto/CommonHMAC.h>

#import <CommonCrypto/CommonKeyDerivation.h>

生成随机熵

我们可以使用SecRandomCopyBytes()函数来生成一个随机的NSData比特组


- (NSString *)generateMnemonicString:(NSNumber *)strlength language:(NSString *)language

{

 //输入长度必须为128、160、192、224、256

 if([strlength integerValue] % 32 != 0)

 {

 [NSException raise:@"Strength must be divisible by 32" format:@"Strength Was: %@",strlength];

 }

 //创建比特数组

 NSMutableData *bytes = [NSMutableData dataWithLength:([strlength integerValue]/8)];

 //生成随机data

 int status = SecRandomCopyBytes(kSecRandomDefault, bytes.length, bytes.mutableBytes);

 //如果生成成功

 if(status == 0)

 {

 NSString *hexString = [bytes my_hexString];

 return [self mnemonicStringFromRandomHexString:hexString language:language];

 }

 else

 {

 [NSException raise:@"Unable to get random data!" format:@"Unable to get random data!"];

 }

 return nil;

}

生成助记词

生成好随机的熵之后,我们就可以通过随机熵的内容根据256哈希计算需要使用的单词列,然后在单词表中查找出需要的单词来。


- (NSString *)mnemonicStringFromRandomHexString:(NSString *)seed language:(NSString *)language

{

 //将16进制转换为NSData

 NSData *seedData = [seed my_dataFromHexString];

 //计算 sha256 哈希

 NSMutableData *hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];

 CC_SHA256(seedData.bytes, (int)seedData.length, hash.mutableBytes);

 NSMutableArray *checkSumBits = [NSMutableArray arrayWithArray:[[NSData dataWithData:hash] my_hexToBitArray]];

 NSMutableArray *seedBits = [NSMutableArray arrayWithArray:[seedData my_hexToBitArray]];

 for(int i = 0 ; i < (int)seedBits.count / 32 ; i++)

 {

 [seedBits addObject:checkSumBits[i]];

 }

 NSString *path = [NSString stringWithFormat:@"%@/%@.txt",[[NSBundle mainBundle] bundlePath], language];

 NSString *fileText = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];

 NSArray *lines = [fileText componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];

 NSMutableArray *words = [NSMutableArray arrayWithCapacity:(int)seedBits.count / 11];

 for(int i = 0 ; i < (int)seedBits.count / 11 ; i++)

 {

 NSUInteger wordNumber = strtol([[[seedBits subarrayWithRange:NSMakeRange(i * 11, 11)] componentsJoinedByString:@""] UTF8String], NULL, 2);

 [words addObject:lines[wordNumber]];

 }

 return [words componentsJoinedByString:@" "];

}

需要的支持

其中我们需要几个辅助性操作:

字符串转换为16进制


//将字符串转换为16进制

- (NSString *)my_hexString

{

 const unsigned char *dataBuffer = (const unsigned char *)[self bytes];

 //如果buffer不存在

 if(!dataBuffer)

 {

 return [NSString string];

 }

 NSUInteger dataLength = [self length];

 NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];

 for(int i = 0 ; i < dataLength ; ++i)

 {

 [hexString appendString:[NSString stringWithFormat:@"%02lx",(unsigned long)dataBuffer[i]]];

 }

 return [NSString stringWithString:hexString];

}

16进制转换为比特数组


- (NSArray *)my_hexToBitArray

{

 NSMutableArray *bitArray = [NSMutableArray arrayWithCapacity:(int)self.length * 8];

 NSString *hexStr = [self my_hexString];

 for(NSUInteger i = 0 ; i < [hexStr length] ; i++)

 {

 NSString *bin = [self my_hexToBinary:[hexStr characterAtIndex:i]];

 for(NSUInteger j = 0 ; j < bin.length ; j++)

 {

 [bitArray addObject:@([[NSString stringWithFormat:@"%C",[bin characterAtIndex:j]] intValue])];

 }

 }

 return [NSArray arrayWithArray:bitArray];

}

- (NSString *)my_hexToBinary:(unichar)value

{

 switch (value)

 {

 case '0': return @"0000";

 case '1': return @"0001";

 case '2': return @"0010";

 case '3': return @"0011";

 case '4': return @"0100";

 case '5': return @"0101";

 case '6': return @"0110";

 case '7': return @"0111";

 case '8': return @"1000";

 case '9': return @"1001";

 case 'a':

 case 'A':

 return @"1010";

 case 'b':

 case 'B':

 return @"1011";

 case 'c':

 case 'C':

 return @"1100";

 case 'd':

 case 'D':

 return @"1101";

 case 'e':

 case 'E':

 return @"1110";

 case 'f':

 case 'F':

 return @"1111";

 }

 return @"-1";

}

16进制字符串转换为NSData


//将16进制字符串转换为NSData

- (NSData *)my_dataFromHexString

{

 const char *chars = [self UTF8String];

 int i = 0, len = (int)self.length;

 NSMutableData *data = [NSMutableData dataWithCapacity:len/2.0];

 char byteChars[3] = {'\0','\0','\0'};

 unsigned long wholeByte;

 while (i < len)

 {

 byteChars[0] = chars[i++];

 byteChars[1] = chars[i++];

 wholeByte = strtoul(byteChars, NULL, 16);

 [data appendBytes:&wholeByte length:1];

 }

 return data;

}

调用

OK,这些关键的内容都写好之后,只需要调用最开始的生成随机字符的函数,指定好长度和助记词语言就可以根据BIP-39生成助记词了。


 NSString *mnemonicString = [self generateMnemonicString:@128 language:@"english"];

Demo

Demo地址在这里

参考文档

bip-0044.mediawiki

BIP32, BIP39, BIP44

Mnemonic Code Converter

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

推荐阅读更多精彩内容