Merge pull request #149 from Christewart/add_hashdigest_endianness_flip

Adding helper function to flip hash's endianness, adding helper funct…
This commit is contained in:
Chris Stewart 2018-04-20 11:19:33 -04:00 committed by GitHub
commit cbf23d0935
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 13 deletions

View file

@ -5,22 +5,32 @@ import org.bitcoins.core.util.{ Factory, BitcoinSUtil }
/**
* Created by chris on 5/24/16.
*/
sealed trait HashDigest {
sealed abstract class HashDigest {
/** The message digest represented in bytes */
def bytes: Seq[Byte]
/** The message digest represented in hexadecimal */
def hex: String = BitcoinSUtil.encodeHex(bytes)
/**
* Flips the endianness of the byte sequence.
* Since bitcoin unfortunately has inconsistent endianness between the protocol
* level and the presentation level. This is useful for switching between the two.
* @return
*/
def flip: HashDigest
}
/**
* Represents the result of SHA1()
*/
sealed trait Sha1Digest extends HashDigest
sealed abstract class Sha1Digest extends HashDigest {
override def flip: Sha1Digest = Sha1Digest(bytes.reverse)
}
object Sha1Digest extends Factory[Sha1Digest] {
private case class Sha1DigestImpl(bytes: Seq[Byte]) extends Sha1Digest {
override def toString = "Sha1DigestImpl(" + hex + ")"
override def toString = s"Sha1DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): Sha1Digest = Sha1DigestImpl(bytes)
}
@ -28,12 +38,14 @@ object Sha1Digest extends Factory[Sha1Digest] {
/**
* Represents the result of SHA256()
*/
sealed trait Sha256Digest extends HashDigest
sealed abstract class Sha256Digest extends HashDigest {
override def flip: Sha256Digest = Sha256Digest(bytes.reverse)
}
object Sha256Digest extends Factory[Sha256Digest] {
private case class Sha256DigestImpl(bytes: Seq[Byte]) extends Sha256Digest {
require(bytes.length == 32, "Sha256Digest must be 32 bytes in size, got: " + bytes.length)
override def toString = "Sha256DigestImpl(" + hex + ")"
override def toString = s"Sha256DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): Sha256Digest = Sha256DigestImpl(bytes)
}
@ -41,12 +53,14 @@ object Sha256Digest extends Factory[Sha256Digest] {
/**
* Represents the result of SHA256(SHA256())
*/
sealed trait DoubleSha256Digest extends HashDigest
sealed abstract class DoubleSha256Digest extends HashDigest {
def flip: DoubleSha256Digest = DoubleSha256Digest(bytes.reverse)
}
object DoubleSha256Digest extends Factory[DoubleSha256Digest] {
private case class DoubleSha256DigestImpl(bytes: Seq[Byte]) extends DoubleSha256Digest {
require(bytes.length == 32, "DoubleSha256Digest must always be 32 bytes, got: " + bytes.length)
override def toString = "DoubleSha256DigestImpl(" + hex + ")"
override def toString = s"DoubleSha256DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): DoubleSha256Digest = DoubleSha256DigestImpl(bytes)
@ -55,12 +69,14 @@ object DoubleSha256Digest extends Factory[DoubleSha256Digest] {
/**
* Represents the result of RIPEMD160()
*/
sealed trait RipeMd160Digest extends HashDigest
sealed abstract class RipeMd160Digest extends HashDigest {
override def flip: RipeMd160Digest = RipeMd160Digest(bytes.reverse)
}
object RipeMd160Digest extends Factory[RipeMd160Digest] {
private case class RipeMd160DigestImpl(bytes: Seq[Byte]) extends RipeMd160Digest {
require(bytes.length == 20, "RIPEMD160Digest must always be 20 bytes, got: " + bytes.length)
override def toString = "RipeMd160DigestImpl(" + hex + ")"
override def toString = s"RipeMd160DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): RipeMd160Digest = RipeMd160DigestImpl(bytes)
}
@ -68,12 +84,14 @@ object RipeMd160Digest extends Factory[RipeMd160Digest] {
/**
* Represents the result of RIPEMD160(SHA256())
*/
sealed trait Sha256Hash160Digest extends HashDigest
sealed abstract class Sha256Hash160Digest extends HashDigest {
override def flip: Sha256Hash160Digest = Sha256Hash160Digest(bytes.reverse)
}
object Sha256Hash160Digest extends Factory[Sha256Hash160Digest] {
private case class Sha256Hash160DigestImpl(bytes: Seq[Byte]) extends Sha256Hash160Digest {
require(bytes.length == 20, "Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length)
override def toString = "Sha256Hash160DigestImpl(" + hex + ")"
override def toString = s"Sha256Hash160DigestImpl($hex)"
}
override def fromBytes(bytes: Seq[Byte]): Sha256Hash160Digest = Sha256Hash160DigestImpl(bytes)
}

View file

@ -40,6 +40,15 @@ sealed trait BlockHeader extends NetworkElement {
def previousBlockHash: DoubleSha256Digest
/**
* Returns the big endian encoding of the previous block hash
* This is useful for using rpc and block exporers, but is NOT used in the protocol itself
* See this link for more info
* [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]]
* @return
*/
def previousBlockHashBE: DoubleSha256Digest = previousBlockHash.flip
/**
* A SHA256(SHA256()) hash in internal byte order.
* The merkle root is derived from the hashes of all transactions included in this block,
@ -51,6 +60,14 @@ sealed trait BlockHeader extends NetworkElement {
def merkleRootHash: DoubleSha256Digest
/** Returns the merkle root hash in BIG ENDIAN format. This is not compatible with the bitcoin
* protocol but it is useful for rpc clients and block explorers
* See this link for more info
* [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]]
* @return
*/
def merkleRootHashBE: DoubleSha256Digest = merkleRootHash.flip
/**
* The block time is a Unix epoch time when the miner started hashing the header (according to the miner).
* Must be greater than or equal to the median time of the previous 11 blocks.
@ -78,9 +95,18 @@ sealed trait BlockHeader extends NetworkElement {
*/
def nonce: UInt32
/** Returns the block's hash */
/** Returns the block's hash in the protocol level little endian encoding */
def hash: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes)
/**
* Returns the block hash in big endian format, this is useful for rpc
* and block explorer debugging. This is *not* used in the core protocol itself.
* See this link for more info
* [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]]
* @return
*/
def hashBE: DoubleSha256Digest = hash.flip
override def bytes: Seq[Byte] = RawBlockHeaderSerializer.write(this)
}

View file

@ -14,10 +14,21 @@ import scala.util.{ Failure, Success, Try }
sealed abstract class Transaction extends NetworkElement {
/**
* The sha256(sha256(tx)) of this transaction
* Note that this is the big endian encoding of the hash NOT the little endian encoding displayed on block explorers
* Note that this is the little endian encoding of the hash, NOT the big endian encoding shown in block
* explorers. See this link for more info
* [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]]
*/
def txId: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes)
/**
* This is the BIG ENDIAN encoding for the txid. This is commonly used for
* RPC interfaces and block explorers, this encoding is NOT used at the protocol level
* For more info see:
* [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]]
* @return
*/
def txIdBE: DoubleSha256Digest = txId.flip
/** The version number for this transaction */
def version: UInt32
@ -100,6 +111,8 @@ sealed abstract class WitnessTransaction extends Transaction {
*/
def wTxId: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes)
/** Returns the big endian encoding of the wtxid */
def wTxIdBE: DoubleSha256Digest = wTxId.flip
/**
* Weight calculation in bitcoin for witness txs
* [[https://github.com/bitcoin/bitcoin/blob/5961b23898ee7c0af2626c46d5d70e80136578d3/src/consensus/validation.h#L96]]