Skip to content
Permalink
Browse files

Add Gold, Cash and Bitcoin Private

  • Loading branch information...
ianpurton committed Jul 31, 2018
1 parent b51c0d4 commit 516e01303bae2d09a23ba80f0f89633d72ff6538
@@ -0,0 +1,24 @@
require "./spec_helper"

describe OnChain::Protocol do

# https://bitcoin.stackexchange.com/questions/71284/how-do-i-generate-the-bitcoin-cash-hash-preimage
it "should correctly hash a bitcoin cash tx" do

tx_hex = (<<-TX
0100000001fb4a8e5c7ac5311f32fbe127f031134ee3e7490f3308ca19c567f78d6aa96d77
0000000000ffffffff0100a00700000000001976a914a8e181e0847b495df439066ca8fb36
ce093692be88ac00000000
TX
).gsub(/\s+/, "")

tx = OnChain::Protocol::BitcoinCashTransaction.new(tx_hex)

tx.to_hex.should eq(tx_hex)

tx.signature_hash_for_bitcoin_cash(0.to_u64,
BigInt.new(500000), 0.to_u32).should eq(
"7bfb153ec3b8d977352e1e0c074d9552916c4d476ed7e356c94563a4085950cf")
end

end
@@ -0,0 +1,24 @@
require "./spec_helper"

describe OnChain::Protocol do

it "should correctly hash a bitcoin gold tx" do

tx_hex = (<<-TX
010000000153a20637bf666c28ceeb8142de0de72da5833de04223e1a51e83cc499ec35957
000000001976a9148ac7591107aec68c282488cd74096014108844dd88acffffffff024042
0f00000000001976a914e342b95d1a6391d1ecc04fe31d5e9655984ab8b888ac1655b74900
0000001976a9148ac7591107aec68c282488cd74096014108844dd88ac00000000
TX
).gsub(/\s+/, "")

tx = OnChain::Protocol::BitcoinCashTransaction.new(tx_hex)

tx.to_hex.should eq(tx_hex)

tx.signature_hash_for_bitcoin_cash(0.to_u64,
BigInt.new(1237761638), 79.to_u32).should eq(
"595f50b91736b0b883cb45591e849be51b112443fc10d7e8e84307d99c6e31a0")
end

end
@@ -0,0 +1,136 @@
require "./**"

module OnChain
module Protocol
class BitcoinCashTransaction < UTXOTransaction

# Double SHA256 of the serialization of:
# 1. nVersion of the transaction (4-byte little endian)
# 2. hashPrevouts (32-byte hash)
# 3. hashSequence (32-byte hash)
# 4. outpoint (32-byte hash + 4-byte little endian)
# 5. scriptCode of the input (serialized as scripts inside CTxOuts)
# 6. value of the output spent by this input (8-byte little endian)
# 7. nSequence of the input (4-byte little endian)
# 8. hashOutputs (32-byte hash)
# 9. nLocktime of the transaction (4-byte little endian)
# 10. sighash type of the signature (4-byte little endian)
#
def signature_hash_for_bitcoin_cash(input_idx : UInt64,
prev_out_value : BigInt, fork_id : UInt32) : String

buffer = IO::Memory.new

# 1. nVersion of the transaction (4-byte little endian)
buffer.write_bytes(ver, IO::ByteFormat::LittleEndian)

# 2. hashPrevouts (32-byte hash)
buffer.write(prev_outs_hash)

# 3. hashSequence (32-byte hash)
buffer.write(sequence_hash)

# 4. outpoint (32-byte hash + 4-byte little endian)
buffer.write(inputs[input_idx].prev_out_hash)
buffer.write_bytes(inputs[input_idx].prev_out_index,
IO::ByteFormat::LittleEndian)

# 5. scriptCode of the input (serialized as scripts inside CTxOuts)
Transaction.write_var_int(buffer,
inputs[input_idx].script_sig.size.to_u64)
buffer.write(inputs[input_idx].script_sig)

# 6. value of the output spent by this input (8-byte little endian)
buffer.write_bytes(prev_out_value.to_u64, IO::ByteFormat::LittleEndian)

# 7. nSequence of the input (4-byte little endian)
buffer.write_bytes(inputs[input_idx].sequence,
IO::ByteFormat::LittleEndian)

# 8. hashOutputs (32-byte hash)
buffer.write(outputs_hash)

# 9. nLocktime of the transaction (4-byte little endian)
buffer.write_bytes(lock_time, IO::ByteFormat::LittleEndian)

# 10. sighash type of the signature (4-byte little endian)
fork_hash_type = 65 # SIGHASH_TYPE[:all] | SIGHASH_TYPE[:forkid]
fork_hash_type |= fork_id
buffer.write_bytes(fork_hash_type, IO::ByteFormat::LittleEndian)

# Double SHA256 of the serialization of:
hash = OpenSSL::Digest.new("SHA256")
hash.update(buffer.to_slice)
hash1 = hash.digest

hash = OpenSSL::Digest.new("SHA256")
hash.update(hash1)
hash2 = hash.digest

return OnChain.to_hex(hash2)
end

def prev_outs_hash : Bytes

buffer = IO::Memory.new

inputs.each do |input|
buffer.write(input.prev_out_hash)
buffer.write_bytes(input.prev_out_index, IO::ByteFormat::LittleEndian)
end

hash = OpenSSL::Digest.new("SHA256")
hash.update(buffer.to_slice)
hash1 = hash.digest

hash = OpenSSL::Digest.new("SHA256")
hash.update(hash1)
hash2 = hash.digest

return hash2

end

def outputs_hash : Bytes

buffer = IO::Memory.new

outputs.each do |output|
output.to_buffer(buffer)
end

hash = OpenSSL::Digest.new("SHA256")
hash.update(buffer.to_slice)
hash1 = hash.digest

hash = OpenSSL::Digest.new("SHA256")
hash.update(hash1)
hash2 = hash.digest

return hash2
end

def sequence_hash : Bytes

buffer = IO::Memory.new

inputs.each do |input|
buffer.write_bytes(input.sequence, IO::ByteFormat::LittleEndian)
end

hash = OpenSSL::Digest.new("SHA256")
hash.update(buffer.to_slice)
hash1 = hash.digest

hash = OpenSSL::Digest.new("SHA256")
hash.update(hash1)
hash2 = hash.digest

return hash2
end

end

end
end

@@ -0,0 +1,52 @@
require "./**"

module OnChain
module Protocol
class BitcoinPrivateTransaction < UTXOTransaction

# htps://github.com/BTCPrivate/BitcoinPrivate/blob/master/src/script/interpreter.cpp#L1102
# https://github.com/BTCGPU/BTCGPU/blob/master/src/script/interpreter.cpp#L1212
# htttps://github.com/BTCPrivate/BitcoinPrivate/blob/master/src/script/interpreter.cpp#L1047
#
def signature_hash_for_bitcoin_private(input_idx : UInt64) : String

buffer = IO::Memory.new

# Inputs size
write_var_int(buffer, inputs.size)

# The inputs
inputs[input_idx].to_buffer(buffer)

# Outputs size
write_var_int(buffer, outputs.size)

# Outputs
outputs.each do |output|
output.to_buffer(buffer)
end

# Lock time
buffer.write_bytes(lock_time, IO::ByteFormat::LittleEndian)

# Fork id
fork_hash_type = 1.to_u32
fork_hash_type |= 0x42.to_u32 << 8.to_u32
buffer.write_bytes(fork_hash_type, IO::ByteFormat::LittleEndian)

hash = OpenSSL::Digest.new("SHA256")
hash.update(buffer.to_slice)
hash1 = hash.digest

hash = OpenSSL::Digest.new("SHA256")
hash.update(hash1)
hash2 = hash.digest

return OnChain.to_hex(hash2)
end

end

end
end

0 comments on commit 516e013

Please sign in to comment.
You can’t perform that action at this time.