Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added BTC256 for holding hashes in fixed-length buffers
- Loading branch information
Showing
8 changed files
with
732 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// CoreBitcoin by Oleg Andreev <oleganza@gmail.com>, WTFPL. | ||
|
||
void BTC256RunAllTests(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
// CoreBitcoin by Oleg Andreev <oleganza@gmail.com>, WTFPL. | ||
|
||
#import "BTC256+Tests.h" | ||
#import "BTC256.h" | ||
#import "BTCData.h" | ||
|
||
void BTC256TestChunkSize() | ||
{ | ||
NSCAssert(sizeof(BTC160) == 20, @"160-bit struct should by 160 bit long"); | ||
NSCAssert(sizeof(BTC256) == 32, @"256-bit struct should by 256 bit long"); | ||
NSCAssert(sizeof(BTC512) == 64, @"512-bit struct should by 512 bit long"); | ||
} | ||
|
||
void BTC256TestNull() | ||
{ | ||
NSCAssert([NSStringFromBTC160(BTC160Null) isEqualTo:@"82963d5edd842f1e6bd2b6bc2e9a97a40a7d8652"], @"null hash should be correct"); | ||
NSCAssert([NSStringFromBTC256(BTC256Null) isEqualTo:@"d1007a1fe826e95409e21595845f44c3b9411d5285b6b5982285aabfa5999a5e"], @"null hash should be correct"); | ||
NSCAssert([NSStringFromBTC512(BTC512Null) isEqualTo:@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f0363e01b5d7a53c4a2e5a76d283f3e4a04d28ab54849c6e3e874ca31128bcb759e1"], @"null hash should be correct"); | ||
} | ||
|
||
void BTC256TestOne() | ||
{ | ||
BTC256 one = BTC256Zero; | ||
one.words64[0] = 1; | ||
NSCAssert([NSStringFromBTC256(one) isEqual:@"0100000000000000000000000000000000000000000000000000000000000000"], @""); | ||
} | ||
|
||
void BTC256TestEqual() | ||
{ | ||
NSCAssert(BTC256Equal(BTC256Null, BTC256Null), @"equal"); | ||
NSCAssert(BTC256Equal(BTC256Zero, BTC256Zero), @"equal"); | ||
NSCAssert(BTC256Equal(BTC256Max, BTC256Max), @"equal"); | ||
|
||
NSCAssert(!BTC256Equal(BTC256Zero, BTC256Null), @"not equal"); | ||
NSCAssert(!BTC256Equal(BTC256Zero, BTC256Max), @"not equal"); | ||
NSCAssert(!BTC256Equal(BTC256Max, BTC256Null), @"not equal"); | ||
} | ||
|
||
void BTC256TestCompare() | ||
{ | ||
NSCAssert(BTC256Compare(BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036"), | ||
BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036")) == NSOrderedSame, @"ordered same"); | ||
|
||
NSCAssert(BTC256Compare(BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f035"), | ||
BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036")) == NSOrderedAscending, @"ordered asc"); | ||
|
||
NSCAssert(BTC256Compare(BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f037"), | ||
BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036")) == NSOrderedDescending, @"ordered asc"); | ||
|
||
NSCAssert(BTC256Compare(BTC256FromNSString(@"61ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036"), | ||
BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036")) == NSOrderedAscending, @"ordered same"); | ||
|
||
NSCAssert(BTC256Compare(BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036"), | ||
BTC256FromNSString(@"61ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036")) == NSOrderedDescending, @"ordered same"); | ||
|
||
} | ||
|
||
void BTC256TestInverse() | ||
{ | ||
BTC256 chunk = BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036"); | ||
BTC256 chunk2 = BTC256Inverse(chunk); | ||
|
||
NSCAssert(!BTC256Equal(chunk, chunk2), @"not equal"); | ||
NSCAssert(BTC256Equal(chunk, BTC256Inverse(chunk2)), @"equal"); | ||
|
||
NSCAssert(chunk2.words64[0] == ~chunk.words64[0], @"bytes are inversed"); | ||
NSCAssert(chunk2.words64[1] == ~chunk.words64[1], @"bytes are inversed"); | ||
NSCAssert(chunk2.words64[2] == ~chunk.words64[2], @"bytes are inversed"); | ||
NSCAssert(chunk2.words64[3] == ~chunk.words64[3], @"bytes are inversed"); | ||
|
||
NSCAssert(BTC256Equal(BTC256Zero, BTC256AND(chunk, chunk2)), @"(a & ~a) == 000000..."); | ||
NSCAssert(BTC256Equal(BTC256Max, BTC256OR(chunk, chunk2)), @"(a | ~a) == 111111..."); | ||
NSCAssert(BTC256Equal(BTC256Max, BTC256XOR(chunk, chunk2)), @"(a ^ ~a) == 111111..."); | ||
} | ||
|
||
void BTC256TestSwap() | ||
{ | ||
BTC256 chunk = BTC256FromNSString(@"62ce64dd92836e6e99d83eee3f623652f6049cf8c22272f295b262861738f036"); | ||
BTC256 chunk2 = BTC256Swap(chunk); | ||
NSCAssert([BTCReversedData(NSDataFromBTC256(chunk)) isEqual:NSDataFromBTC256(chunk2)], @"swap should reverse all bytes"); | ||
|
||
NSCAssert(chunk2.words64[0] == OSSwapConstInt64(chunk.words64[3]), @"swap should reverse all bytes"); | ||
NSCAssert(chunk2.words64[1] == OSSwapConstInt64(chunk.words64[2]), @"swap should reverse all bytes"); | ||
NSCAssert(chunk2.words64[2] == OSSwapConstInt64(chunk.words64[1]), @"swap should reverse all bytes"); | ||
NSCAssert(chunk2.words64[3] == OSSwapConstInt64(chunk.words64[0]), @"swap should reverse all bytes"); | ||
} | ||
|
||
void BTC256TestAND() | ||
{ | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Max, BTC256Max), BTC256Max), @"1 & 1 == 1"); | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Max, BTC256Zero), BTC256Zero), @"1 & 0 == 0"); | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Zero, BTC256Max), BTC256Zero), @"0 & 1 == 0"); | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Zero, BTC256Null), BTC256Zero), @"0 & x == 0"); | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Null, BTC256Zero), BTC256Zero), @"x & 0 == 0"); | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Max, BTC256Null), BTC256Null), @"1 & x == x"); | ||
NSCAssert(BTC256Equal(BTC256AND(BTC256Null, BTC256Max), BTC256Null), @"x & 1 == x"); | ||
} | ||
|
||
void BTC256TestOR() | ||
{ | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Max, BTC256Max), BTC256Max), @"1 | 1 == 1"); | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Max, BTC256Zero), BTC256Max), @"1 | 0 == 1"); | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Zero, BTC256Max), BTC256Max), @"0 | 1 == 1"); | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Zero, BTC256Null), BTC256Null), @"0 | x == x"); | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Null, BTC256Zero), BTC256Null), @"x | 0 == x"); | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Max, BTC256Null), BTC256Max), @"1 | x == 1"); | ||
NSCAssert(BTC256Equal(BTC256OR(BTC256Null, BTC256Max), BTC256Max), @"x | 1 == 1"); | ||
} | ||
|
||
void BTC256TestXOR() | ||
{ | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Max, BTC256Max), BTC256Zero), @"1 ^ 1 == 0"); | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Max, BTC256Zero), BTC256Max), @"1 ^ 0 == 1"); | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Zero, BTC256Max), BTC256Max), @"0 ^ 1 == 1"); | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Zero, BTC256Null), BTC256Null), @"0 ^ x == x"); | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Null, BTC256Zero), BTC256Null), @"x ^ 0 == x"); | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Max, BTC256Null), BTC256Inverse(BTC256Null)), @"1 ^ x == ~x"); | ||
NSCAssert(BTC256Equal(BTC256XOR(BTC256Null, BTC256Max), BTC256Inverse(BTC256Null)), @"x ^ 1 == ~x"); | ||
} | ||
|
||
void BTC256TestConcat() | ||
{ | ||
BTC512 concat = BTC512Concat(BTC256Null, BTC256Max); | ||
NSCAssert([NSStringFromBTC512(concat) isEqualTo:@"d1007a1fe826e95409e21595845f44c3b9411d5285b6b5982285aabfa5999a5e" | ||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"], @"should concatenate properly"); | ||
|
||
concat = BTC512Concat(BTC256Max, BTC256Null); | ||
NSCAssert([NSStringFromBTC512(concat) isEqualTo:@"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" | ||
"d1007a1fe826e95409e21595845f44c3b9411d5285b6b5982285aabfa5999a5e"], @"should concatenate properly"); | ||
|
||
} | ||
|
||
void BTC256TestConvertToData() | ||
{ | ||
// TODO... | ||
} | ||
|
||
void BTC256TestConvertToString() | ||
{ | ||
// Too short string should yield null value. | ||
BTC256 chunk = BTC256FromNSString(@"000095409e215952" | ||
"85b6b5982285aabf" | ||
"a5999a5e845f44c3" | ||
"b9411d5d1007a1"); | ||
NSCAssert(BTC256Equal(chunk, BTC256Null), @"too short string => null"); | ||
|
||
chunk = BTC256FromNSString(@"000095409e215952" | ||
"85b6b5982285aabf" | ||
"a5999a5e845f44c3" | ||
"b9411d5d1007a1b166"); | ||
NSCAssert(chunk.words64[0] == OSSwapBigToHostConstInt64(0x000095409e215952), @"parse correctly"); | ||
NSCAssert(chunk.words64[1] == OSSwapBigToHostConstInt64(0x85b6b5982285aabf), @"parse correctly"); | ||
NSCAssert(chunk.words64[2] == OSSwapBigToHostConstInt64(0xa5999a5e845f44c3), @"parse correctly"); | ||
NSCAssert(chunk.words64[3] == OSSwapBigToHostConstInt64(0xb9411d5d1007a1b1), @"parse correctly"); | ||
|
||
NSCAssert([NSStringFromBTC256(chunk) isEqualTo:@"000095409e215952" | ||
"85b6b5982285aabf" | ||
"a5999a5e845f44c3" | ||
"b9411d5d1007a1b1"], @"should serialize to the same string"); | ||
} | ||
|
||
|
||
void BTC256RunAllTests() | ||
{ | ||
BTC256TestChunkSize(); | ||
BTC256TestNull(); | ||
BTC256TestOne(); | ||
BTC256TestEqual(); | ||
BTC256TestCompare(); | ||
BTC256TestInverse(); | ||
BTC256TestSwap(); | ||
BTC256TestAND(); | ||
BTC256TestOR(); | ||
BTC256TestXOR(); | ||
BTC256TestConcat(); | ||
BTC256TestConvertToData(); | ||
BTC256TestConvertToString(); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
// CoreBitcoin by Oleg Andreev <oleganza@gmail.com>, WTFPL. | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
// A set of ubiquitous types and functions to deal with fixed-length chunks of data | ||
// (160-bit, 256-bit and 512-bit). These are relevant almost always to hashes, | ||
// but there's no hash-specific about them. | ||
// The purpose of these is to avoid dynamic memory allocations via NSData when | ||
// we need to move exactly 32 bytes around. | ||
// | ||
// We don't call these BTCFixedData256 because these types are way too ubiquituous | ||
// in CoreBitcoin to have such an explicit name. | ||
// | ||
// Somewhat similar to uint256 in bitcoind, but here we don't try | ||
// to pretend that these are integers and then allow arithmetic on them | ||
// and create a mess with the byte order. | ||
// Use BTCBigNumber to do arithmetic on big numbers and convert | ||
// to bignum format explicitly. | ||
// BTCBigNumber has API for converting BTC256 to a big int. | ||
// | ||
// We also declare BTC160 and BTC512 for use with RIPEMD-160, SHA-1 and SHA-512 hashes. | ||
|
||
|
||
// 1. Fixed-length types | ||
|
||
struct private_BTC160 | ||
{ | ||
// 160 bits can't be formed with 64-bit words, so we have to use 32-bit ones instead. | ||
uint32_t words32[5]; | ||
} __attribute__((packed)); | ||
typedef struct private_BTC160 BTC160; | ||
|
||
struct private_BTC256 | ||
{ | ||
// Since all modern CPUs are 64-bit (ARM is 64-bit starting with iPhone 5s), | ||
// we will use 64-bit words. | ||
uint64_t words64[4]; | ||
} __attribute__((aligned(1))); | ||
typedef struct private_BTC256 BTC256; | ||
|
||
struct private_BTC512 | ||
{ | ||
// Since all modern CPUs are 64-bit (ARM is 64-bit starting with iPhone 5s), | ||
// we will use 64-bit words. | ||
uint64_t words64[8]; | ||
} __attribute__((aligned(1))); | ||
typedef struct private_BTC512 BTC512; | ||
|
||
|
||
// 2. Constants | ||
|
||
// All-zero constants | ||
extern const BTC160 BTC160Zero; | ||
extern const BTC256 BTC256Zero; | ||
extern const BTC512 BTC512Zero; | ||
|
||
// All-one constants | ||
extern const BTC160 BTC160Max; | ||
extern const BTC256 BTC256Max; | ||
extern const BTC512 BTC512Max; | ||
|
||
// First 160 bits of SHA512("CoreBitcoin/BTC160Null") | ||
extern const BTC160 BTC160Null; | ||
|
||
// First 256 bits of SHA512("CoreBitcoin/BTC256Null") | ||
extern const BTC256 BTC256Null; | ||
|
||
// Value of SHA512("CoreBitcoin/BTC512Null") | ||
extern const BTC512 BTC512Null; | ||
|
||
|
||
// 3. Comparison | ||
|
||
BOOL BTC160Equal(BTC160 chunk1, BTC160 chunk2); | ||
BOOL BTC256Equal(BTC256 chunk1, BTC256 chunk2); | ||
BOOL BTC512Equal(BTC512 chunk1, BTC512 chunk2); | ||
|
||
NSComparisonResult BTC160Compare(BTC160 chunk1, BTC160 chunk2); | ||
NSComparisonResult BTC256Compare(BTC256 chunk1, BTC256 chunk2); | ||
NSComparisonResult BTC512Compare(BTC512 chunk1, BTC512 chunk2); | ||
|
||
|
||
// 4. Operations | ||
|
||
|
||
// Inverse (b = ~a) | ||
BTC160 BTC160Inverse(BTC160 chunk); | ||
BTC256 BTC256Inverse(BTC256 chunk); | ||
BTC512 BTC512Inverse(BTC512 chunk); | ||
|
||
// Swap byte order | ||
BTC160 BTC160Swap(BTC160 chunk); | ||
BTC256 BTC256Swap(BTC256 chunk); | ||
BTC512 BTC512Swap(BTC512 chunk); | ||
|
||
// Bitwise AND operation (a & b) | ||
BTC160 BTC160AND(BTC160 chunk1, BTC160 chunk2); | ||
BTC256 BTC256AND(BTC256 chunk1, BTC256 chunk2); | ||
BTC512 BTC512AND(BTC512 chunk1, BTC512 chunk2); | ||
|
||
// Bitwise OR operation (a | b) | ||
BTC160 BTC160OR(BTC160 chunk1, BTC160 chunk2); | ||
BTC256 BTC256OR(BTC256 chunk1, BTC256 chunk2); | ||
BTC512 BTC512OR(BTC512 chunk1, BTC512 chunk2); | ||
|
||
// Bitwise exclusive-OR operation (a ^ b) | ||
BTC160 BTC160XOR(BTC160 chunk1, BTC160 chunk2); | ||
BTC256 BTC256XOR(BTC256 chunk1, BTC256 chunk2); | ||
BTC512 BTC512XOR(BTC512 chunk1, BTC512 chunk2); | ||
|
||
// Concatenation of two 256-bit chunks | ||
BTC512 BTC512Concat(BTC256 chunk1, BTC256 chunk2); | ||
|
||
|
||
// 5. Conversion functions | ||
|
||
|
||
// Conversion to NSData | ||
NSData* NSDataFromBTC160(BTC160 chunk); | ||
NSData* NSDataFromBTC256(BTC256 chunk); | ||
NSData* NSDataFromBTC512(BTC512 chunk); | ||
|
||
// Conversion from NSData. | ||
// If NSData is not big enough, returns BTCHash{160,256,512}Null. | ||
BTC160 BTC160FromNSData(NSData* data); | ||
BTC256 BTC256FromNSData(NSData* data); | ||
BTC512 BTC512FromNSData(NSData* data); | ||
|
||
// Returns lowercase hex representation of the chunk | ||
NSString* NSStringFromBTC160(BTC160 chunk); | ||
NSString* NSStringFromBTC256(BTC256 chunk); | ||
NSString* NSStringFromBTC512(BTC512 chunk); | ||
|
||
// Conversion from hex NSString (lower- or uppercase). | ||
// If string is invalid or data is too short, returns BTCHash{160,256,512}Null. | ||
BTC160 BTC160FromNSString(NSString* string); | ||
BTC256 BTC256FromNSString(NSString* string); | ||
BTC512 BTC512FromNSString(NSString* string); | ||
|
||
|
||
|
Oops, something went wrong.