All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavesplatform.common.merkle.ScryptoMerkleProof.scala Maven / Gradle / Ivy

The newest version!
package com.wavesplatform.common.merkle

import com.wavesplatform.common.merkle.ScryptoMerkleProof._

import scala.util.Try

case class ScryptoMerkleProof(leafData: LeafData, levels: Seq[(Digest, Byte)]) {
  def valid(expectedRootHash: Digest): Boolean = {
    val leafHash = Merkle.hash(LeafPrefix +: leafData)

    levels
      .foldLeft(leafHash) {
        case (prevHash, (hash, side)) =>
          if (side == ScryptoMerkleProof.LeftSide) {
            Merkle.hash(InternalNodePrefix +: (prevHash ++ hash))
          } else {
            Merkle.hash(InternalNodePrefix +: (hash ++ prevHash))
          }
      }
      .sameElements(expectedRootHash)
  }
}

object ScryptoMerkleProof {
  val LeftSide: Byte  = 0.toByte
  val RightSide: Byte = 1.toByte

  val LeafPrefix: Byte         = 0: Byte
  val InternalNodePrefix: Byte = 1: Byte

  def parse(proofBytes: Array[Byte], valueHash: Array[Byte]): Option[ScryptoMerkleProof] =
    parseMerkleProofLevels(proofBytes).map { data =>
      ScryptoMerkleProof(valueHash, data)
    }.toOption

  private def parseMerkleProofLevels(arr: Array[Byte]): Either[String, List[(Digest, Byte)]] = {
    def parseHashAndSide(arr: Array[Byte]): Either[String, (Byte, Digest, Array[Byte])] = {
      val side =
        if (arr(0) == ScryptoMerkleProof.LeftSide) ScryptoMerkleProof.LeftSide
        else ScryptoMerkleProof.RightSide
      val hashLen   = arr(1).toInt
      lazy val hash = arr.slice(2, 2 + hashLen)

      Either
        .cond(
          hashLen >= 0,
          (side, hash, arr.drop(2 + hashLen)),
          s"Invalid proof hash length: $hashLen"
        )
    }

    def parseLevels(arr: Array[Byte], acc: List[(Digest, Byte)]): Either[String, List[(Digest, Byte)]] = {
      if (arr.nonEmpty) {
        parseHashAndSide(arr)
          .flatMap {
            case (side, hash, rest) =>
              parseLevels(rest, (hash, side) :: acc)
          }
      } else Right(acc.reverse)
    }

    Try(parseLevels(arr, Nil))
      .getOrElse(Left("Can't parse proof bytes"))
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy