Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import org.apache.ivy.core.module.descriptor.ExcludeRule

name := "encry-common"
version := "0.9.0"
version := "0.9.1"
scalaVersion := "2.12.6"
organization := "org.encry"

val circeVersion = "0.9.3"

val excludeRule = ExclusionRule("ove")

lazy val root = project.in(file(".")).dependsOn(blake2b)
lazy val blake2b = ProjectRef(uri("git://github.com/alphazero/Blake2b.git#master"), "blake2b")

libraryDependencies ++= Seq(
"org.encry" %% "prism" % "0.8.5",
("org.encry" %% "prism" % "0.8.6").excludeAll(excludeRule),
"io.circe" %% "circe-core" % circeVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion,
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version = 1.2.0
sbt.version = 1.3.0
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package org.encryfoundation.common.modifiers

import org.encryfoundation.common.utils.Algos
import org.encryfoundation.common.utils.TaggedTypes.{ModifierId, ModifierTypeId}
import org.encryfoundation.prismlang.utils.{BouncyCastleHasher, Hasher}

trait ModifierWithDigest extends PersistentNodeViewModifier {
trait ModifierWithDigest extends PersistentNodeViewModifier with BouncyCastleHasher {

override lazy val id: ModifierId = ModifierWithDigest.computeId(modifierTypeId, headerId, digest)
override lazy val id: ModifierId = ModifierId @@ prefixedHash(modifierTypeId, headerId, digest).repr

def digest: Array[Byte]

def headerId: Array[Byte]
}

object ModifierWithDigest {
def computeId(modifierType: ModifierTypeId, headerId: Array[Byte], digest: Array[Byte]): ModifierId =
ModifierId @@ Algos.hash.prefixedHash(modifierType, headerId, digest).repr
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import org.encryfoundation.common.utils.TaggedTypes.{ADDigest, Difficulty, Modif
import scorex.crypto.hash.Digest32
import io.circe.{Decoder, Encoder, HCursor}
import io.circe.syntax._

import scala.util.Try
import Header._
import org.encryfoundation.common.utils.constants.TestNetConstants
import org.encryfoundation.common.utils.Algos
import org.encryfoundation.prismlang.utils.BouncyCastleHasher

case class Header(version: Byte,
override val parentId: ModifierId,
Expand All @@ -23,7 +25,7 @@ case class Header(version: Byte,
height: Int,
nonce: Long,
difficulty: Difficulty,
equihashSolution: EquihashSolution) extends PersistentModifier {
equihashSolution: EquihashSolution) extends PersistentModifier with BouncyCastleHasher {

override type M = Header

Expand All @@ -38,7 +40,10 @@ case class Header(version: Byte,
lazy val isGenesis: Boolean = height == TestNetConstants.GenesisHeight

lazy val payloadId: ModifierId =
ModifierWithDigest.computeId(Payload.modifierTypeId, id, transactionsRoot)
computeId(Payload.modifierTypeId, id, transactionsRoot)

def computeId(modifierType: ModifierTypeId, headerId: Array[Byte], digest: Array[Byte]): ModifierId =
ModifierId @@ prefixedHash(modifierType, headerId, digest).repr

def toHeaderProto: HeaderProtoMessage = HeaderProtoSerializer.toProto(this)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import org.apache.commons.lang.ArrayUtils
import org.encryfoundation.common.modifiers.mempool.transaction.{Transaction, TransactionProtoSerializer, TransactionSerializer}
import org.encryfoundation.common.modifiers.{ModifierWithDigest, PersistentModifier}
import org.encryfoundation.common.serialization.Serializer
import org.encryfoundation.common.utils.Algos.emptyMerkleTreeRoot
import org.encryfoundation.common.utils.{Algos, TaggedTypes}
import org.encryfoundation.common.utils.TaggedTypes.{LeafData, ModifierId, ModifierTypeId}
import org.encryfoundation.common.utils.TaggedTypes.{ModifierId, ModifierTypeId}
import scorex.crypto.authds.{LeafData => ScorexLeaf}
import scorex.crypto.authds.merkle.MerkleTree
import scorex.crypto.hash.Digest32

import scala.util.{Success, Try}

case class Payload(override val headerId: ModifierId,
Expand All @@ -23,7 +27,7 @@ case class Payload(override val headerId: ModifierId,

override val modifierTypeId: ModifierTypeId = Payload.modifierTypeId

override lazy val digest: Digest32 = Payload.rootHash(txs.map(_.id))
override lazy val digest: Digest32 = rootHash(txs.map(_.id))

override def serializer: Serializer[Payload] = PayloadSerializer

Expand All @@ -33,10 +37,20 @@ case class Payload(override val headerId: ModifierId,
s" txsQty=${txs.size}, id = ${Algos.encode(id)})"

override def parentId: ModifierId = null

def rootHash(ids: Seq[ModifierId]): Digest32 = merkleTreeRoot(ScorexLeaf !@@ ids)

def merkleTreeRoot(elements: Seq[ScorexLeaf]): Digest32 =
if (elements.isEmpty) emptyMerkleTreeRoot else MerkleTree(elements.map(ScorexLeaf @@ _.repr))(this).rootHash
}

object Payload {

def rootHash(ids: Seq[ModifierId]): Digest32 = merkleTreeRoot(ScorexLeaf !@@ ids) //for tests only

def merkleTreeRoot(elements: Seq[ScorexLeaf]): Digest32 =
if (elements.isEmpty) emptyMerkleTreeRoot else MerkleTree(elements.map(ScorexLeaf @@ _.repr))(Algos.hash).rootHash

implicit val jsonEncoder: Encoder[Payload] = (p: Payload) => Map(
"headerId" -> Algos.encode(p.headerId).asJson,
"transactions" -> p.txs.map(_.asJson).asJson
Expand All @@ -51,9 +65,6 @@ object Payload {
)

val modifierTypeId: ModifierTypeId = ModifierTypeId @@ (102: Byte)

def rootHash(ids: Seq[ModifierId]): Digest32 = Algos.merkleTreeRoot(LeafData !@@ ids)

}

object PayloadProtoSerializer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ case class AssetIssuingDirective(contractHash: ContractHash, amount: Amount) ext

override def boxes(digest: Digest32, idx: Int): Seq[EncryBaseBox] = Seq(TokenIssuingBox(
EncryProposition(contractHash),
Utils.nonceFromDigest(digest ++ Ints.toByteArray(idx)),
nonceFromDigest(digest ++ Ints.toByteArray(idx)),
amount,
Algos.hash(Ints.toByteArray(idx) ++ digest)
blake2b.digest(Ints.toByteArray(idx) ++ digest)
))

override def serializer: Serializer[M] = AssetIssuingDirectiveSerializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ case class DataDirective(contractHash: ContractHash, data: Array[Byte]) extends
override lazy val isValid: Boolean = data.length <= TestNetConstants.MaxDataLength

override def boxes(digest: Digest32, idx: Int): Seq[EncryBaseBox] =
Seq(DataBox(EncryProposition(contractHash), Utils.nonceFromDigest(digest ++ Ints.toByteArray(idx)), data))
Seq(DataBox(EncryProposition(contractHash), nonceFromDigest(digest ++ Ints.toByteArray(idx)), data))

override def serializer: Serializer[M] = DataDirectiveSerializer

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package org.encryfoundation.common.modifiers.mempool.directive

import TransactionProto.TransactionProtoMessage.DirectiveProtoMessage
import com.google.common.primitives.Longs
import io.circe._
import org.encryfoundation.common.modifiers.mempool.directive.Directive.DTypeId
import org.encryfoundation.common.modifiers.state.box.EncryBaseBox
import org.encryfoundation.common.serialization.BytesSerializable
import org.encryfoundation.prismlang.utils.Hasher
import scorex.crypto.hash.Digest32

trait Directive extends BytesSerializable {
trait Directive extends BytesSerializable with Hasher {

val typeId: DTypeId

Expand All @@ -16,6 +18,8 @@ trait Directive extends BytesSerializable {
def boxes(digest: Digest32, idx: Int): Seq[EncryBaseBox]

def toDirectiveProto: DirectiveProtoMessage

def nonceFromDigest(digest: Array[Byte]): Long = Longs.fromByteArray(blake2b.digest(digest).take(8))
}

object Directive {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ case class ScriptedAssetDirective(contractHash: ContractHash,
override lazy val isValid: Boolean = amount > 0

override def boxes(digest: Digest32, idx: Int): Seq[EncryBaseBox] =
Seq(AssetBox(EncryProposition(contractHash), Utils.nonceFromDigest(digest ++ Ints.toByteArray(idx)), amount))
Seq(AssetBox(EncryProposition(contractHash), nonceFromDigest(digest ++ Ints.toByteArray(idx)), amount))

override def serializer: Serializer[M] = ScriptedAssetDirectiveSerializer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ case class TransferDirective(address: Address,

override def boxes(digest: Digest32, idx: Int): Seq[EncryBaseBox] =
Seq(AssetBox(EncryProposition.addressLocked(address),
Utils.nonceFromDigest(digest ++ Ints.toByteArray(idx)), amount, tokenIdOpt))
nonceFromDigest(digest ++ Ints.toByteArray(idx)), amount, tokenIdOpt))

override def serializer: Serializer[M] = TransferDirectiveSerializer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import org.encryfoundation.common.utils.TaggedTypes.{ModifierId, ModifierTypeId}
import org.encryfoundation.common.utils.constants.TestNetConstants
import org.encryfoundation.common.validation.{ModifierValidator, ValidationResult}
import org.encryfoundation.prismlang.core.wrapped.{PObject, PValue}
import org.encryfoundation.prismlang.utils.Hasher

case class Transaction(fee: Amount,
timestamp: Long,
inputs: IndexedSeq[Input],
directives: IndexedSeq[Directive],
defaultProofOpt: Option[Proof]) extends NodeViewModifier with ModifierValidator with PConvertible {
defaultProofOpt: Option[Proof])
extends NodeViewModifier with ModifierValidator with PConvertible with Hasher with BytesToSign {

override val modifierTypeId: ModifierTypeId = Transaction.modifierTypeId

Expand All @@ -36,9 +38,9 @@ case class Transaction(fee: Amount,

def toTransactionProto: TransactionProtoMessage = TransactionProtoSerializer.toProto(this)

val messageToSign: Array[Byte] = UnsignedTransaction.bytesToSign(fee, timestamp, inputs, directives)
val messageToSign: Array[Byte] = bytesToSign(fee, timestamp, inputs, directives)

val id: ModifierId = ModifierId !@@ Algos.hash(messageToSign)
val id: ModifierId = ModifierId !@@ blake2b.digest(messageToSign)

val size: Int = this.bytes.length

Expand Down Expand Up @@ -182,9 +184,9 @@ object TransactionSerializer extends Serializer[Transaction] {
case class UnsignedTransaction(fee: Amount,
timestamp: Long,
inputs: IndexedSeq[Input],
directives: IndexedSeq[Directive]) {
directives: IndexedSeq[Directive]) extends BytesToSign with Hasher {

val messageToSign: Array[Byte] = UnsignedTransaction.bytesToSign(fee, timestamp, inputs, directives)
val messageToSign: Array[Byte] = bytesToSign(fee, timestamp, inputs, directives)

def toSigned(proofs: IndexedSeq[Seq[Proof]], defaultProofOpt: Option[Proof]): Transaction = {
val signedInputs: IndexedSeq[Input] = inputs.zipWithIndex.map { case (input, idx) =>
Expand All @@ -194,13 +196,14 @@ case class UnsignedTransaction(fee: Amount,
}
}

object UnsignedTransaction {
trait BytesToSign {
this: Hasher =>

def bytesToSign(fee: Amount,
timestamp: Long,
unlockers: IndexedSeq[Input],
directives: IndexedSeq[Directive]): Digest32 =
Algos.hash(Bytes.concat(
Digest32 @@ blake2b.digest(Bytes.concat(
unlockers.map(_.bytesWithoutProof).foldLeft(Array[Byte]())(_ ++ _),
directives.map(_.bytes).foldLeft(Array[Byte]())(_ ++ _),
Longs.toByteArray(timestamp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import BoxesProto.BoxProtoMessage
import com.google.common.primitives.Longs
import io.circe.{Decoder, DecodingFailure, Encoder}
import org.encryfoundation.common.modifiers.state.box.EncryBox.BxTypeId
import org.encryfoundation.common.utils.Algos
import org.encryfoundation.common.utils.TaggedTypes.ADKey
import org.encryfoundation.prismlang.core.wrapped.{PObject, PValue}
import org.encryfoundation.prismlang.core.{PConvertible, Types}
import org.encryfoundation.prismlang.utils.Hasher

import scala.util.Try

trait EncryBaseBox extends Box[EncryProposition] with PConvertible {
trait EncryBaseBox extends Box[EncryProposition] with PConvertible with Hasher {

val typeId: BxTypeId

val nonce: Long

def serializeToProto: BoxProtoMessage

override lazy val id: ADKey = ADKey @@ Algos.hash(Longs.toByteArray(nonce)).updated(0, typeId)
override lazy val id: ADKey = ADKey @@ blake2b.digest(Longs.toByteArray(nonce)).updated(0, typeId)

def isAmountCarrying: Boolean = this.isInstanceOf[MonetaryBox]

Expand Down
5 changes: 0 additions & 5 deletions src/main/scala/org/encryfoundation/common/utils/Algos.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package org.encryfoundation.common.utils

import java.nio.charset.Charset
import org.encryfoundation.common.utils.TaggedTypes.LeafData
import scorex.crypto.authds.merkle.MerkleTree
import scorex.crypto.encode.Base16
import scorex.crypto.hash.{Blake2b256, Digest32}
import scorex.crypto.authds.{LeafData => ScorexLeaf}
import scala.util.Try

object Algos {
Expand All @@ -22,8 +20,5 @@ object Algos {

val charset: Charset = Charset.defaultCharset()

def merkleTreeRoot(elements: Seq[LeafData]): Digest32 =
if (elements.isEmpty) emptyMerkleTreeRoot else MerkleTree(elements.map(ScorexLeaf @@ _.repr))(hash).rootHash

lazy val emptyMerkleTreeRoot: Digest32 = Algos.hash(LeafData @@ Array[Byte]())
}
3 changes: 0 additions & 3 deletions src/main/scala/org/encryfoundation/common/utils/Utils.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.encryfoundation.common.utils

import java.nio.{ByteBuffer, ByteOrder}
import com.google.common.primitives.Longs
import org.bouncycastle.crypto.Digest

object Utils {
Expand Down Expand Up @@ -32,6 +31,4 @@ object Utils {
}

def validateSolution(solution: Array[Byte], target: Double): Boolean = countLeadingZeroes(solution) >= target

def nonceFromDigest(digest: Array[Byte]): Long = Longs.fromByteArray(Algos.hash(digest).take(8))
}