예제 #1
0
uint32_t CBTransactionOutputSerialise(CBTransactionOutput * self){
	CBByteArray * bytes = CBGetMessage(self)->bytes;
	if (NOT bytes) {
		CBLogError("Attempting to serialise a CBTransactionInput with no bytes.");
		return 0;
	}
	if (NOT self->scriptObject){
		CBLogError("Attempting to serialise a CBTransactionOutput without scriptObject.");
		return 0;
	}
	CBVarInt scriptLen = CBVarIntFromUInt64(CBGetByteArray(self->scriptObject)->length);
	uint32_t reqLen = 8 + scriptLen.size + CBGetByteArray(self->scriptObject)->length;
	if (bytes->length < reqLen) {
		CBLogError("Attempting to serialise a CBTransactionOutput with less bytes than required. %i < %i", bytes->length, reqLen);
		return 0;
	}
	// Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory.
	CBByteArraySetInt64(bytes, 0, self->value);
	CBVarIntEncode(bytes, 8, scriptLen);
	CBByteArrayCopyByteArray(bytes, 8 + scriptLen.size, CBGetByteArray(self->scriptObject));
	CBByteArrayChangeReference(CBGetByteArray(self->scriptObject), bytes, 8 + scriptLen.size);
	// Ensure length is correct
	bytes->length = reqLen;
	// Is serialised.
	CBGetMessage(self)->serialised = true;
	return reqLen;
}
예제 #2
0
uint32_t CBTransactionInputSerialise(CBTransactionInput * self){
	CBByteArray * bytes = CBGetMessage(self)->bytes;
	if (NOT bytes) {
		CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBTransactionInput with no bytes.");
		return 0;
	}
	if (NOT self->prevOut.hash){
		CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_DATA,"Attempting to serialise a CBTransactionInput without prevOut.hash.");
		return 0;
	}
	if (NOT self->scriptObject){
		CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_DATA,"Attempting to serialise a CBTransactionInput without scriptObject.");
		return 0;
	}
	CBVarInt scriptLen = CBVarIntFromUInt64(CBGetByteArray(self->scriptObject)->length);
	uint32_t reqLen = 40 + scriptLen.size + CBGetByteArray(self->scriptObject)->length;
	if (bytes->length < reqLen) {
		CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"Attempting to serialise a CBTransactionInput with less bytes than required. %i < %i\n",bytes->length, reqLen);
		return 0;
	}
	// Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory.
	CBByteArrayCopyByteArray(bytes, 0, self->prevOut.hash);
	CBByteArrayChangeReference(self->prevOut.hash, bytes, 0);
	CBByteArraySetInt32(bytes, 32, self->prevOut.index);
	CBVarIntEncode(bytes, 36, scriptLen);
	CBByteArrayCopyByteArray(bytes, 36 + scriptLen.size,CBGetByteArray(self->scriptObject));
	CBByteArrayChangeReference(CBGetByteArray(self->scriptObject),bytes,36 + scriptLen.size);
	CBByteArraySetInt32(bytes,36 + scriptLen.size + CBGetByteArray(self->scriptObject)->length,self->sequence);
	CBGetMessage(self)->serialised = true;
	return reqLen;
}
예제 #3
0
CBByteArray * CBVersionChecksumBytesGetString(CBVersionChecksumBytes * self){
	if (self->cachedString) {
		// Return cached string
		CBRetainObject(self->cachedString);
		return self->cachedString;
	}else{
		// Make string
		CBByteArrayReverseBytes(CBGetByteArray(self)); // Make this into little-endian
		CBBigInt bytes;
		CBBigIntAlloc(&bytes, CBGetByteArray(self)->length);
		bytes.length = CBGetByteArray(self)->length;
		memcpy(bytes.data, CBByteArrayGetData(CBGetByteArray(self)), bytes.length);
		char * string = CBEncodeBase58(&bytes);
		if (NOT string)
			return NULL;
		CBByteArray * str = CBNewByteArrayFromString(string, true);
		if (NOT str) {
			free(string);
			return NULL;
		}
		CBByteArrayReverseBytes(CBGetByteArray(self)); // Now the string is got, back to big-endian.
		if (self->cacheString) {
			self->cachedString = str;
			CBRetainObject(str); // Retain for this object.
		}
		return str; // No additional retain. Retained from constructor.
	}
}
예제 #4
0
bool CBInitVersionChecksumBytesFromBytes(CBVersionChecksumBytes * self,uint8_t * bytes,uint32_t size,bool cacheString,void (*logError)(char *,...)) {
    self->cacheString = cacheString;
    self->cachedString = NULL;
    if (NOT CBInitByteArrayWithData(CBGetByteArray(self), bytes, size, logError))
        return false;
    return true;
}
예제 #5
0
bool CBInitVersionChecksumBytesFromBytes(CBVersionChecksumBytes * self,uint8_t * bytes,uint32_t size,bool cacheString,CBEvents * events){
	self->cacheString = cacheString;
	self->cachedString = NULL;
	if (NOT CBInitByteArrayWithData(CBGetByteArray(self), bytes, size, events))
		return false;
	return true;
}
예제 #6
0
CBByteArray * CBVersionChecksumBytesGetString(CBVersionChecksumBytes * self){
	if (self->cachedString) {
		// Return cached string
		CBRetainObject(self->cachedString);
		return self->cachedString;
	}else{
		// Make string
		CBByteArrayReverseBytes(CBGetByteArray(self)); // Make this into little-endian
		char * string = CBEncodeBase58(CBByteArrayGetData(CBGetByteArray(self)),CBGetByteArray(self)->length);
		CBByteArray * str = CBNewByteArrayWithData((uint8_t *)string, strlen(string), CBGetByteArray(self)->events);
		CBByteArrayReverseBytes(CBGetByteArray(self)); // Now the string is got, back to big-endian.
		if (self->cacheString) {
			self->cachedString = str;
			CBRetainObject(str); // Retain for this object.
		}
		return str; // No additional retain. Retained from constructor.
	}
}
예제 #7
0
bool CBInitVersionChecksumBytesFromString(CBVersionChecksumBytes * self,CBByteArray * string,bool cacheString,void (*logError)(char *,...)) {
    // Cache string if needed
    if (cacheString) {
        self->cachedString = string;
        CBRetainObject(string);
    } else
        self->cachedString = NULL;
    self->cacheString = cacheString;
    // Get bytes from string conversion
    CBBigInt bytes;
    CBBigIntAlloc(&bytes, 25); // 25 is the number of bytes for bitcoin addresses.
    if (NOT CBDecodeBase58Checked(&bytes, (char *)CBByteArrayGetData(string), logError))
        return false;
    // Take over the bytes with the CBByteArray
    if (NOT CBInitByteArrayWithData(CBGetByteArray(self), bytes.data, bytes.length, logError))
        return false;
    CBByteArrayReverseBytes(CBGetByteArray(self)); // CBBigInt is in little-endian. Conversion needed to make bitcoin address the right way.
    return true;
}
예제 #8
0
bool CBInitVersionChecksumBytesFromString(CBVersionChecksumBytes * self,CBByteArray * string,bool cacheString,CBEvents * events){
	// Cache string if needed
	if (cacheString) {
		self->cachedString = string;
		CBRetainObject(string);
	}else
		self->cachedString = NULL;
	self->cacheString = cacheString;
	// Get bytes from string conversion
	CBBigInt bytes = CBDecodeBase58Checked((char *)CBByteArrayGetData(string), events);
	if (bytes.length == 1) {
		return false;
	}
	// Take over the bytes with the CBByteArray
	if (NOT CBInitByteArrayWithData(CBGetByteArray(self), bytes.data, bytes.length, events))
		return false;
	CBByteArrayReverseBytes(CBGetByteArray(self)); // CBBigInt is in little-endian. Conversion needed to make bitcoin address the right way.
	return true;
}
예제 #9
0
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;
}
예제 #10
0
uint8_t CBVersionChecksumBytesGetVersion(CBVersionChecksumBytes * self) {
    return CBByteArrayGetByte(CBGetByteArray(self), 0);
}
예제 #11
0
void CBFreeVersionChecksumBytes(void * vself) {
    CBVersionChecksumBytes * self = vself;
    if (self->cachedString) CBReleaseObject(self->cachedString);
    CBFreeByteArray(CBGetByteArray(self));
}
예제 #12
0
bool CBScriptExecute(CBScript * self,CBScriptStack * stack,CBDependencies * dependencies){
	// This looks confusing but isn't too bad, trust me.
	CBScriptStack altStack = CBNewEmptyScriptStack();
	u_int16_t skipIfElseBlock = 0xffff; // Skips all instructions on or over this if/else level.
	u_int16_t ifElseSize = 0; // Amount of if/else block levels
	if (CBGetByteArray(self->program)->length > 10000)
		return false; // Script is an illegal size.
	for (u_int8_t opCount = 0;;opCount++) {
		if (!(CBGetByteArray(self->program)->length - self->cursor))
			break; // Reached end of program
		if (opCount == 201) {
			return false; // Too many Op codes
		}
		u_int8_t byte = CBGetByteArrayVT(self->program)->getByte(self->program,self->cursor);
		self->cursor++;
		// Control management for skipping
		if (ifElseSize >= skipIfElseBlock) { // Skip when "ifElseSize" level is over or at "skipIfElseBlock"
			if (byte == CB_SCRIPT_OP_ELSE && ifElseSize == skipIfElseBlock) {
				skipIfElseBlock = 0xffff; // No more skipping
			}else if (byte == CB_SCRIPT_OP_ENDIF){
				if (ifElseSize == skipIfElseBlock) {
					skipIfElseBlock = 0xffff; // No more skipping
				}
				ifElseSize--;
			}else if (byte == CB_SCRIPT_OP_IF){
				ifElseSize++;
			}
		}else{ // Execution for no skipping
			if (!byte) {
				// Push 0 onto stack
				CBScriptStackItem item;
				item.data = malloc(1);
				item.length = 1;
				item.data[0] = 0;
				CBScriptStackPushItem(stack, item);
			}else if (byte < 76){
				// Check size
				if ((CBGetByteArray(self->program)->length - self->cursor) < byte)
					return false; // Not enough space.
				// Push data the size of the value of the byte
				CBScriptStackItem item;
				item.data = malloc(byte);
				item.length = byte;
				memmove(item.data, CBGetByteArrayVT(self->program)->getData(self->program) + self->cursor, byte);
				CBScriptStackPushItem(stack, item);
				self->cursor += byte;
			}else if (byte < 79){
				// Push data with the length of bytes represented by the next bytes
				u_int32_t amount;
				if (byte == CB_SCRIPT_OP_PUSHDATA1){
					amount = CBGetByteArrayVT(self->program)->getByte(self->program,self->cursor);
					self->cursor++;
				}else if (byte == CB_SCRIPT_OP_PUSHDATA2){
					amount = CBGetByteArrayVT(self->program)->readUInt16(self->program,self->cursor);
					self->cursor += 2;
				}else{
					amount = CBGetByteArrayVT(self->program)->readUInt32(self->program,self->cursor);
					self->cursor += 4;
				}
				// Check limitation
				if (amount > 520)
					return false; // Size of data to push is illegal.
				// Check size
				if ((CBGetByteArray(self->program)->length - self->cursor) < amount)
					return false; // Not enough space.
				CBScriptStackItem item;
				item.data = malloc(amount);
				item.length = amount;
				memmove(item.data, CBGetByteArrayVT(self->program)->getData(self->program) + self->cursor, amount);
				CBScriptStackPushItem(stack, item);
				self->cursor += amount;
			}else if (byte == CB_SCRIPT_OP_1NEGATE){
				// Push -1 onto the stack
				CBScriptStackItem item;
				item.data = malloc(1);
				item.length = 1;
				item.data[0] = 0x81; // 10000001 Not like normal signed integers, most significant bit applies sign, making the rest of the bits take away from zero.
				CBScriptStackPushItem(stack, item);
			}else if (byte < 97){
				// Push a number onto the stack
				CBScriptStackItem item;
				item.data = malloc(1);
				item.length = 1;
				item.data[0] = byte - CB_SCRIPT_OP_1 + 1;
				CBScriptStackPushItem(stack, item);
			}else if (byte == CB_SCRIPT_OP_NOP){
				// Nothing...
			}else if (byte == CB_SCRIPT_OP_IF 
					  || byte == CB_SCRIPT_OP_NOTIF){
				// If top of stack is true, continue, else goto OP_ELSE or OP_ENDIF.
				ifElseSize++;
				if (!stack->length)
					return false; // Stack empty
				bool res = CBScriptStackEvalBool(stack);
				if ((res && byte == CB_SCRIPT_OP_IF) 
					|| (!res && byte == CB_SCRIPT_OP_NOTIF))
					skipIfElseBlock = 0xffff;
				else
					skipIfElseBlock = ifElseSize; // Is skipping on this level until OP_ELSE or OP_ENDIF is reached on this level
				// Remove top stack item
				CBScriptStackRemoveItem(stack);
			}else if (byte == CB_SCRIPT_OP_ELSE){
				if (!ifElseSize)
					return false; // OP_ELSE on lowest level not possible
				skipIfElseBlock = ifElseSize; // Begin skipping
			}else if (byte == CB_SCRIPT_OP_ENDIF){
				if (!ifElseSize)
					return false; // OP_ENDIF on lowest level not possible
				ifElseSize--; // Lower level
			}else if (byte == CB_SCRIPT_OP_VERIFY){
				if (!stack->length)
					return false; // Stack empty
				if (CBScriptStackEvalBool(stack))
					// Remove top stack item
					CBScriptStackRemoveItem(stack);
				else
					return false; // Failed verification
			}else if (byte == CB_SCRIPT_OP_RETURN){
				return false; // Failed verification with OP_RETURN.
			}else if (byte == CB_SCRIPT_OP_TOALTSTACK){
				if (!stack->length)
					return false; // Stack empty
				CBScriptStackPushItem(&altStack, CBScriptStackPopItem(stack));
			}else if (byte == CB_SCRIPT_OP_FROMALTSTACK){
				if (!altStack.length)
					return false; // Alternative stack empty
				CBScriptStackPushItem(stack, CBScriptStackPopItem(&altStack));
			}else if (byte == CB_SCRIPT_OP_IFDUP){
				if (!stack->length)
					return false; // Stack empty
				if (CBScriptStackEvalBool(stack))
					//Duplicate top stack item
					CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,0));
			}else if (byte == CB_SCRIPT_OP_DEPTH){
				CBScriptStackItem item;
				item.data = malloc(2);
				item.length = 2;
				item.data[0] = stack->length >> 8;
				item.data[1] = stack->length;
				CBScriptStackPushItem(stack, item);
			}else if (byte == CB_SCRIPT_OP_DROP){
				if (!stack->length)
					return false; // Stack empty
				CBScriptStackRemoveItem(stack);
			}else if (byte == CB_SCRIPT_OP_DUP){
				if (!stack->length)
					return false; // Stack empty
				//Duplicate top stack item
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,0));
			}else if (byte == CB_SCRIPT_OP_NIP){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				// Remove second from top item.
				stack->length--;
				free(stack->elements[stack->length-1].data);
				stack->elements[stack->length-1] = stack->elements[stack->length]; // Top item moves down
				stack->elements = realloc(stack->elements, sizeof(*stack->elements)*stack->length);
			}else if (byte == CB_SCRIPT_OP_OVER){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,1)); // Copies second from top and pushes it on the top.
			}else if (byte == CB_SCRIPT_OP_PICK || byte == CB_SCRIPT_OP_ROLL){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				CBScriptStackItem item = CBScriptStackPopItem(stack);
				if (item.length > 4)
					return false; // Protocol does not except integers more than 32 bits.
				if (item.data[item.length-1] > 0x80) // Negative
					return false; // Must be positive
				u_int32_t i = item.data[0] & (item.data[1] << 8) & (item.data[2] << 16) & (item.data[3] << 24);
				if (i >= stack->length)
					return false; // Must be smaller than stack size
				if (byte == CB_SCRIPT_OP_PICK) {
					// Copy element
					CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,i));
				}else{ // CB_SCRIPT_OP_ROLL
					// Move element.
					CBScriptStackItem temp = stack->elements[stack->length-i-1];
					for (u_int32_t x = 0; x < i; x++) // Move other elements down
						stack->elements[stack->length-i+x-1] = stack->elements[stack->length-i+x];
					stack->elements[stack->length] = temp;
				}
			}else if (byte == CB_SCRIPT_OP_ROT){
				if (stack->length < 3)
					return false; // Stack needs 3 or more elements.
				// Rotate top three elements to the left.
				CBScriptStackItem temp = stack->elements[stack->length-3];
				stack->elements[stack->length-3] = stack->elements[stack->length-2];
				stack->elements[stack->length-2] = stack->elements[stack->length-1];
				stack->elements[stack->length-1] = temp;
			}else if (byte == CB_SCRIPT_OP_SWAP){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				CBScriptStackItem temp = stack->elements[stack->length-2];
				stack->elements[stack->length-2] = stack->elements[stack->length-1];
				stack->elements[stack->length-1] = temp;
			}else if (byte == CB_SCRIPT_OP_TUCK){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				CBScriptStackItem item = CBScriptStackCopyItem(stack, 0);
				// New copy three down.
				stack->length++;
				stack->elements = realloc(stack->elements, sizeof(*stack->elements)*stack->length);
				stack->elements[stack->length-1] = stack->elements[stack->length-2];
				stack->elements[stack->length-2] = stack->elements[stack->length-3];
				stack->elements[stack->length-3] = item;
			}else if (byte == CB_SCRIPT_OP_2DROP){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				CBScriptStackRemoveItem(stack);
				CBScriptStackRemoveItem(stack);
			}else if (byte == CB_SCRIPT_OP_2DUP){
				if (stack->length < 2)
					return false; // Stack needs 2 or more elements.
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,1));
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,1));
			}else if (byte == CB_SCRIPT_OP_3DUP){
				if (stack->length < 3)
					return false; // Stack needs 3 or more elements.
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,2));
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,2));
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,2));
			}else if (byte == CB_SCRIPT_OP_2OVER){
				if (stack->length < 4)
					return false; // Stack needs 4 or more elements.
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,3));
				CBScriptStackPushItem(stack, CBScriptStackCopyItem(stack,3));
			}else if (byte == CB_SCRIPT_OP_2ROT){
				if (stack->length < 6)
					return false; // Stack needs 6 or more elements.
				// Rotate top three pairs of elements to the left.
				CBScriptStackItem temp = stack->elements[stack->length-6];
				CBScriptStackItem temp2 = stack->elements[stack->length-5];
				stack->elements[stack->length-6] = stack->elements[stack->length-4];
				stack->elements[stack->length-5] = stack->elements[stack->length-3];
				stack->elements[stack->length-4] = stack->elements[stack->length-2];
				stack->elements[stack->length-3] = stack->elements[stack->length-1];
				stack->elements[stack->length-2] = temp;
				stack->elements[stack->length-1] = temp2;
			}else if (byte == CB_SCRIPT_OP_2SWAP){
				if (stack->length < 4)
					return false; // Stack needs 4 or more elements.
				CBScriptStackItem temp = stack->elements[stack->length-4];
				CBScriptStackItem temp2 = stack->elements[stack->length-3];
				stack->elements[stack->length-4] = stack->elements[stack->length-2];
				stack->elements[stack->length-3] = stack->elements[stack->length-1];
				stack->elements[stack->length-2] = temp;
				stack->elements[stack->length-1] = temp2;
			}else if (byte == CB_SCRIPT_OP_SIZE){
				// ??? Does this match the protocol?
				if (!stack->length)
					return false; // Stack empty
				u_int16_t len = stack->elements[stack->length-1].length;
				CBScriptStackItem item;
				if (len > 0x80) { // More than 0x80 so use two bytes as on a single byte it would be negative.
					item.data = malloc(2);
					item.length = 2;
					item.data[0] = len >> 8;
					item.data[1] = len;
				}else{
예제 #13
0
int main(){
	CBByteArray * walletKeyString = CBNewByteArrayFromString("xpub6DRhpXssnj7X6CwJgseK9oyFxSC8jk6nJz2SWkf5pjsQs12xv89Dfr627TtaZKkFbG6Aq23fmaNaf5KRo9iGfEXTTXvtd6gsXJTB8Sdah3B", false);
    CBChecksumBytes * walletKeyData = CBNewChecksumBytesFromString(walletKeyString, false);
    CBHDKey * cbkey = CBNewHDKeyFromData(CBByteArrayGetData(CBGetByteArray(walletKeyData)));
	CBAddress * address = CBNewAddressFromRIPEMD160Hash(CBHDKeyGetHash(cbkey), CB_NETWORK_PRODUCTION, false);
	CBByteArray * str = CBChecksumBytesGetString(CBGetChecksumBytes(address));
	printf("%s\n", CBByteArrayGetData(str));
	CBReleaseObject(address);
	// Test type
	if (CBHDKeyGetType(CB_HD_KEY_VERSION_PROD_PRIVATE) != CB_HD_KEY_TYPE_PRIVATE) {
		printf("CB_HD_KEY_VERSION_PROD_PRIVATE TYPE FAIL\n");
		return EXIT_FAILURE;
	}
	if (CBHDKeyGetType(CB_HD_KEY_VERSION_PROD_PUBLIC) != CB_HD_KEY_TYPE_PUBLIC) {
		printf("CB_HD_KEY_VERSION_PROD_PUBLIC TYPE FAIL\n");
		return EXIT_FAILURE;
	}
	if (CBHDKeyGetType(CB_HD_KEY_VERSION_TEST_PRIVATE) != CB_HD_KEY_TYPE_PRIVATE) {
		printf("CB_HD_KEY_VERSION_TEST_PRIVATE TYPE FAIL\n");
		return EXIT_FAILURE;
	}
	if (CBHDKeyGetType(CB_HD_KEY_VERSION_TEST_PUBLIC) != CB_HD_KEY_TYPE_PUBLIC) {
		printf("CB_HD_KEY_VERSION_TEST_PUBLIC TYPE FAIL\n");
		return EXIT_FAILURE;
	}
	// Test HMAC-SHA512
	uint8_t hash[64];
	CBHDKeyHmacSha512((uint8_t [37]){0x2f, 0xf7, 0xd6, 0x9f, 0x7a, 0x59, 0x0b, 0xb0, 0x5e, 0x68, 0xd1, 0xdc, 0x0f, 0xcf, 0x8d, 0xc2, 0x17, 0x59, 0xc9, 0x39, 0xbb, 0x6b, 0x9b, 0x02, 0x0f, 0x65, 0x5d, 0x53, 0x85, 0x3c, 0xb5, 0xc2, 0x14, 0x61, 0x4b, 0x24, 0x42}, (uint8_t [32]){0xa2, 0x55, 0x21, 0xe3, 0xc5, 0x5b, 0x65, 0xd1, 0xcf, 0x25, 0x4b, 0x6c, 0x85, 0x23, 0xdc, 0xbf, 0x89, 0x46, 0x8d, 0x1f, 0x09, 0x1f, 0x15, 0x87, 0x6b, 0xbb, 0xc7, 0xfd, 0xd5, 0x44, 0x28, 0x43}, hash);
	if (memcmp(hash, (uint8_t [64]){0xfa, 0xa7, 0x9d, 0x85, 0xe0, 0xe4, 0x3d, 0xae, 0x8c, 0x3f, 0x99, 0xf0, 0x70, 0xdf, 0x97, 0x56, 0x2b, 0x3f, 0xbb, 0x17, 0x35, 0x20, 0xe0, 0x87, 0x32, 0xa6, 0x64, 0xca, 0xd4, 0x55, 0x0b, 0xbe, 0xc1, 0x11, 0xe5, 0xf8, 0x80, 0xdb, 0xb7, 0x3d, 0x67, 0x74, 0xbb, 0xc2, 0x9f, 0x67, 0xd9, 0x67, 0xaa, 0x10, 0xac, 0x60, 0x18, 0x90, 0x7f, 0x35, 0x53, 0xe3, 0x21, 0x38, 0xf6, 0x5b, 0xbe, 0x69}, 64) != 0) {
		printf("HMAC FAIL\n");
		return EXIT_FAILURE;
	}
	for (uint8_t x = 0; x < NUM_TEST_VECTORS; x++) {
		// Deserialise private key
		CBByteArray * masterString = CBNewByteArrayFromString(testVectors[x][0].privString, true);
		CBChecksumBytes * masterData = CBNewChecksumBytesFromString(masterString, false);
		CBReleaseObject(masterString);
		CBHDKey * key = CBNewHDKeyFromData(CBByteArrayGetData(CBGetByteArray(masterData)));
		CBReleaseObject(masterData);
		checkKey(key, x, 0);
		for (uint8_t y = 0; y < NUM_CHILDREN; y++) {
			if (testVectors[x][y+1].childID.priv == false) {
				// Derive public child and check public key is correct by address
				CBHDKey * newKey = CBNewHDKey(false);
				key->versionBytes = CB_HD_KEY_VERSION_PROD_PUBLIC;
				CBHDKeyDeriveChild(key, testVectors[x][y+1].childID, newKey);
				key->versionBytes = CB_HD_KEY_VERSION_PROD_PRIVATE;
				CBAddress * address = CBNewAddressFromRIPEMD160Hash(CBHDKeyGetHash(newKey), CB_NETWORK_PRODUCTION, false);
				CBByteArray * str = CBChecksumBytesGetString(CBGetChecksumBytes(address));
				CBReleaseObject(address);
				if (memcmp(CBByteArrayGetData(str), testVectors[x][y + 1].addr, 34) != 0) {
					printf("ADDR FROM PUB FAIL AT %u - %u\n", x, y + 1);
					exit(EXIT_FAILURE);
				}
				CBReleaseObject(str);
				// Check serialisation of public key
				uint8_t * keyData = malloc(82);
				CBHDKeySerialise(newKey, keyData);
				CBChecksumBytes * checksumBytes = CBNewChecksumBytesFromBytes(keyData, 82, false);
				str = CBChecksumBytesGetString(checksumBytes);
				CBReleaseObject(checksumBytes);
				if (memcmp(CBByteArrayGetData(str), testVectors[x][y+1].pubString, 111) != 0) {
					printf("PUBLIC KEY STRING FROM PUB FAIL AT %u - %u\n", x, y);
					exit(EXIT_FAILURE);
				}
				CBReleaseObject(str);
				free(newKey);
			}
			// Derive private child
			CBHDKey * newKey = CBNewHDKey(true);
			CBHDKeyDeriveChild(key, testVectors[x][y+1].childID, newKey);
			free(key);
			key = newKey;
			checkKey(key, x, y+1);
		}
		free(key);
	}
	return EXIT_SUCCESS;
}