bool CBDecodeBase58Checked(CBBigInt * bi, char * str){ if(NOT CBDecodeBase58(bi, str)) { CBLogError("Memory failure in CBDecodeBase58."); return false; } if (bi->length < 4){ CBLogError("The string passed into CBDecodeBase58Checked decoded into data that was too short."); return false; } // Reverse bytes for checksum generation uint8_t * reversed = malloc(bi->length - 4); if (NOT reversed) { CBLogError("Cannot allocate %i bytes of memory in CBDecodeBase58Checked", bi->length - 4); return false; } for (uint8_t x = 4; x < bi->length; x++) reversed[bi->length - 1 - x] = bi->data[x]; // The checksum uses SHA-256, twice, for some reason unknown to man. uint8_t checksum[32]; uint8_t checksum2[32]; CBSha256(reversed, bi->length - 4, checksum); free(reversed); CBSha256(checksum, 32, checksum2); bool ok = true; for (uint8_t x = 0; x < 4; x++) if (checksum2[x] != bi->data[3-x]) ok = false; if (NOT ok){ CBLogError("The data passed to CBDecodeBase58Checked is invalid. Checksum does not match."); return false; } return true; }
void BRSendMessage(BRConnection *c, CBMessage *message, char *command) { /* partially adapted from examples/pingpong.c */ char header[24] = {0}; /* zeros help us out places */ memcpy(header + CB_MESSAGE_HEADER_TYPE, command, strlen(command)); uint8_t hash[32]; uint8_t hash2[32]; if (message->bytes) CBSha256(CBByteArrayGetData(message->bytes), message->bytes->length, hash); else { /* Get the checksum right -- handles problem where checksum not calculated * for messages with no payload */ CBSha256(NULL, 0, hash); } CBSha256(hash, 32, hash2); message->checksum[0] = hash2[0]; message->checksum[1] = hash2[1]; message->checksum[2] = hash2[2]; message->checksum[3] = hash2[3]; CBInt32ToArray(header, CB_MESSAGE_HEADER_NETWORK_ID, NETMAGIC); if (message->bytes) { CBInt32ToArray(header, CB_MESSAGE_HEADER_LENGTH, message->bytes->length); } memcpy(header + CB_MESSAGE_HEADER_CHECKSUM, message->checksum, 4); int sent = send(c->sock, header, 24, 0); if (sent < 0) { perror("send failed"); exit(1); } if (sent != 24) { fprintf(stderr, "send sent %d, not 24 bytes\n", sent); exit(1); } if (message->bytes) { sent = send(c->sock, message->bytes->sharedData->data + message->bytes->offset, message->bytes->length, 0); if (sent < 0) { perror("send failed"); exit(1); } if (sent != message->bytes->length) { fprintf(stderr, "send sent %d, not %d bytes\n", sent, message->bytes->length); exit(1); } } #ifdef BRDEBUG print_header(header); printf("message len: %d\n", message->bytes ? message->bytes->length : 0); printf("checksum: %x\n", *((uint32_t *) message->checksum)); print_hex(message->bytes); printf("\n"); #endif }
uint8_t * CBKeyPairGetHash(CBKeyPair * key){ if (!key->pubkey.hashSet) { uint8_t hash[32]; CBSha256(key->pubkey.key, 33, hash); CBRipemd160(hash, 32, key->pubkey.hash); } return key->pubkey.hash; }
CBMerkleNode * CBBuildMerkleTree(CBByteArray ** hashes, uint32_t numHashes){ CBMerkleNode * level = malloc(numHashes * sizeof(*level)); // Nodes on a level of the tree for processing. // Create nodes from the CBByteArray hashes for (uint32_t x = 0; x < numHashes; x++) { memcpy(level[x].hash, CBByteArrayGetData(hashes[x]), 32); level[x].left = NULL; level[x].right = NULL; } // Build each level upwards to the root uint8_t hash[32]; uint8_t cat[64]; CBMerkleNode * nextLevel = malloc((numHashes + 1)/2 * sizeof(*level)); for (uint32_t x = 0;;) { nextLevel[x/2].left = level + x; if (x == numHashes - 1) nextLevel[x/2].right = level + x; else nextLevel[x/2].right = level + x + 1; memcpy(cat, nextLevel[x/2].left->hash, 32); memcpy(cat + 32, nextLevel[x/2].right->hash, 32); // Double SHA256 CBSha256(cat, 64, hash); CBSha256(hash, 32, nextLevel[x/2].hash); x += 2; if (x >= numHashes) { // Finished level if (x > numHashes) // The number of hashes was odd. Increment to even numHashes++; numHashes /= 2; // Move to next level level = nextLevel; if (numHashes == 1) // Done, got the single root hash break; x = 0; nextLevel = malloc((numHashes + 1)/2 * sizeof(*level)); } } // Return last level which contains only the root node. return level; }
static void send_version() { CBByteArray *ip = CBNewByteArrayWithDataCopy((uint8_t [16]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 127, 0, 0, 1}, 16); CBByteArray *ua = CBNewByteArrayFromString("cmsc417versiona", '\00'); CBNetworkAddress * sourceAddr = CBNewNetworkAddress(0, ip, 0, CB_SERVICE_FULL_BLOCKS, false); int32_t vers = 70001; int nonce = rand(); CBVersion * version = CBNewVersion(vers, CB_SERVICE_FULL_BLOCKS, time(NULL), &peer->base, sourceAddr, nonce, ua, 0); CBMessage *message = CBGetMessage(version); char header[24]; memcpy(header + CB_MESSAGE_HEADER_TYPE, "version\0\0\0\0\0", 12); /* Compute length, serialized, and checksum */ uint32_t len = CBVersionCalculateLength(version); message->bytes = CBNewByteArrayOfSize(len); len = CBVersionSerialise(version, false); if (message->bytes) { // Make checksum uint8_t hash[32]; uint8_t hash2[32]; CBSha256(CBByteArrayGetData(message->bytes), message->bytes->length, hash); CBSha256(hash, 32, hash2); message->checksum[0] = hash2[0]; message->checksum[1] = hash2[1]; message->checksum[2] = hash2[2]; message->checksum[3] = hash2[3]; } CBInt32ToArray(header, CB_MESSAGE_HEADER_NETWORK_ID, NETMAGIC); CBInt32ToArray(header, CB_MESSAGE_HEADER_LENGTH, message->bytes->length); // Checksum memcpy(header + CB_MESSAGE_HEADER_CHECKSUM, message->checksum, 4); // Send the header send(sd, header, 24, 0); // Send the message printf("message len: %d\n", message->bytes->length); printf("checksum: %x\n", *((uint32_t *) message->checksum)); send(sd, message->bytes->sharedData->data+message->bytes->offset, message->bytes->length, 0); print_hex(message->bytes); }
bool CBInitAddressFromRIPEMD160Hash(CBAddress * self,uint8_t networkCode,uint8_t * hash,bool cacheString,void (*logError)(char *,...)){ // Build address and then complete intitialisation with CBVersionChecksumBytes uint8_t * data = malloc(25); // 1 Network byte, 20 hash bytes, 4 checksum bytes. if (NOT data) { logError("Cannot allocate 25 bytes of memory in CBInitAddressFromRIPEMD160Hash\n"); return false; } // Set network byte data[0] = networkCode; // Move hash memmove(data+1, hash, 20); // Make checksum and move it into address uint8_t checksum[32]; uint8_t checksum2[32]; CBSha256(data,21,checksum); CBSha256(checksum,32,checksum2); memmove(data+21, checksum2, 4); // Initialise CBVersionChecksumBytes if (NOT CBInitVersionChecksumBytesFromBytes(CBGetVersionChecksumBytes(self), data, 25,cacheString, logError)) return false; return true; }
bool CBHDKeyGenerateMaster(CBHDKey * key, bool production){ key->versionBytes = production ? CB_HD_KEY_VERSION_PROD_PRIVATE : CB_HD_KEY_VERSION_TEST_PRIVATE; key->childID.priv = false; // It is private but the BIP specifies 0 for the child number. key->childID.childNumber = 0; key->depth = 0; memset(key->parentFingerprint, 0, 4); if (!CBKeyPairGenerate(key->keyPair)) { CBLogError("Could not generate the master key"); return false; } // Make chain code by hashing private key CBSha256(CBHDKeyGetPrivateKey(key), 32, key->chainCode); return true; }
CBGetHashReturn CBTransactionGetInputHashForSignature(void * vself, CBByteArray * prevOutSubScript, uint32_t input, CBSignType signType, uint8_t * hash){ CBTransaction * self= vself; if (self->inputNum < input + 1) { CBLogError("Receiving transaction hash to sign cannot be done for because the input index goes past the number of inputs."); return CB_TX_HASH_BAD; } uint8_t last5Bits = (signType & 0x1f); // For some reason this is what the C++ client does. CBVarInt prevOutputSubScriptVarInt = CBVarIntFromUInt64(prevOutSubScript->length); uint32_t sizeOfData = 12 + prevOutSubScript->length + prevOutputSubScriptVarInt.size; // Version, lock time and the sign type make up 12 bytes. if (signType & CB_SIGHASH_ANYONECANPAY) { sizeOfData += 41; // Just this one input. 32 bytes for outPointerHash, 4 for outPointerIndex, 4 for sequence and one for the *inputNum* var int }else{ sizeOfData += CBVarIntSizeOf(self->inputNum) + self->inputNum * 41 - 1; // All inputs with 1 byte var int except one. } if (last5Bits == CB_SIGHASH_NONE){ sizeOfData++; // Just for the CBVarInt and no outputs. }else if ((signType & 0x1f) == CB_SIGHASH_SINGLE){ if (self->outputNum < input + 1) { CBLogError("Receiving transaction hash to sign cannot be done for CB_SIGHASH_SINGLE because there are not enough outputs."); return CB_TX_HASH_BAD; } sizeOfData += CBVarIntSizeOf(input + 1) + input * 9; // For outputs up to the input index // The size for the output at the input index. uint32_t len = CBGetByteArray(self->outputs[input]->scriptObject)->length; sizeOfData += 8 + CBVarIntSizeOf(len) + len; }else{ // All outputs. Default to SIGHASH_ALL sizeOfData += CBVarIntSizeOf(self->outputNum); for (uint32_t x = 0; x < self->outputNum; x++) { uint32_t len = CBGetByteArray(self->outputs[x]->scriptObject)->length; sizeOfData += 8 + CBVarIntSizeOf(len) + len; } } CBByteArray * data = CBNewByteArrayOfSize(sizeOfData); if (NOT data) return CB_TX_HASH_ERR; CBByteArraySetInt32(data, 0, self->version); // Copy input data. Scripts are not copied for the inputs. uint32_t cursor; if (signType & CB_SIGHASH_ANYONECANPAY) { CBVarIntEncode(data, 4, CBVarIntFromUInt64(1)); // Only the input the signature is for. CBByteArrayCopyByteArray(data, 5, self->inputs[input]->prevOut.hash); CBByteArraySetInt32(data, 37, self->inputs[input]->prevOut.index); // Add prevOutSubScript CBVarIntEncode(data, 41, prevOutputSubScriptVarInt); cursor = 41 + prevOutputSubScriptVarInt.size; CBByteArrayCopyByteArray(data, cursor, prevOutSubScript); cursor += prevOutSubScript->length; CBByteArraySetInt32(data, cursor, self->inputs[input]->sequence); cursor += 4; }else{ CBVarInt inputNum = CBVarIntFromUInt64(self->inputNum); CBVarIntEncode(data, 4, inputNum); cursor = 4 + inputNum.size; for (uint32_t x = 0; x < self->inputNum; x++) { CBByteArrayCopyByteArray(data, cursor, self->inputs[x]->prevOut.hash); cursor += 32; CBByteArraySetInt32(data, cursor, self->inputs[x]->prevOut.index); cursor += 4; // Add prevOutSubScript if the input is for the signature. if (x == input) { CBVarIntEncode(data, cursor, prevOutputSubScriptVarInt); cursor += prevOutputSubScriptVarInt.size; CBByteArrayCopyByteArray(data, cursor, prevOutSubScript); cursor += prevOutSubScript->length; }else{ CBVarIntEncode(data, cursor, CBVarIntFromUInt64(0)); cursor++; } if ((signType == CB_SIGHASH_NONE || signType == CB_SIGHASH_SINGLE) && x != input) { CBByteArraySetInt32(data, cursor, 0); } else // SIGHASH_ALL or input index for signing sequence CBByteArraySetInt32(data, cursor, self->inputs[x]->sequence); cursor += 4; } } // Copy output data if (last5Bits == CB_SIGHASH_NONE){ CBVarInt varInt = CBVarIntFromUInt64(0); CBVarIntEncode(data, cursor, varInt); cursor++; }else if (last5Bits == CB_SIGHASH_SINGLE){ CBVarInt varInt = CBVarIntFromUInt64(input + 1); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; for (uint32_t x = 0; x < input; x++) { CBByteArraySetInt64(data, cursor, CB_OUTPUT_VALUE_MINUS_ONE); cursor += 8; CBVarIntEncode(data, cursor, CBVarIntFromUInt64(0)); cursor++; } CBByteArraySetInt64(data, cursor, self->outputs[input]->value); cursor += 8; varInt = CBVarIntFromUInt64(CBGetByteArray(self->outputs[input]->scriptObject)->length); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; CBByteArrayCopyByteArray(data, cursor, CBGetByteArray(self->outputs[input]->scriptObject)); cursor += varInt.val; }else{ // SIGHASH_ALL CBVarInt varInt = CBVarIntFromUInt64(self->outputNum); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; for (uint32_t x = 0; x < self->outputNum; x++) { CBByteArraySetInt64(data, cursor, self->outputs[x]->value); cursor += 8; varInt = CBVarIntFromUInt64(CBGetByteArray(self->outputs[x]->scriptObject)->length); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; CBByteArrayCopyByteArray(data, cursor, CBGetByteArray(self->outputs[x]->scriptObject)); cursor += varInt.val; } } // Set lockTime CBByteArraySetInt32(data, cursor, self->lockTime); CBByteArraySetInt32(data, cursor + 4, signType); assert(sizeOfData == cursor + 8); // Must always be like this uint8_t firstHash[32]; CBSha256(CBByteArrayGetData(data), sizeOfData, firstHash); CBSha256(firstHash, 32, hash); return CB_TX_HASH_OK; }
void CBTransactionCalculateHash(CBTransaction * self, uint8_t * hash){ uint8_t * data = CBByteArrayGetData(CBGetMessage(self)->bytes); uint8_t hash2[32]; CBSha256(data, CBGetMessage(self)->bytes->length, hash2); CBSha256(hash2, 32, hash); }
unsigned long long int CBSecureRandomInteger(CBDepObject gen){ CBSha256(gen.ptr, 32, gen.ptr); unsigned long long int i; memcpy(&i, gen.ptr, 8); return i; }
int main(){ unsigned int s = (unsigned int)time(NULL); s = 1337544566; printf("Session = %ui\n",s); srand(s); // Test deserialisation of real alert uint8_t data[188] = { 0x73, // Length of payload 0x01,0x00,0x00,0x00, // Version 1 0x37,0x66,0x40,0x4F,0x00,0x00,0x00,0x00, // Relay until 1329620535 0xB3,0x05,0x43,0x4F,0x00,0x00,0x00,0x00, // Expires at 1329792435 0xF2,0x03,0x00,0x00, // ID 1010 0xF1,0x03,0x00,0x00, // Cancel < 1009 0x00, // No more IDs 0x10,0x27,0x00,0x00, // Min version 10000 0x48,0xee,0x00,0x00, // Max version 61000 0x00, // No user agents 0x64,0x00,0x00,0x00, // Priority 100 0x00, // Empty hidden comment 0x46, // Displayed comment is 70 characters long // "See bitcoin.org/feb20 if you have trouble connecting after 20 February" 0x53,0x65,0x65,0x20,0x62,0x69,0x74,0x63,0x6F,0x69,0x6E,0x2E,0x6F,0x72,0x67,0x2F,0x66,0x65,0x62,0x32,0x30,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x20,0x68,0x61,0x76,0x65,0x20,0x74,0x72,0x6F,0x75,0x62,0x6C,0x65,0x20,0x63,0x6F,0x6E,0x6E,0x65,0x63,0x74,0x69,0x6E,0x67,0x20,0x61,0x66,0x74,0x65,0x72,0x20,0x32,0x30,0x20,0x46,0x65,0x62,0x72,0x75,0x61,0x72,0x79, 0x00, // No reserved // Signature 0x47, // Signature is 71 bytes long 0x30,0x45,0x02,0x21,0x00,0x83,0x89,0xdf,0x45,0xF0,0x70,0x3F,0x39,0xEC,0x8C,0x1C,0xC4,0x2C,0x13,0x81,0x0F,0xFC,0xAE,0x14,0x99,0x5B,0xB6,0x48,0x34,0x02,0x19,0xE3,0x53,0xB6,0x3B,0x53,0xEB,0x02,0x20,0x09,0xEC,0x65,0xE1,0xC1,0xAA,0xEE,0xC1,0xFD,0x33,0x4C,0x6B,0x68,0x4B,0xDE,0x2B,0x3F,0x57,0x30,0x60,0xD5,0xb7,0x0C,0x3A,0x46,0x72,0x33,0x26,0xE4,0xE8,0xA4,0xF1 }; CBByteArray * bytes = CBNewByteArrayWithDataCopy(data, 188, logError); CBAlert * alert = CBNewAlertFromData(bytes, logError); if(CBAlertDeserialise(alert) != 188){ printf("DESERIALISATION LEN FAIL\n"); return 1; } if (alert->version != 1) { printf("DESERIALISATION VERSION FAIL\n"); return 1; } if (alert->relayUntil != 1329620535) { printf("DESERIALISATION RELAY UNTIL FAIL\n"); return 1; } if (alert->expiration != 1329792435) { printf("DESERIALISATION EXPIRATION FAIL\n"); return 1; } if (alert->ID != 1010) { printf("DESERIALISATION ID FAIL\n"); return 1; } if (alert->cancel != 1009) { printf("DESERIALISATION CANCEL FAIL\n"); return 1; } if (alert->setCancelNum != 0) { printf("DESERIALISATION SET CANCEL NUM FAIL\n"); return 1; } if (alert->setCancel != NULL) { printf("DESERIALISATION SET CANCEL FAIL\n"); return 1; } if (alert->minVer != 10000) { printf("DESERIALISATION MIN VERSION FAIL\n"); return 1; } if (alert->maxVer != 61000) { printf("DESERIALISATION MAX VERSION FAIL\n"); return 1; } if (alert->userAgentNum != 0) { printf("DESERIALISATION USER AGENT NUM FAIL\n"); return 1; } if (alert->userAgents != NULL) { printf("DESERIALISATION USER AGENTS FAIL\n"); return 1; } if (alert->priority != 100) { printf("DESERIALISATION PRIORITY FAIL\n"); return 1; } if (alert->hiddenComment != NULL) { printf("DESERIALISATION HIDDEN COMMENT FAIL\n"); return 1; } if (memcmp(CBByteArrayGetData(alert->displayedComment),"See bitcoin.org/feb20 if you have trouble connecting after 20 February",70)) { printf("DESERIALISATION DISPLAYED COMMENT FAIL\n0x"); char * d = (char *)CBByteArrayGetData(alert->displayedComment); for (int x = 0; x < 70; x++) { printf("%c",d[x]); } printf("\n!=\nSee bitcoin.org/feb20 if you have trouble connecting after 20 February\n"); return 1; } if (alert->reserved != NULL) { printf("DESERIALISATION RESERVED FAIL\n"); return 1; } // Check signature CBByteArray * payload = CBAlertGetPayload(alert); uint8_t hash1[32]; CBSha256(CBByteArrayGetData(payload),payload->length,hash1); uint8_t hash2[32]; CBSha256(hash1, 32,hash2); if (NOT CBEcdsaVerify(CBByteArrayGetData(alert->signature),alert->signature->length,hash2,(uint8_t [65]){0x04,0xFC,0x97,0x02,0x84,0x78,0x40,0xAA,0xF1,0x95,0xDE,0x84,0x42,0xEB,0xEC,0xED,0xF5,0xB0,0x95,0xCD,0xBB,0x9B,0xC7,0x16,0xBD,0xA9,0x11,0x09,0x71,0xB2,0x8A,0x49,0xE0,0xEA,0xD8,0x56,0x4F,0xF0,0xDB,0x22,0x20,0x9E,0x03,0x74,0x78,0x2C,0x09,0x3B,0xB8,0x99,0x69,0x2D,0x52,0x4E,0x9D,0x6A,0x69,0x56,0xE7,0xC5,0xEC,0xBC,0xD6,0x82,0x84},65)) { printf("DESERIALISATION SIG FAIL\n"); return 1; } CBReleaseObject(payload); // Test serialisation memset(CBByteArrayGetData(bytes), 0, 188); CBReleaseObject(alert->displayedComment); alert->displayedComment = CBNewByteArrayWithDataCopy((uint8_t *)"See bitcoin.org/feb20 if you have trouble connecting after 20 February", 70, logError); CBReleaseObject(alert->signature); alert->signature = CBNewByteArrayWithDataCopy((uint8_t []){0x30,0x45,0x02,0x21,0x00,0x83,0x89,0xdf,0x45,0xF0,0x70,0x3F,0x39,0xEC,0x8C,0x1C,0xC4,0x2C,0x13,0x81,0x0F,0xFC,0xAE,0x14,0x99,0x5B,0xB6,0x48,0x34,0x02,0x19,0xE3,0x53,0xB6,0x3B,0x53,0xEB,0x02,0x20,0x09,0xEC,0x65,0xE1,0xC1,0xAA,0xEE,0xC1,0xFD,0x33,0x4C,0x6B,0x68,0x4B,0xDE,0x2B,0x3F,0x57,0x30,0x60,0xD5,0xb7,0x0C,0x3A,0x46,0x72,0x33,0x26,0xE4,0xE8,0xA4,0xF1}, 71, logError); CBAlertSerialisePayload(alert); if(CBAlertSerialiseSignature(alert, 116) != 188){ printf("SERIALISATION LEN FAIL\n"); return 1; } if (memcmp(data, CBByteArrayGetData(bytes), 188)) { printf("SERIALISATION FAIL\n0x"); uint8_t * d = CBByteArrayGetData(bytes); for (int x = 0; x < 188; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); for (int x = 0; x < 188; x++) { printf("%.2X",data[x]); } return 1; } CBReleaseObject(alert); CBReleaseObject(bytes); return 0; }
uint64_t CBSecureRandomInteger(uint64_t gen){ CBSha256((uint8_t *)gen, 32, (void *)gen); uint64_t i; memcpy(&i, (void *)gen, 8); return i; }
void CBBlockCalculateHash(CBBlock * self, uint8_t * hash){ uint8_t * headerData = CBByteArrayGetData(CBGetMessage(self)->bytes); uint8_t hash2[32]; CBSha256(headerData, 80, hash2); CBSha256(hash2, 32, hash); }