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

sigmastate.crypto.DLogProtocol.scala Maven / Gradle / Ivy

The newest version!
package sigmastate.crypto

import scorex.util.encode.Base16
import sigma.crypto.{BigIntegers, EcPointType}
import sigma.data.ProveDlog
import sigma.serialization.GroupElementSerializer
import sigma.crypto.CryptoConstants.dlogGroup
import sigmastate.crypto.VerifierMessage.Challenge

import java.math.BigInteger

/** Implementation of sigma protocol steps using discrete logarithm problem in EC group. */
object DLogProtocol {

  /** Secret key of discrete logarithm signature protocol.
    * @param w secret number in [0, q-1]
    *          where q - an order of DLog group.
    */
  case class DLogProverInput(w: BigInteger)
    extends SigmaProtocolPrivateInput[ProveDlog] {

    import sigma.crypto.CryptoConstants.dlogGroup

    override lazy val publicImage: ProveDlog = {
      val g = dlogGroup.generator
      ProveDlog(dlogGroup.exponentiate(g, w))
    }
  }

  object DLogProverInput {

    import sigma.crypto.CryptoConstants.dlogGroup

    /** Create random secret in a range 0..q-1, where q - an order of DLog group. */
    def random(): DLogProverInput = {
      val qMinusOne = dlogGroup.order.subtract(BigInteger.ONE)
      val w = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, dlogGroup.secureRandom)
      DLogProverInput(w)
    }
  }

  /** First message of dlog-based sigma protocol.
    * @param ecData commitment to randomness ecData = G^r, where
    *               G - generator of EC group,
    *               r - random number known only to prover from [0, q-1] range,
    *               where q - order of EC group.
    */
  case class FirstDLogProverMessage(ecData: EcPointType) extends FirstProverMessage {
    override def bytes: Array[Byte] = {
      GroupElementSerializer.toBytes(ecData)
    }

    override def toString = s"FirstDLogProverMessage(${Base16.encode(bytes)})"
  }

  /** Second message of dlog-based sigma protocol.
    * @param z response to the challenge from the verifier
    * @see responseToChallenge()
    */
  case class SecondDLogProverMessage(z: BigInt) extends SecondProverMessage


  /** Prover operations of dlog-based sigma protocol. */
  object DLogProver extends SigmaProtocolProver {
    import sigma.crypto.CryptoConstants.secureRandom

    /** Generate a first prover message with a commitment to a secret random number. */
    def firstMessage(): (BigInteger, FirstDLogProverMessage) = {
      import sigma.crypto.CryptoConstants.dlogGroup

      val qMinusOne = dlogGroup.order.subtract(BigInteger.ONE) // q - 1
      val r = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, secureRandom) // r <- [0, q-1]
      val a = dlogGroup.exponentiate(dlogGroup.generator, r) // g^r
      r -> FirstDLogProverMessage(a)
    }

    /** Creates a second message of sigma protocol by computing
      * `z = rnd + challenge * privateInput.w mod q`, where q - order of EC group.
      *
      * @param privateInput secret known only to prover from [0, q-1] range,
      * @param rnd          random number generated by the prover (secret random number used to
      *                     compute commitment)
      * @param challenge    from the verifier (also computed by the prover in non-interactive case)
      */
    def secondMessage(privateInput: DLogProverInput, rnd: BigInteger, challenge: Challenge): SecondDLogProverMessage = {
      val z = responseToChallenge(privateInput, rnd, challenge)
      SecondDLogProverMessage(z)
    }

    /** Simulation of sigma protocol. */
    def simulate(publicInput: ProveDlog, challenge: Challenge): (FirstDLogProverMessage, SecondDLogProverMessage) = {
      val qMinusOne = dlogGroup.order.subtract(BigInteger.ONE)

      //SAMPLE a random z <- Zq
      val z = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, secureRandom)

      //COMPUTE a = g^z*h^(-e)  (where -e here means -e mod q)
      val e: BigInteger = new BigInteger(1, challenge.toArray)
      val minusE = dlogGroup.order.subtract(e)
      val hToE = dlogGroup.exponentiate(publicInput.value, minusE)
      val gToZ = dlogGroup.exponentiate(dlogGroup.generator, z)
      val a = dlogGroup.multiplyGroupElements(gToZ, hToE)
      FirstDLogProverMessage(a) -> SecondDLogProverMessage(z)
    }

    /**
      * The function computes initial prover's commitment to randomness
      * ("a" message of the sigma-protocol) based on the verifier's challenge ("e")
      * and prover's response ("z")
      *
      * g^z = a*h^e => a = g^z/h^e
      *
      * @param proposition proposition being proved
      * @param challenge   challenge from verifier
      * @param secondMessage prover's response to the challenge
      * @return
      */
    def computeCommitment(proposition: ProveDlog,
                          challenge: Challenge,
                          secondMessage: SecondDLogProverMessage): EcPointType = {
      val g = dlogGroup.generator
      val h = proposition.value

      // COMPUTE a = g^z / h^e
      dlogGroup.multiplyGroupElements(
        dlogGroup.exponentiate(g, secondMessage.z.underlying()),
        dlogGroup.inverseOf(dlogGroup.exponentiate(h, new BigInteger(1, challenge.toArray))))
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy