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

co.topl.crypto.signatures.eddsa.X25519.scala Maven / Gradle / Ivy

The newest version!
package co.topl.crypto.signatures.eddsa

import java.security.SecureRandom

/**
 * AMS 2021:
 * X25519 ported from BouncyCastle
 * Licensing: https://www.bouncycastle.org/licence.html
 * Copyright (c) 2000 - 2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

private[crypto] class X25519 extends EC {
  val POINT_SIZE = 32
  val SCALAR_SIZE = 32
  val C_A = 486662
  val C_A24: Int = (C_A + 2) / 4

  def calculateAgreement(k: Array[Byte], kOff: Int, u: Array[Byte], uOff: Int, r: Array[Byte], rOff: Int): Boolean = {
    scalarMult(k, kOff, u, uOff, r, rOff)
    !areAllZeroes(r, rOff, POINT_SIZE)
  }

  override def decodeScalar(k: Array[Byte], kOff: Int, n: Array[Int]): Unit = {
    for (i <- 0 until 8)
      n(i) = decode32(k, kOff + i * 4)
    n(0) &= 0xfffffff8
    n(7) &= 0x7fffffff
    n(7) |= 0x40000000
  }

  def generatePrivateKey(random: SecureRandom, k: Array[Byte]): Unit = {
    random.nextBytes(k)
    k(0) = (k(0) & 0xf8).toByte
    k(SCALAR_SIZE - 1) = (k(SCALAR_SIZE - 1) & 0x7f).toByte
    k(SCALAR_SIZE - 1) = (k(SCALAR_SIZE - 1) | 0x40).toByte
  }

  def generatePublicKey(k: Array[Byte], kOff: Int, r: Array[Byte], rOff: Int): Unit =
    scalarMultBase(k, kOff, r, rOff)

  private def pointDouble(x: Array[Int], z: Array[Int]): Unit = {
    val A = x25519Field.create
    val B = x25519Field.create
    x25519Field.apm(x, z, A, B)
    x25519Field.sqr(A, A)
    x25519Field.sqr(B, B)
    x25519Field.mul(A, B, x)
    x25519Field.sub(A, B, A)
    x25519Field.mul(A, C_A24, z)
    x25519Field.add(z, B, z)
    x25519Field.mul(z, A, z)
  }

  def scalarMult(k: Array[Byte], kOff: Int, u: Array[Byte], uOff: Int, r: Array[Byte], rOff: Int): Unit = {
    val n = new Array[Int](8)
    decodeScalar(k, kOff, n)
    val x1 = x25519Field.create
    x25519Field.decode(u, uOff, x1)
    val x2 = x25519Field.create
    x25519Field.copy(x1, 0, x2, 0)
    val z2 = x25519Field.create
    z2(0) = 1
    val x3 = x25519Field.create
    x3(0) = 1
    val z3 = x25519Field.create
    val t1 = x25519Field.create
    val t2 = x25519Field.create
    var bit = 254
    var swap = 1
    do {
      x25519Field.apm(x3, z3, t1, x3)
      x25519Field.apm(x2, z2, z3, x2)
      x25519Field.mul(t1, x2, t1)
      x25519Field.mul(x3, z3, x3)
      x25519Field.sqr(z3, z3)
      x25519Field.sqr(x2, x2)
      x25519Field.sub(z3, x2, t2)
      x25519Field.mul(t2, C_A24, z2)
      x25519Field.add(z2, x2, z2)
      x25519Field.mul(z2, t2, z2)
      x25519Field.mul(x2, z3, x2)
      x25519Field.apm(t1, x3, x3, z3)
      x25519Field.sqr(x3, x3)
      x25519Field.sqr(z3, z3)
      x25519Field.mul(z3, x1, z3)
      bit -= 1
      val word = bit >>> 5
      val shift = bit & 0x1f
      val kt = (n(word) >>> shift) & 1
      swap ^= kt
      x25519Field.cswap(swap, x2, x3)
      x25519Field.cswap(swap, z2, z3)
      swap = kt
    } while (bit >= 3)
    for (_ <- 0 until 3)
      pointDouble(x2, z2)
    x25519Field.inv(z2, z2)
    x25519Field.mul(x2, z2, x2)
    x25519Field.normalize(x2)
    x25519Field.encode(x2, r, rOff)
  }

  def scalarMultBase(k: Array[Byte], kOff: Int, r: Array[Byte], rOff: Int): Unit = {
    val y = x25519Field.create
    val z = x25519Field.create
    scalarMultBaseYZ(k, kOff, y, z)
    x25519Field.apm(z, y, y, z)
    x25519Field.inv(z, z)
    x25519Field.mul(y, z, y)
    x25519Field.normalize(y)
    x25519Field.encode(y, r, rOff)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy