diff --git a/README.md b/README.md index 05ad5b9..4064ad3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Currently, following algorithms are implemented: - Poseidon hash - Edwards curve arithmetic - Curves: Jubjub, BabyJubjub, AltBabyJubjub +- Schnorr EdDSA signatures with Blake2 hash ### Getting started diff --git a/build.gradle b/build.gradle index dacc29b..4a0e37f 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id "com.jfrog.bintray" version "1.8.5" id "maven-publish" id 'java-library' + id 'com.diffplug.gradle.spotless' version '3.28.1' } group = "com.ing.dlt" @@ -20,9 +21,16 @@ dependencies { } test { - useJUnitPlatform() + useJUnitPlatform { + excludeTags("benchmark") + } } +task benchmark(type: Test) { + useJUnitPlatform { + includeTags("benchmark") + } +} compileKotlin { kotlinOptions.jvmTarget = "1.8" } @@ -35,6 +43,11 @@ java { withJavadocJar() } +spotless { + kotlin { + ktlint("0.37.1") + } +} // Bintray publishing bintray { diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurve.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurve.kt index f9efddf..7315150 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurve.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurve.kt @@ -16,4 +16,4 @@ interface EllipticCurve : Arithmetic { // identity element val zero: EllipticCurvePoint -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurvePoint.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurvePoint.kt index 90df976..fde92af 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurvePoint.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/EllipticCurvePoint.kt @@ -8,4 +8,4 @@ data class EllipticCurvePoint(val x: BigInteger, val y: BigInteger, val curve: E fun scalarMult(scalar: BigInteger): EllipticCurvePoint = curve.scalarMult(this, scalar) fun double(): EllipticCurvePoint = curve.double(this) fun isOnCurve(): Boolean = curve.isOnCurve(this) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/HashEnum.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/HashEnum.kt new file mode 100644 index 0000000..a85baba --- /dev/null +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/HashEnum.kt @@ -0,0 +1,9 @@ +package com.ing.dlt.zkkrypto.ecc + +enum class HashEnum { + BLAKE2S, + BLAKE2B, + PEDERSEN, + MIMC, + POSEIDON +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/ZKHash.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/ZKHash.kt index 875b06e..b0d0f8c 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/ZKHash.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/ZKHash.kt @@ -8,4 +8,4 @@ interface ZKHash { val hashLength: Int fun hash(msg: ByteArray): ByteArray -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/Arithmetic.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/Arithmetic.kt index 355906d..ab79564 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/Arithmetic.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/Arithmetic.kt @@ -8,4 +8,4 @@ interface Arithmetic { fun scalarMult(p: EllipticCurvePoint, scalar: BigInteger): EllipticCurvePoint fun double(p: EllipticCurvePoint): EllipticCurvePoint fun isOnCurve(p: EllipticCurvePoint): Boolean -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/EdwardsForm.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/EdwardsForm.kt index b7c6ddb..ec1cd33 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/EdwardsForm.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/arithmetic/EdwardsForm.kt @@ -12,7 +12,7 @@ object EdwardsForm : Arithmetic { // x = (pointA.x * pointB.y + pointA.y * pointB.x) / (1 + d * pointA.x * pointB.x * pointA.y * pointB.y) // y = (pointA.y * pointB.y + pointA.x * pointB.x) / (1 - d * pointA.x * pointB.x * pointA.y * pointB.y) - if(a.curve != b.curve) throw IllegalArgumentException("Points should be on the same curve, A's curve is ${a.curve}, B's curve is ${b.curve}") + if (a.curve != b.curve) throw IllegalArgumentException("Points should be on the same curve, A's curve is ${a.curve}, B's curve is ${b.curve}") val curve = a.curve as EdwardsCurve @@ -43,7 +43,7 @@ object EdwardsForm : Arithmetic { var doubling: EllipticCurvePoint = p.copy() var result: EllipticCurvePoint = p.curve.zero - for( i in 0 until s.bitLength() ) { + for (i in 0 until s.bitLength()) { if (s.testBit(i)) { result = result.add(doubling) } @@ -69,5 +69,4 @@ object EdwardsForm : Arithmetic { return y2.subtract(x2).mod(p.curve.R) == BigInteger.ONE.add(dTimesX2Y2).mod(p.curve.R) } - -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/AltBabyJubjub.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/AltBabyJubjub.kt index 185fd7b..fe80b6b 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/AltBabyJubjub.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/AltBabyJubjub.kt @@ -12,4 +12,4 @@ object AltBabyJubjub : EdwardsCurve { override val cofactor: BigInteger = BigInteger.valueOf(8) override val zero: EllipticCurvePoint = EllipticCurvePoint(BigInteger.ZERO, BigInteger.ONE, this) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/BabyJubjub.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/BabyJubjub.kt index a695a00..31376c4 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/BabyJubjub.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/BabyJubjub.kt @@ -11,5 +11,4 @@ object BabyJubjub : EdwardsCurve { override val cofactor: BigInteger = BigInteger.valueOf(8) override val zero: EllipticCurvePoint = EllipticCurvePoint(BigInteger.ZERO, BigInteger.ONE, this) - -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/EdwardsCurve.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/EdwardsCurve.kt index cfe7a60..1fbc88f 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/EdwardsCurve.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/EdwardsCurve.kt @@ -1,8 +1,8 @@ package com.ing.dlt.zkkrypto.ecc.curves -import com.ing.dlt.zkkrypto.ecc.arithmetic.EdwardsForm import com.ing.dlt.zkkrypto.ecc.EllipticCurve import com.ing.dlt.zkkrypto.ecc.EllipticCurvePoint +import com.ing.dlt.zkkrypto.ecc.arithmetic.EdwardsForm import java.math.BigInteger /** @@ -19,5 +19,5 @@ interface EdwardsCurve : EllipticCurve { override fun double(p: EllipticCurvePoint): EllipticCurvePoint = EdwardsForm.double(p) - override fun isOnCurve(p: EllipticCurvePoint): Boolean = EdwardsForm.isOnCurve(p) -} \ No newline at end of file + override fun isOnCurve(p: EllipticCurvePoint): Boolean = EdwardsForm.isOnCurve(p) +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/Jubjub.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/Jubjub.kt index dd60809..c582569 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/Jubjub.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/curves/Jubjub.kt @@ -12,4 +12,4 @@ object Jubjub : EdwardsCurve { override val cofactor: BigInteger = BigInteger.valueOf(8) override val zero: EllipticCurvePoint = EllipticCurvePoint(BigInteger.ZERO, BigInteger.ONE, this) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7Hash.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7Hash.kt index 2dc4eac..05b9351 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7Hash.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7Hash.kt @@ -6,17 +6,16 @@ import org.bouncycastle.jcajce.provider.digest.Keccak import java.math.BigInteger import kotlin.math.min - data class Mimc7Hash( val r: BigInteger = BabyJubjub.R, val numRounds: Int = defaultNumRounds, val roundConstants: List = generateRoundConstants(r = r, numRounds = numRounds) -): ZKHash { +) : ZKHash { /** * Hash size in bytes */ - override val hashLength = r.bitLength() / 8 + if(r.bitLength() / 8 != 0) 1 else 0 + override val hashLength = r.bitLength() / 8 + if (r.bitLength() / 8 != 0) 1 else 0 override fun hash(msg: ByteArray): ByteArray = hash(bytesToField(msg)) @@ -24,7 +23,7 @@ data class Mimc7Hash( // check if all elements are in field R msg.forEach { - if( it > r) throw IllegalArgumentException("Element $it is not in field $r") + if (it > r) throw IllegalArgumentException("Element $it is not in field $r") } var result = BigInteger.ZERO @@ -33,7 +32,7 @@ data class Mimc7Hash( result = (result + it + hashElement(it, result)) % r } val bytes = result.toByteArray() - return if(bytes.size == hashLength) + return if (bytes.size == hashLength) bytes else ByteArray(hashLength - bytes.size).plus(bytes) @@ -63,7 +62,7 @@ data class Mimc7Hash( for (i in msg.indices step n) { // We revert array here because bytes are supposed to be little-endian unlike BigInteger - val int = BigInteger(1, msg.sliceArray(i until min(i+n, msg.size)).reversedArray()) + val int = BigInteger(1, msg.sliceArray(i until min(i + n, msg.size)).reversedArray()) ints.add(int) } return ints @@ -99,4 +98,4 @@ data class Mimc7Hash( } else bytes } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/GeneratorsGenerator.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/GeneratorsGenerator.kt index eba4a1e..4c8bb78 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/GeneratorsGenerator.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/GeneratorsGenerator.kt @@ -1,7 +1,7 @@ package com.ing.dlt.zkkrypto.ecc.pedersenhash -import com.ing.dlt.zkkrypto.ecc.EllipticCurvePoint import com.ing.dlt.zkkrypto.ecc.EllipticCurve +import com.ing.dlt.zkkrypto.ecc.EllipticCurvePoint import com.ing.dlt.zkkrypto.ecc.curves.AltBabyJubjub import com.ing.dlt.zkkrypto.ecc.curves.BabyJubjub import com.ing.dlt.zkkrypto.ecc.curves.Jubjub @@ -162,4 +162,4 @@ object GeneratorsGenerator { else -> throw IllegalArgumentException("Unknown curve: $curve") } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHash.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHash.kt index a9d2fff..116ccf3 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHash.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHash.kt @@ -20,14 +20,14 @@ data class PedersenHash( val curve: EllipticCurve, val generators: List = GeneratorsGenerator.defaultForCurve(curve), val defaultSalt: BitArray? = null -): ZKHash { +) : ZKHash { init { generators.forEach { if (!it.isOnCurve()) throw IllegalStateException("Point is not on the curve") - if(it.curve != generators.first().curve) throw IllegalStateException("Generators should belong to same curve") + if (it.curve != generators.first().curve) throw IllegalStateException("Generators should belong to same curve") } - if(window != 3) throw IllegalStateException("Only supporting window size 3 at the moment") + if (window != 3) throw IllegalStateException("Only supporting window size 3 at the moment") } private val chunkShift = window + 1 @@ -46,18 +46,18 @@ data class PedersenHash( var hashPoint = curve.zero val salted = salted(msg, salt) - if(salted.size > maxBitLength()) throw IllegalArgumentException("Message is too long, length = ${salted.size}, limit = ${maxBitLength()}") + if (salted.size > maxBitLength()) throw IllegalArgumentException("Message is too long, length = ${salted.size}, limit = ${maxBitLength()}") val m = padded(salted) val numProducts = numProducts(m) for (i in 0 until numProducts) { - hashPoint = hashPoint.add(generators[i].scalarMult(product(m, i))) + hashPoint = hashPoint.add(generators[i].scalarMult(product(m, i))) } // we want constant size hashes so we add trailing zero bytes to the beginning val bytes = hashPoint.x.toByteArray() - return if(bytes.size == hashLength) + return if (bytes.size == hashLength) bytes else ByteArray(hashLength - bytes.size).plus(bytes) @@ -68,11 +68,11 @@ data class PedersenHash( val lowestBitIndex = (productIndex * chunksPerGenerator + chunkIndex) * window var chunk = BigInteger.ONE - for(i in 0 until window-1) { + for (i in 0 until window - 1) { chunk += m.get(lowestBitIndex + i).shiftLeft(i) } - if(m.testBit(lowestBitIndex + (window-1))) { + if (m.testBit(lowestBitIndex + (window - 1))) { // only works for ZCash 3-bits window now because iden3 4-bit algorithm uses different sign switch :shrug: chunk = chunk.negate() } @@ -81,7 +81,7 @@ data class PedersenHash( } private fun fieldNegate(element: BigInteger): BigInteger { - return if(element >= BigInteger.ZERO) { + return if (element >= BigInteger.ZERO) { element } else { curve.S + element @@ -93,7 +93,7 @@ data class PedersenHash( var product = BigInteger.ZERO - for(j in 0 until numChunksInProduct(msg, i)) { + for (j in 0 until numChunksInProduct(msg, i)) { val chunk = fieldNegate(chunk(msg, i, j).shiftLeft(chunkShift * j)) product += chunk } @@ -104,13 +104,13 @@ data class PedersenHash( // chunksPerGenerator in most cases but variable for last product (it can be shorter) private fun numChunksInProduct(msg: BitArray, productIndex: Int): Int { - val lastProduct = if(msg.size % productBitSize() == 0) msg.size / productBitSize() - 1 else msg.size / productBitSize() + val lastProduct = if (msg.size % productBitSize() == 0) msg.size / productBitSize() - 1 else msg.size / productBitSize() - return if(productIndex == lastProduct) { - if(msg.size % productBitSize() == 0) + return if (productIndex == lastProduct) { + if (msg.size % productBitSize() == 0) chunksPerGenerator else { - msg.size % productBitSize() / window + if(msg.size % window == 0) 0 else 1 + msg.size % productBitSize() / window + if (msg.size % window == 0) 0 else 1 } } else chunksPerGenerator } @@ -123,7 +123,7 @@ data class PedersenHash( return generators.size * productBitSize() } - private fun numProducts(m: BitArray) = min(generators.size, m.size / productBitSize() + if(m.size % productBitSize() == 0) 0 else 1) + private fun numProducts(m: BitArray) = min(generators.size, m.size / productBitSize() + if (m.size % productBitSize() == 0) 0 else 1) private fun salted(msg: BitArray, salt: BitArray?): BitArray { return salt?.plus(msg) ?: msg @@ -143,4 +143,3 @@ data class PedersenHash( fun zcash() = PedersenHash(curve = Jubjub, chunksPerGenerator = 63) } } - diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/Constants.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/Constants.kt index 0ad466f..00f1f11 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/Constants.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/Constants.kt @@ -16,8 +16,8 @@ data class Constants( fun defaultRoundConstants(): Constants { return Constants( - defaultCStrings.map { it.map { BigInteger(it, 10) }}, - defaultMStrings.map { it.map { it.map { BigInteger(it, 10) }}} , + defaultCStrings.map { it.map { BigInteger(it, 10) } }, + defaultMStrings.map { it.map { it.map { BigInteger(it, 10) } } }, defaultNumRoundsF, defaultNumRoundsP ) @@ -3472,4 +3472,4 @@ data class Constants( ) ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHash.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHash.kt index c03d547..3ce89ed 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHash.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHash.kt @@ -9,27 +9,27 @@ import kotlin.math.min data class PoseidonHash( val r: BigInteger = BabyJubjub.R, val constants: Constants = defaultRoundConstants() -): ZKHash { +) : ZKHash { /** * Hash size in bytes */ - override val hashLength = r.bitLength() / 8 + if(r.bitLength() / 8 != 0) 1 else 0 + override val hashLength = r.bitLength() / 8 + if (r.bitLength() / 8 != 0) 1 else 0 override fun hash(msg: ByteArray): ByteArray = hash(bytesToField(msg)).toByteArray() - fun hash(msg: List): BigInteger { + fun hash(msg: List): BigInteger { if (msg.isEmpty() || msg.size >= constants.numRoundsP.size - 1) throw Exception("Invalid inputs length: ${msg.size}, maximum allowed: ${constants.numRoundsP.size - 2}") - msg.forEach { if(it >= r) throw Exception("Element {$it} is out of the field {$r}") } + msg.forEach { if (it >= r) throw Exception("Element {$it} is out of the field {$r}") } val t = msg.size + 1 var state = msg.plus(BigInteger.ZERO).toMutableList() - val nRoundsP = constants.numRoundsP[t-2] + val nRoundsP = constants.numRoundsP[t - 2] val lastRound = constants.numRoundsF + nRoundsP - 1 @@ -37,7 +37,7 @@ data class PoseidonHash( // Add Round Key for (i in state.indices) { - state[i] = state[i] + constants.c[t-2][round * t + i] + state[i] = state[i] + constants.c[t - 2][round * t + i] } // S-Box @@ -53,7 +53,7 @@ data class PoseidonHash( // If not last round: mix (via matrix multiplication) if (round != lastRound) { - state = mix(state, constants.m[t-2]).toMutableList() + state = mix(state, constants.m[t - 2]).toMutableList() } } @@ -87,9 +87,9 @@ data class PoseidonHash( val ints = mutableListOf() for (i in msg.indices step n) { - val int = BigInteger(1, msg.sliceArray(i until min(i+n, msg.size))) + val int = BigInteger(1, msg.sliceArray(i until min(i + n, msg.size))) ints.add(int) } return ints } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/FixedGenerators.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/FixedGenerators.kt new file mode 100644 index 0000000..398aea5 --- /dev/null +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/FixedGenerators.kt @@ -0,0 +1,49 @@ +package com.ing.dlt.zkkrypto.ecc.schnorr + +import com.ing.dlt.zkkrypto.ecc.EllipticCurvePoint +import com.ing.dlt.zkkrypto.ecc.curves.AltBabyJubjub +import java.math.BigInteger + +object FixedGenerators { + /** + * Base points to be used in different protocols. Right now we only use SpendingKeyGenerator for Schnorr signatures + */ + val altBabyJubjubFixedGenerators = listOf( + // ProofGenerationKey + EllipticCurvePoint( + BigInteger("1ee77350e12c9895b2ce939094e92af260b4a56c9a4f09230e0ff0c5786a30ca", 16), + BigInteger("18c6409592649c36a79a15177b4aec5784075f5a03f9a1b09a57af4b288f929d", 16), + AltBabyJubjub + ), + // NoteCommitmentRandomness + EllipticCurvePoint( + BigInteger("1f8151972518489ee4e4877f27a98ee98b16045a3df8a623f782090b4592bcee", 16), + BigInteger("2590f9fbe09f7f5e83a29e97bb97981a6125edb96af6577c738af072bf1142e4", 16), + AltBabyJubjub + ), + // NullifierPosition + EllipticCurvePoint( + BigInteger("06365233b672101388d5d99a9514a8ba26ccbbae043205293d8aa2b1254dda88", 16), + BigInteger("063007fe32cc0f6934b24bfc11bdaaf82cdaab270e596c1a1cac59ab9d85ab81", 16), + AltBabyJubjub + ), + // ValueCommitmentValue + EllipticCurvePoint( + BigInteger("0a71462a426047520559654bf211850d5060582816d27c4a80dd05c85112b2ad", 16), + BigInteger("0042358566d0cd4c9cfa3b48b85b5b7653cd483fa71222b378a6952ab6232e5f", 16), + AltBabyJubjub + ), + // ValueCommitmentRandomness + EllipticCurvePoint( + BigInteger("21108e5b084a15ced07f197a5e7ae8b7c52076fdb63c5b9b245ba5e2711b8abc", 16), + BigInteger("0c4ea6f36b841e28a3bea6b126ac247e7f0558d717b6d5c4734063cd762a5099", 16), + AltBabyJubjub + ), + // SpendingKeyGenerator + EllipticCurvePoint( + BigInteger("2ef3f9b423a2c8c74e9803958f6c320e854a1c1c06cd5cc8fd221dc052d76df7", 16), + BigInteger("05a01167ea785d3f784224644a68e4067532c815f5f6d57d984b5c0e9c6c94b7", 16), + AltBabyJubjub + ) + ) +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/SchnorrSignature.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/SchnorrSignature.kt new file mode 100644 index 0000000..7c6ee61 --- /dev/null +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/SchnorrSignature.kt @@ -0,0 +1,174 @@ +package com.ing.dlt.zkkrypto.ecc.schnorr + +import com.ing.dlt.zkkrypto.ecc.EllipticCurve +import com.ing.dlt.zkkrypto.ecc.EllipticCurvePoint +import com.ing.dlt.zkkrypto.ecc.HashEnum +import com.ing.dlt.zkkrypto.ecc.curves.AltBabyJubjub +import com.ing.dlt.zkkrypto.ecc.schnorr.FixedGenerators.altBabyJubjubFixedGenerators +import com.ing.dlt.zkkrypto.util.asUnsigned +import org.bouncycastle.crypto.digests.Blake2bDigest +import org.bouncycastle.crypto.digests.Blake2sDigest +import java.lang.IllegalArgumentException +import java.math.BigInteger +import java.security.SecureRandom + +/** + * Implementation of Schnorr signatures + * This implementation uses AltBabyJubJub curve and Blake2 hash + */ + +class SchnorrSignature( + val curve: EllipticCurve, + val base: EllipticCurvePoint, + val compPersonalization: ByteArray, + val msgPersonalization: ByteArray +) { + + companion object { + val zinc = SchnorrSignature( + curve = AltBabyJubjub, + base = altBabyJubjubFixedGenerators[5], + compPersonalization = "Zcash_RedJubjubH".toByteArray(), + msgPersonalization = "Matter_H".toByteArray() + ) + + const val MAX_MESSAGE_SIZE = 32 + const val BLAKE2B_DIGEST_LENGTH = 64 + const val BLAKE2S_DIGEST_LENGTH = 32 + } + + private var privateKey: BigInteger + var publicKey: EllipticCurvePoint + init { + // Generate private key + privateKey = BigInteger(curve.S.bitLength(), SecureRandom()) + while (privateKey > curve.S) { + privateKey = BigInteger(curve.S.bitLength(), SecureRandom()) + } + // Compute public key + publicKey = base.scalarMult(privateKey) + } + + fun setKeys(privKey: BigInteger) { + privateKey = privKey + publicKey = base.scalarMult(privateKey) + } + + fun nextKeyPair() { + // Generate private key + privateKey = BigInteger(curve.S.bitLength(), SecureRandom()) + while (privateKey > curve.S) { + privateKey = BigInteger(curve.S.bitLength(), SecureRandom()) + } + // Compute public key + publicKey = base.scalarMult(privateKey) + } + + fun signRawMessage(msgBytes: ByteArray, seed: ByteArray): Signature { + + // Generate random r as the hash digest of Blake2b(randomBytes || msg) + val r = hashToScalar(HashEnum.BLAKE2B, compPersonalization, first = seed, second = msgBytes) + + // compute first component of the signature + val rPoint = base.scalarMult(r) + + // pad message + check(MAX_MESSAGE_SIZE - msgBytes.size >= 0) { "Message size should not be greater than MAX_MESSAGE_SIZE" } + val paddedMessage = msgBytes + ByteArray(MAX_MESSAGE_SIZE - msgBytes.size) + val uniformMessage = toUniformFieldElement(paddedMessage) + + // second component of the signature + val s = (((uniformMessage * privateKey) % curve.S) + r) % curve.S + + return Signature(rPoint, s) + } + + fun signHashedMessage(msgBytes: ByteArray, seed: ByteArray): Signature { + + // Generate random r as the hash digest of Blake2b(randomBytes || msg) + val r = hashToScalar(HashEnum.BLAKE2B, compPersonalization, first = seed, second = msgBytes) + + // compute first component of the signature + val rPoint = base.scalarMult(r) + + // hash r_x || message + val rXCoordBytes = rPoint.x.toByteArray().reversedArray() + check(MAX_MESSAGE_SIZE - msgBytes.size >= 0) { "Message size should not be greater than MAX_MESSAGE_SIZE" } + val paddedMessage = msgBytes + ByteArray(MAX_MESSAGE_SIZE - msgBytes.size) + + val messageDigest = hashToScalar(HashEnum.BLAKE2S, msgPersonalization, first = rXCoordBytes, second = paddedMessage) + + // second component of the signature + val s = (((messageDigest * privateKey) % curve.S) + r) % curve.S + + return Signature(rPoint, s) + } + + fun verifyRawMessage(msgBytes: ByteArray, signature: Signature): Boolean { + // pad message to max message size and convert to a field element + check(MAX_MESSAGE_SIZE - msgBytes.size >= 0) { "Message size should not be greater than MAX_MESSAGE_SIZE" } + val paddedMessage = msgBytes + ByteArray(MAX_MESSAGE_SIZE - msgBytes.size) + val uniformMessage = toUniformFieldElement(paddedMessage) + + val baseMultS = base.scalarMult(signature.s) + val pkMultMsg = publicKey.scalarMult(uniformMessage) + val rhs = pkMultMsg.add(signature.r) + + return rhs == baseMultS + } + + fun verifyHashedMessage(msgBytes: ByteArray, signature: Signature): Boolean { + // hash r_x || message + val rXCoordBytes = signature.r.x.toByteArray().reversedArray() + + check(MAX_MESSAGE_SIZE - msgBytes.size >= 0) { "Message size should not be greater than MAX_MESSAGE_SIZE" } + val paddedMessage = msgBytes + ByteArray(MAX_MESSAGE_SIZE - msgBytes.size) + + val messageDigest = hashToScalar(HashEnum.BLAKE2S, msgPersonalization, first = rXCoordBytes, second = paddedMessage) + + // verification + val baseMultS = base.scalarMult(signature.s) + val pkMultMsg = publicKey.scalarMult(messageDigest) + val rhs = pkMultMsg.add(signature.r) + + return rhs == baseMultS + } + + private fun hashToScalar(hashFunction: HashEnum, personalization: ByteArray, first: ByteArray, second: ByteArray): BigInteger { + val digest = when (hashFunction) { + HashEnum.BLAKE2B -> hashBlake2b(first + second, personalization) + HashEnum.BLAKE2S -> hashBlake2s(first + second, personalization) + else -> throw IllegalArgumentException("Unsupported function type") + } + + return toUniformFieldElement(digest) + } + + private fun toUniformFieldElement(value: ByteArray): BigInteger = value + .reversedArray() + .fold(BigInteger.ZERO) { acc, byte -> + val ubyte = byte.asUnsigned() + (7 downTo 0).fold(acc) { local, shift -> + val bit = ubyte shr shift and 1 + ((local + local) % curve.S + if (bit == 1) { BigInteger.ONE } else { BigInteger.ZERO }) % curve.S + } + } + + private fun hashBlake2b(bytes: ByteArray, personalization: ByteArray): ByteArray { + val blake2b = Blake2bDigest(null, BLAKE2B_DIGEST_LENGTH, null, personalization) + blake2b.reset() + blake2b.update(bytes, 0, bytes.size) + val hash = ByteArray(BLAKE2B_DIGEST_LENGTH) + blake2b.doFinal(hash, 0) + return hash + } + + private fun hashBlake2s(bytes: ByteArray, personalization: ByteArray): ByteArray { + val blake2s = Blake2sDigest(null, BLAKE2S_DIGEST_LENGTH, null, personalization) + blake2s.reset() + blake2s.update(bytes, 0, bytes.size) + val hash = ByteArray(BLAKE2S_DIGEST_LENGTH) + blake2s.doFinal(hash, 0) + return hash + } +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/Signature.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/Signature.kt new file mode 100644 index 0000000..4962374 --- /dev/null +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/Signature.kt @@ -0,0 +1,6 @@ +package com.ing.dlt.zkkrypto.ecc.schnorr + +import com.ing.dlt.zkkrypto.ecc.EllipticCurvePoint +import java.math.BigInteger + +data class Signature(val r: EllipticCurvePoint, val s: BigInteger) diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/util/BitArray.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/util/BitArray.kt index b705584..bb7a19e 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/util/BitArray.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/util/BitArray.kt @@ -8,11 +8,11 @@ import java.math.BigInteger data class BitArray(val data: ByteArray, val size: Int = data.size * 8) { fun get(i: Int): BigInteger { - return if(testBit(i)) BigInteger.ONE else BigInteger.ZERO + return if (testBit(i)) BigInteger.ONE else BigInteger.ZERO } fun testBit(i: Int): Boolean { - if(i >= size) throw ArrayIndexOutOfBoundsException(i) + if (i >= size) throw ArrayIndexOutOfBoundsException(i) val byte: Int = i / 8 val bit: Int = 7 - i % 8 return data[byte].toInt().ushr(bit).and(1) > 0 @@ -43,7 +43,7 @@ data class BitArray(val data: ByteArray, val size: Int = data.size * 8) { } fun plus(other: BitArray): BitArray { - return if(size % 8 != 0) { + return if (size % 8 != 0) { val newData = shift(other.data, this.size) for (i in this.data.indices) newData[i] = newData[i] or data[i] BitArray(newData, this.size + other.size) @@ -55,11 +55,11 @@ data class BitArray(val data: ByteArray, val size: Int = data.size * 8) { private fun shift(source: ByteArray, bitCount: Int): ByteArray { val shiftMod = bitCount % 8 val offsetBytes = bitCount / 8 - val dest = ByteArray(source.size + offsetBytes + (if(shiftMod == 0) 0 else 1)) + val dest = ByteArray(source.size + offsetBytes + (if (shiftMod == 0) 0 else 1)) val carryMask = (0xFF ushr (8 - shiftMod)).toByte() for (i in source.indices) { - if(shiftMod == 0) { + if (shiftMod == 0) { dest[offsetBytes + i] = source[i] } else { val sourceCarry = (source[i] and carryMask).asUnsigned() shl (8 - shiftMod) @@ -72,7 +72,7 @@ data class BitArray(val data: ByteArray, val size: Int = data.size * 8) { companion object { - fun fromString(bitString: String) : BitArray { + fun fromString(bitString: String): BitArray { val byteLen = wordLen(bitString.length) val data = ByteArray(byteLen) @@ -81,12 +81,12 @@ data class BitArray(val data: ByteArray, val size: Int = data.size * 8) { var byteIndex = 0 bitString.forEach { char -> - if(char == '1') { + if (char == '1') { data[byteIndex] = (data[byteIndex] + 1.shl(bitIndex)).toByte() - } else if(char != '0') throw IllegalArgumentException("Only binary strings are allowed") + } else if (char != '0') throw IllegalArgumentException("Only binary strings are allowed") bitIndex-- - if(bitIndex < 0) { + if (bitIndex < 0) { byteIndex++ bitIndex = 7 } @@ -96,7 +96,7 @@ data class BitArray(val data: ByteArray, val size: Int = data.size * 8) { } fun wordLen(bitLen: Int, wordLen: Int = 8): Int { - return bitLen / wordLen + if(bitLen % wordLen == 0) 0 else 1 + return bitLen / wordLen + if (bitLen % wordLen == 0) 0 else 1 } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/ing/dlt/zkkrypto/util/Extensions.kt b/src/main/kotlin/com/ing/dlt/zkkrypto/util/Extensions.kt index 79f213e..1d078c2 100644 --- a/src/main/kotlin/com/ing/dlt/zkkrypto/util/Extensions.kt +++ b/src/main/kotlin/com/ing/dlt/zkkrypto/util/Extensions.kt @@ -3,7 +3,7 @@ package com.ing.dlt.zkkrypto.util fun Byte.asUnsigned() = this.toInt() and 0xFF /** Performs a bitwise AND operation between the two values. */ -inline infix fun Byte.and(other: Byte): Byte = (this.toInt() and other.toInt()).toByte() +infix fun Byte.and(other: Byte): Byte = (this.toInt() and other.toInt()).toByte() /** Performs a bitwise OR operation between the two values. */ -inline infix fun Byte.or(other: Byte): Byte = (this.toInt() or other.toInt()).toByte() +infix fun Byte.or(other: Byte): Byte = (this.toInt() or other.toInt()).toByte() diff --git a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7HashTest.kt b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7HashTest.kt index 0f3a35f..f0675a7 100644 --- a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7HashTest.kt +++ b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/mimc/Mimc7HashTest.kt @@ -19,8 +19,8 @@ class Mimc7HashTest { val seedHash = sha3.digest(Mimc7Hash.defaultSeed) assertEquals( - Hex.toHexString(seedHash), - "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e" + Hex.toHexString(seedHash), + "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e" ) } @@ -35,8 +35,8 @@ class Mimc7HashTest { constants[1].toString(10) ) } - - @Test + + @Test fun testBigIntegerHashing() { val b12 = BigInteger("12", 10) @@ -45,33 +45,33 @@ class Mimc7HashTest { val b41 = BigInteger("41", 10) val mimc7 = Mimc7Hash() - + val ints1 = listOf(b12) val h1 = mimc7.hash(ints1) assertEquals( Hex.toHexString(h1), - "237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd" + "237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd" ) val ints2 = listOf(b78, b41) val h2 = mimc7.hash(ints2) assertEquals( Hex.toHexString(h2), - "067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70" + "067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70" ) val ints3 = listOf(b12, b45) val h3 = mimc7.hash(ints3) assertEquals( Hex.toHexString(h3), - "15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879" + "15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879" ) val ints4 = listOf(b12, b45, b78, b41) val h4 = mimc7.hash(ints4) assertEquals( Hex.toHexString(h4), - "284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb" + "284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb" ) } @@ -85,8 +85,7 @@ class Mimc7HashTest { val h = mimc7.hash(msg.toByteArray()) assertEquals( BigInteger(h).toString(10), - "16855787120419064316734350414336285711017110414939748784029922801367685456065" + "16855787120419064316734350414336285711017110414939748784029922801367685456065" ) - } -} \ No newline at end of file +} diff --git a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHashTest.kt b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHashTest.kt index 44e6baf..018374c 100644 --- a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHashTest.kt +++ b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/PedersenHashTest.kt @@ -16,7 +16,7 @@ internal class PedersenHashTest { TestVectors.jubjub.forEach { vector -> - val hash = BigInteger(PedersenHash.zcash().hash(vector.input_bits)) + val hash = BigInteger(PedersenHash.zcash().hash(vector.input_bits)) assertEquals(BigInteger(vector.hash_x, 16), hash) } @@ -27,8 +27,10 @@ internal class PedersenHashTest { TestVectors.altBabyJubjub.forEach { vector -> - val hash = BigInteger(PedersenHash(curve = AltBabyJubjub, chunksPerGenerator = 62) - .hash(vector.input_bits)) + val hash = BigInteger( + PedersenHash(curve = AltBabyJubjub, chunksPerGenerator = 62) + .hash(vector.input_bits) + ) assertEquals(BigInteger(vector.hash_x, 16), hash) } @@ -41,7 +43,7 @@ internal class PedersenHashTest { val hash = BigInteger(PedersenHash.zinc().hash(vector.input_bits)) - assertEquals(vector.hash_x, hash.toString(16)) + assertEquals(vector.hash_x, hash.toString(16)) } } @@ -55,7 +57,7 @@ internal class PedersenHashTest { hash_y = "40d2992106b2c6e8c2f0b38e5238fbd9b46ef042d91011a5566044f2943ac65" ) - val hash = BigInteger(PedersenHash.zinc().hash(vector.input_bits)) + val hash = BigInteger(PedersenHash.zinc().hash(vector.input_bits)) assertEquals(vector.hash_x, hash.toString(16)) } @@ -74,7 +76,6 @@ internal class PedersenHashTest { assertEquals("116fbd117d117768ec0f977d857df3e278015d4ce9fd4d08bd6c153ebd1fa2", BigInteger(hash).toString(16)) } - @Test fun salt() { @@ -90,7 +91,6 @@ internal class PedersenHashTest { assertArrayEquals(expected, hash) } - // @Test fun hashSingle() { @@ -101,10 +101,8 @@ internal class PedersenHashTest { println("Message hash is: ${hash.toString(16)}") assertEquals(BigInteger(vector.hash_x, 16), hash) - } - // @Test fun benchmark() { // From https://github.com/zcash-hackworks/sapling-crypto/pull/79 : @@ -133,14 +131,13 @@ internal class PedersenHashTest { // Neither MM nor lookups nor any other optimizations are implemented // so looks like there is plenty of room for improvement yet its good enough at least for experimentation - val start = System.nanoTime() val numRuns = 1000 - for(m in 1..numRuns) { + for (m in 1..numRuns) { PedersenHash(curve = Jubjub).hash(BitArray(m.toBigInteger().toByteArray())) } val finish = System.nanoTime() println("Total time (nanos): ${finish - start}") println("Total time per hash (nanos): ${(finish - start) / numRuns}") } -} \ No newline at end of file +} diff --git a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/TestVectors.kt b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/TestVectors.kt index f2991d7..0ac0d50 100644 --- a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/TestVectors.kt +++ b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/pedersenhash/TestVectors.kt @@ -4,11 +4,11 @@ import com.ing.dlt.zkkrypto.util.BitArray object TestVectors { - //! Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py + // ! Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py val jubjub = listOf( - - TestVector ( + + TestVector( personalization = Personalization.NoteCommitment, input_bits = BitArray.fromString("111111"), hash_x = "06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b", @@ -40,26 +40,29 @@ object TestVectors { ), TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray.fromString("1111111000001111011100011100" + + input_bits = BitArray.fromString( + "1111111000001111011100011100" + "0010000100111010110100011010" + "0001000000101000101111101110" + "1011100100110100110111000011" + "1011001100101001011111111100" + "0010111010011111001010100110" + "100010100101010101000" - ), + ), hash_x = "2da510317620f5dfdce1f31db6019f947eedcf02ff2972cff597a5c3ad21f5dd", hash_y = "198789969c0c33e6c359b9da4a51771f4d50863f36beef90436944fe568399f2" ), TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray.fromString("1111111010001101000100010000" + + input_bits = BitArray.fromString( + "1111111010001101000100010000" + "0011000001111100001110001110" + "1100111110010101000010110110" + "0111110100010101000011000000" + "0011100101100001100100100100" + "0000101101111101111011000110" + - "0111100001011111000011"), + "0111100001011111000011" + ), hash_x = "601247c7e640992d193dfb51df6ed93446687a7f2bcd0e4a598e6feb1ef20c40", hash_y = "371931733b73e7b95c2cad55a6cebd15c83619f697c64283e54e5ef61442a743" ), @@ -67,32 +70,32 @@ object TestVectors { personalization = Personalization.NoteCommitment, input_bits = BitArray.fromString( "1111111100100100101000000110" + - "0101111010110011100001100100" + - "1110010011101110110100000111" + - "0111110011111100011011001010" + - "1110100000100111000101110001" + - "1011100000110100000111101011" + - "0001000011010101111100010101" + - "1100100110001100110101100100" + - "1111011110011100010100010010" + - "0010000110000000010111011000" + - "1000110110010000101001010010" + - "1011011001011111000010001000" + - "0000010101111001011110101110" + - "1101011110100110001001101110" + - "0000111001010100010011101111" + - "1001000001000010110101010110" + - "0011001011100100010001111101" + - "0000111011111110111101000010" + - "1001000110010001100100110101" + - "0001011010001110100110010001" + - "0000001011011010100010101011" + - "1000100010000101100110101101" + - "1110101001111000101111110101" + - "0011111101011110110101010010" + - "0010101100011111010100100010" + - "1101000001001010010001101011" + - "1100110100100000010000000111" + "0101111010110011100001100100" + + "1110010011101110110100000111" + + "0111110011111100011011001010" + + "1110100000100111000101110001" + + "1011100000110100000111101011" + + "0001000011010101111100010101" + + "1100100110001100110101100100" + + "1111011110011100010100010010" + + "0010000110000000010111011000" + + "1000110110010000101001010010" + + "1011011001011111000010001000" + + "0000010101111001011110101110" + + "1101011110100110001001101110" + + "0000111001010100010011101111" + + "1001000001000010110101010110" + + "0011001011100100010001111101" + + "0000111011111110111101000010" + + "1001000110010001100100110101" + + "0001011010001110100110010001" + + "0000001011011010100010101011" + + "1000100010000101100110101101" + + "1110101001111000101111110101" + + "0011111101011110110101010010" + + "0010101100011111010100100010" + + "1101000001001010010001101011" + + "1100110100100000010000000111" ), hash_x = "314192ecb1f2d8806a8108704c875a25d9fb7e444f9f373919adedebe8f2ae27", hash_y = "6b12b32f1372ad574799dee9eb591d961b704bf611f55fcc71f7e82cd3330b74" @@ -101,40 +104,41 @@ object TestVectors { personalization = Personalization.NoteCommitment, input_bits = BitArray.fromString( "1111111100110101110101110010" + - "0111010000000101010110000110" + - "1111001110000110110010101101" + - "1001001000100011101011001011" + - "0000111101001010010100001001" + - "0110001111001110011101011010" + - "0110110001100110010111010110" + - "0111100001011011010010011010" + - "1011101110101100010101110101" + - "1111011111000110110010000010" + - "1000100001000100011011101100" + - "1011111011000111111110001010" + - "1100100011100110100011010101" + - "1101100101011000111110101010" + - "1111010101111100001011011001" + - "1000011000000110010010001100" + - "1100110001001101001001010001" + - "0101000111101010100010111000" + - "1111101010100101010101110010" + - "0011111010101010000101101110" + - "0101111011011000100000010001" + - "0011011110100011001011011001" + - "0111000101011011111000000101" + - "0101101100010011111101010011" + - "0100001101110101010000010100" + - "1100110001000011101011000011" + - "1101011111001010000101010111" + - "0" + "0111010000000101010110000110" + + "1111001110000110110010101101" + + "1001001000100011101011001011" + + "0000111101001010010100001001" + + "0110001111001110011101011010" + + "0110110001100110010111010110" + + "0111100001011011010010011010" + + "1011101110101100010101110101" + + "1111011111000110110010000010" + + "1000100001000100011011101100" + + "1011111011000111111110001010" + + "1100100011100110100011010101" + + "1101100101011000111110101010" + + "1111010101111100001011011001" + + "1000011000000110010010001100" + + "1100110001001101001001010001" + + "0101000111101010100010111000" + + "1111101010100101010101110010" + + "0011111010101010000101101110" + + "0101111011011000100000010001" + + "0011011110100011001011011001" + + "0111000101011011111000000101" + + "0101101100010011111101010011" + + "0100001101110101010000010100" + + "1100110001000011101011000011" + + "1101011111001010000101010111" + + "0" ), hash_x = "0666c2bce7f362a2b807d212e9a577f116891a932affd7addec39fbf372c494e", hash_y = "6758bccfaf2e47c07756b96edea23aa8d10c33b38220bd1c411af612eeec18ab" ), TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray.fromString("1111111000000101100100100001" + + input_bits = BitArray.fromString( + "1111111000000101100100100001" + "1001011101101000000100010110" + "0000110010111010111010011001" + "1101100001110011000000110011" + @@ -176,39 +180,39 @@ object TestVectors { personalization = Personalization.NoteCommitment, input_bits = BitArray.fromString( "1111110110011010011011001110" + - "1101101000110011110110100101" + - "0111000010101110011000000100" + - "1010101100010001001101000110" + - "0101011111100101111011000100" + - "1111001010100010000000011101" + - "0010011111010101111011001001" + - "0000111011010111000011001010" + - "1001100010101010000101100100" + - "0100010011100101000010101111" + - "1011001100010000000010101100" + - "1111100000001101100001000011" + - "1000100100000110101000001100" + - "0110101001100010101000100111" + - "1101011010001001011110110101" + - "1011000111011100000001101000" + - "1011110111100110110101011111" + - "0010100101011001001010000011" + - "0100001010110001010100100101" + - "1011001110001011010101011000" + - "1000110000000011100011001011" + - "1110010000101001011011100110" + - "1000110001011101101110000000" + - "1111100000000010111000001110" + - "1110111100000111010110010100" + - "0010111110011010000111001110" + - "1101000010111100010101101001" + - "0111001111000110111111000011" + - "0100010010111000000101100100" + - "1111100010111001101110101111" + - "1100110110110111110000111000" + - "1001110100010010100010011110" + - "0100011011110000100111111011" + - "1110000111011001110001" + "1101101000110011110110100101" + + "0111000010101110011000000100" + + "1010101100010001001101000110" + + "0101011111100101111011000100" + + "1111001010100010000000011101" + + "0010011111010101111011001001" + + "0000111011010111000011001010" + + "1001100010101010000101100100" + + "0100010011100101000010101111" + + "1011001100010000000010101100" + + "1111100000001101100001000011" + + "1000100100000110101000001100" + + "0110101001100010101000100111" + + "1101011010001001011110110101" + + "1011000111011100000001101000" + + "1011110111100110110101011111" + + "0010100101011001001010000011" + + "0100001010110001010100100101" + + "1011001110001011010101011000" + + "1000110000000011100011001011" + + "1110010000101001011011100110" + + "1000110001011101101110000000" + + "1111100000000010111000001110" + + "1110111100000111010110010100" + + "0010111110011010000111001110" + + "1101000010111100010101101001" + + "0111001111000110111111000011" + + "0100010010111000000101100100" + + "1111100010111001101110101111" + + "1100110110110111110000111000" + + "1001110100010010100010011110" + + "0100011011110000100111111011" + + "1110000111011001110001" ), hash_x = "67914ebd539961b70f468fa23d4cb42133693a8ac57cd35a1e6369fe34fbedf7", hash_y = "44770870c0f0cfe59a10df95d6c21e6f1514a2f464b66377599438c126052d9f" @@ -241,12 +245,12 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000001101001110010010110111" + - "0001111001101010111010111000" + - "0100001001101001110011011001" + - "1100111011101010001101101011" + - "0011000101011101000110001110" + - "1110000110110010101110101101" + - "110111111001000110" + "0001111001101010111010111000" + + "0100001001101001110011011001" + + "1100111011101010001101101011" + + "0011000101011101000110001110" + + "1110000110110010101110101101" + + "110111111001000110" ), hash_x = "20d2b1b0551efe511755d564f8da4f5bf285fd6051331fa5f129ad95b318f6cd", hash_y = "2834d96950de67ae80e85545f8333c6e14b5cf5be7325dac768f401e6edd9544" @@ -255,12 +259,12 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000000010000110001100111101" + - "1001011110011001110101101111" + - "1110011110000000000110011100" + - "0110111110010010110010101111" + - "1101001011000101001100101010" + - "0010011100011011011101110100" + - "010111101111011010000" + "1001011110011001110101101111" + + "1110011110000000000110011100" + + "0110111110010010110010101111" + + "1101001011000101001100101010" + + "0010011100011011011101110100" + + "010111101111011010000" ), hash_x = "01f4850a0f40e07186fee1f0a276f52fb12cffe05c18eb2aa18170330a93c555", hash_y = "19b0807358e7c8cba9168815ec54c4cd76997c34c592607d172151c48d5377cb" @@ -269,12 +273,12 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000001111100001011111111000" + - "0101100011111111001110101001" + - "0000101101111001010010111010" + - "0111011111100111110010010101" + - "0100101110100001101101111101" + - "1001011111000110101011111101" + - "0011010110101001101100" + "0101100011111111001110101001" + + "0000101101111001010010111010" + + "0111011111100111110010010101" + + "0100101110100001101101111101" + + "1001011111000110101011111101" + + "0011010110101001101100" ), hash_x = "26dd81a3ffa37452c6a932d41eb4f2e0fedd531e9af8c2a7935b91dff653879d", hash_y = "2fc7aebb729ef5cabf0fb3f883bc2eb2603093850b0ec19c1a3c08b653e7f27f" @@ -283,32 +287,32 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000000100011111100000000101" + - "0110011100001110010001010010" + - "1110010011000011010101010111" + - "1001011111100000001110011101" + - "0101010101010000001011100000" + - "0110110000100111101010000101" + - "1101001100111110110111110000" + - "0011001111000001100101111110" + - "1001001101011101001110100110" + - "0111010100011010010110110001" + - "0101011011011010100110100010" + - "0101100000000100100010101011" + - "0110001001101111100110010111" + - "0000000011101111011100100000" + - "0110111100000100010100101010" + - "1000110010111010111001110100" + - "0000100110110000111100000101" + - "0000000011011101001010010101" + - "0011101101000000101000111000" + - "0100101011110101100100010011" + - "0001101101010111100011111010" + - "0011010011011100101011010110" + - "1001001101001101100000011010" + - "1010001000111010100100101011" + - "0000100101000011110010110001" + - "0101110110101101001101001111" + - "1110001100111101101001011001" + "0110011100001110010001010010" + + "1110010011000011010101010111" + + "1001011111100000001110011101" + + "0101010101010000001011100000" + + "0110110000100111101010000101" + + "1101001100111110110111110000" + + "0011001111000001100101111110" + + "1001001101011101001110100110" + + "0111010100011010010110110001" + + "0101011011011010100110100010" + + "0101100000000100100010101011" + + "0110001001101111100110010111" + + "0000000011101111011100100000" + + "0110111100000100010100101010" + + "1000110010111010111001110100" + + "0000100110110000111100000101" + + "0000000011011101001010010101" + + "0011101101000000101000111000" + + "0100101011110101100100010011" + + "0001101101010111100011111010" + + "0011010011011100101011010110" + + "1001001101001101100000011010" + + "1010001000111010100100101011" + + "0000100101000011110010110001" + + "0101110110101101001101001111" + + "1110001100111101101001011001" ), hash_x = "1111740552773b00aa6a2334575aa94102cfbd084290a430c90eb56d6db65b85", hash_y = "6560c44b11683c20030626f89456f78a53ae8a89f565956a98ffc554b48fbb1a" @@ -317,33 +321,33 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000000010011010110111011010" + - "1000010000001100101010101000" + - "0100100010100101111000011111" + - "0001001101011110010110010111" + - "1100000100011110111110001000" + - "0110111011100111010001001011" + - "0100000100001101000110110100" + - "0111101000101101011100010111" + - "1101101011000111011010101111" + - "1010010110100010101011000000" + - "0000010010101101011011100001" + - "0111111110111100001100100100" + - "0001110000101000110101111100" + - "1001000010101111001101010011" + - "0110101000001010101110001100" + - "0001101111000010011111110101" + - "1110001000010100001000011011" + - "0000101101111100100100101000" + - "0111111101000010110111011001" + - "1000010011011001010100111110" + - "1100010110101110110011110101" + - "1000011011100010111011010010" + - "1010110001110111100001010110" + - "1111011111110001000001100010" + - "1000101100011101101001101101" + - "1011010010101111011110001011" + - "1110110100100110100000111100" + - "0" + "1000010000001100101010101000" + + "0100100010100101111000011111" + + "0001001101011110010110010111" + + "1100000100011110111110001000" + + "0110111011100111010001001011" + + "0100000100001101000110110100" + + "0111101000101101011100010111" + + "1101101011000111011010101111" + + "1010010110100010101011000000" + + "0000010010101101011011100001" + + "0111111110111100001100100100" + + "0001110000101000110101111100" + + "1001000010101111001101010011" + + "0110101000001010101110001100" + + "0001101111000010011111110101" + + "1110001000010100001000011011" + + "0000101101111100100100101000" + + "0111111101000010110111011001" + + "1000010011011001010100111110" + + "1100010110101110110011110101" + + "1000011011100010111011010010" + + "1010110001110111100001010110" + + "1111011111110001000001100010" + + "1000101100011101101001101101" + + "1011010010101111011110001011" + + "1110110100100110100000111100" + + "0" ), hash_x = "429349ea9b5f8163bcda3014b3e15554df5173353fd73f315a49360c97265f68", hash_y = "188774bb6de41eba669be5d368942783f937acf2f418385fc5c78479b0a405ee" @@ -352,39 +356,39 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000000010000011010000000001" + - "0010111101001010101011011100" + - "0001011111100011111110110011" + - "0001101101010110010000101001" + - "0010011010100011111010100001" + - "1011011111100000101011010001" + - "1011111001110011011000100100" + - "0000000000010110000000100000" + - "0100011111101010010011000111" + - "0010111100111101111110010000" + - "1011011011001100001111101001" + - "1011111000100110000011101110" + - "1110110010010110010001110110" + - "1010001101101011100000110011" + - "0110101110101001001001110000" + - "0111101011101111101000000001" + - "0010100100000100010001101011" + - "0011001001110001010010001000" + - "0011101101000001011100001111" + - "0011101010111000111100100101" + - "1110001100001001011000011101" + - "1000110100110011010111000001" + - "1111000101001001100001110001" + - "0010001111011010010001010111" + - "0101111011001100110010111111" + - "0011001110110110001101110011" + - "0001010011000010001001101111" + - "0100110111011010111101001010" + - "0110000110011101000011011111" + - "0010010100011110110000010011" + - "0001100001110111110000011001" + - "0101110111110001101101101110" + - "0111001100111000010010100000" + - "001100010111100100110" + "0010111101001010101011011100" + + "0001011111100011111110110011" + + "0001101101010110010000101001" + + "0010011010100011111010100001" + + "1011011111100000101011010001" + + "1011111001110011011000100100" + + "0000000000010110000000100000" + + "0100011111101010010011000111" + + "0010111100111101111110010000" + + "1011011011001100001111101001" + + "1011111000100110000011101110" + + "1110110010010110010001110110" + + "1010001101101011100000110011" + + "0110101110101001001001110000" + + "0111101011101111101000000001" + + "0010100100000100010001101011" + + "0011001001110001010010001000" + + "0011101101000001011100001111" + + "0011101010111000111100100101" + + "1110001100001001011000011101" + + "1000110100110011010111000001" + + "1111000101001001100001110001" + + "0010001111011010010001010111" + + "0101111011001100110010111111" + + "0011001110110110001101110011" + + "0001010011000010001001101111" + + "0100110111011010111101001010" + + "0110000110011101000011011111" + + "0010010100011110110000010011" + + "0001100001110111110000011001" + + "0101110111110001101101101110" + + "0111001100111000010010100000" + + "001100010111100100110" ), hash_x = "00e827f3ed136f3c91c61c97ab9b7cca0ea53c20e47abb5e226ede297bdd5f37", hash_y = "315cc00a54972df6a19f650d3fab5f2ad0fb07397bacb6944568618f2aa76bf6" @@ -393,39 +397,39 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000000011100101011100111111" + - "0011011101000011101111001101" + - "1010111010101010110011101110" + - "0001111001100100110111100011" + - "1000010101111101000100101010" + - "0100011011010010110111111101" + - "0100010111010111110001001000" + - "1001000010101101001010101110" + - "0110111001001111100011000101" + - "0011110111011010111011100100" + - "0010010001100111001010000110" + - "1101100011100001101011101000" + - "0000001010001000000101111010" + - "1001001011001011001111100011" + - "0001010010100100011010000000" + - "0100110010001001001001001011" + - "1111110100000000101100001001" + - "1000000100101101001001001001" + - "0110101011010100101010111110" + - "1010010101000111010100010011" + - "1001011101000111010110010011" + - "0010011111010100011110111000" + - "0100111000101001101100000010" + - "1111111100010010111110000000" + - "1011110000010100110100110111" + - "1011011100101111001000011110" + - "0011101010101010110011001010" + - "0011101000011111101000100111" + - "0000010010011110011101110001" + - "0001001110110110001010111001" + - "0111000100100001110100011110" + - "1101101000000100111101111010" + - "1000110011001110011000100111" + - "1010100001000010101000" + "0011011101000011101111001101" + + "1010111010101010110011101110" + + "0001111001100100110111100011" + + "1000010101111101000100101010" + + "0100011011010010110111111101" + + "0100010111010111110001001000" + + "1001000010101101001010101110" + + "0110111001001111100011000101" + + "0011110111011010111011100100" + + "0010010001100111001010000110" + + "1101100011100001101011101000" + + "0000001010001000000101111010" + + "1001001011001011001111100011" + + "0001010010100100011010000000" + + "0100110010001001001001001011" + + "1111110100000000101100001001" + + "1000000100101101001001001001" + + "0110101011010100101010111110" + + "1010010101000111010100010011" + + "1001011101000111010110010011" + + "0010011111010100011110111000" + + "0100111000101001101100000010" + + "1111111100010010111110000000" + + "1011110000010100110100110111" + + "1011011100101111001000011110" + + "0011101010101010110011001010" + + "0011101000011111101000100111" + + "0000010010011110011101110001" + + "0001001110110110001010111001" + + "0111000100100001110100011110" + + "1101101000000100111101111010" + + "1000110011001110011000100111" + + "1010100001000010101000" ), hash_x = "3ee50557c4aa9158c4bb9d5961208e6c62f55c73ad7c7695a0eba0bcb6d83d05", hash_y = "1b1a2be6e47688828aeadf2d37db298eac0c2736c2722b227871fdeeee29de33" @@ -458,12 +462,12 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100010101010000100010000110" + - "0011111100000100011010100101" + - "1111011110010111001000101110" + - "1000101110000001100100110100" + - "0111111100101110110101110010" + - "1011011010011010100011110010" + - "001001110110000110" + "0011111100000100011010100101" + + "1111011110010111001000101110" + + "1000101110000001100100110100" + + "0111111100101110110101110010" + + "1011011010011010100011110010" + + "001001110110000110" ), hash_x = "544a0b44c35dca64ee806d1af70b7c44134e5d86efed413947657ffd71adf9b2", hash_y = "5ddc5dbf12abbbc5561defd3782a32f450b3c398f52ff4629677e59e86e3ab31" @@ -472,12 +476,12 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100011000110001011100010011" + - "0010000000110010101100111101" + - "0010011101101011011010111111" + - "0111001110011011100101100100" + - "0010111111010011110011110110" + - "1110001011111110001100010011" + - "100010111110000011101" + "0010000000110010101100111101" + + "0010011101101011011010111111" + + "0111001110011011100101100100" + + "0010111111010011110011110110" + + "1110001011111110001100010011" + + "100010111110000011101" ), hash_x = "6cb6490ccb0ca9ccd657146f58a7b800bc4fb2556ee37861227ee8fda724acfb", hash_y = "05c6fe100926f5cc441e54e72f024b6b12c907f2ec5680335057896411984c9f" @@ -486,12 +490,12 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100010110011001111010111101" + - "0110111001000101111010110011" + - "0000000101100101100010000111" + - "1001111010000101001010100100" + - "0100101101101001001001000111" + - "0000010010010011101010101001" + - "0001101011100111010100" + "0110111001000101111010110011" + + "0000000101100101100010000111" + + "1001111010000101001010100100" + + "0100101101101001001001000111" + + "0000010010010011101010101001" + + "0001101011100111010100" ), hash_x = "40901e2175cb7f06a00c676d54d90e59fd448f11cbbc5eb517f9fea74b795ce2", hash_y = "42d512891f91087310c9bc630c8d0ecc014596f884fd6df55dada8195ed726de" @@ -500,32 +504,32 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100011100110011011001000110" + - "0010100111110011100000100001" + - "1111010001011001000000100100" + - "1001111111011010000111010001" + - "1111111001111111010001011000" + - "1000000011001011110000001001" + - "1000100111001100000100111100" + - "0111011110010000101110101011" + - "1110101000000000110001000010" + - "0010101011010001010101010100" + - "0111011000110011011101110001" + - "1000010010001011110111111001" + - "1110010100100110101111100110" + - "1100011000010110110110110101" + - "0111111010010111000110011100" + - "1101000100011111110110001100" + - "1010010100010101101010001000" + - "1001101010110110111010000110" + - "0111111101001100110101010011" + - "1011010001100111010010110010" + - "1001000101010100100010100100" + - "1000001100010001100110100110" + - "1110111000101000010011000110" + - "1100001101101101001100001001" + - "1001110011101000101101010100" + - "0001001101101001001010111011" + - "0111001000000111010101000101" + "0010100111110011100000100001" + + "1111010001011001000000100100" + + "1001111111011010000111010001" + + "1111111001111111010001011000" + + "1000000011001011110000001001" + + "1000100111001100000100111100" + + "0111011110010000101110101011" + + "1110101000000000110001000010" + + "0010101011010001010101010100" + + "0111011000110011011101110001" + + "1000010010001011110111111001" + + "1110010100100110101111100110" + + "1100011000010110110110110101" + + "0111111010010111000110011100" + + "1101000100011111110110001100" + + "1010010100010101101010001000" + + "1001101010110110111010000110" + + "0111111101001100110101010011" + + "1011010001100111010010110010" + + "1001000101010100100010100100" + + "1000001100010001100110100110" + + "1110111000101000010011000110" + + "1100001101101101001100001001" + + "1001110011101000101101010100" + + "0001001101101001001010111011" + + "0111001000000111010101000101" ), hash_x = "66a433542419f1a086ed0663b0e8df2ece9a04065f147896976baba1a916b6dc", hash_y = "203bd3672522e1d3c86fa6b9f3b58f20199a4216adfd40982add13a856f6f3de" @@ -534,33 +538,33 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100010010011000100001010011" + - "1010111000010011000010000111" + - "1101000000001010100001110111" + - "1110011111010110001111011110" + - "1101000101011001000101000101" + - "0000010001001111110101101111" + - "0110011100100001011101011100" + - "1100011011110100110111111011" + - "1101001111001001001011000001" + - "1100011110111001100000100011" + - "0001101001000101110001110000" + - "0010001100010101101011110100" + - "0111100000101010000100010100" + - "1011110101010001011001100011" + - "1000010010001011110110001101" + - "1011100000001011010100010011" + - "0010111100101100110101001000" + - "1010101000100100101111010001" + - "0100101110010000111011110000" + - "0000111110101011100001101001" + - "0110101011100001011001100010" + - "0110011000110111000011111001" + - "1011110110110100101011101001" + - "1111101110000011011101110010" + - "1000100101101011100011111100" + - "1001110001101100000011000000" + - "1011000101110111011001110000" + - "1" + "1010111000010011000010000111" + + "1101000000001010100001110111" + + "1110011111010110001111011110" + + "1101000101011001000101000101" + + "0000010001001111110101101111" + + "0110011100100001011101011100" + + "1100011011110100110111111011" + + "1101001111001001001011000001" + + "1100011110111001100000100011" + + "0001101001000101110001110000" + + "0010001100010101101011110100" + + "0111100000101010000100010100" + + "1011110101010001011001100011" + + "1000010010001011110110001101" + + "1011100000001011010100010011" + + "0010111100101100110101001000" + + "1010101000100100101111010001" + + "0100101110010000111011110000" + + "0000111110101011100001101001" + + "0110101011100001011001100010" + + "0110011000110111000011111001" + + "1011110110110100101011101001" + + "1111101110000011011101110010" + + "1000100101101011100011111100" + + "1001110001101100000011000000" + + "1011000101110111011001110000" + + "1" ), hash_x = "119db3b38086c1a3c6c6f53c529ee62d9311d69c2d8aeeafa6e172e650d3afda", hash_y = "72287540be7d2b0f58f5c73eaa53c55bea6b79dd79873b4e47cc11787bb9a15d" @@ -569,39 +573,39 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100010011000011011010110111" + - "1101101100100110110011000101" + - "1111101111100100010100111110" + - "0011010001001000001000110010" + - "1101000000000010100001110000" + - "0100101010100101100101101010" + - "0111101010010110011101010101" + - "1010000011010011100111010110" + - "1101110100100010110111101010" + - "1011001100000001110110011111" + - "0000000011011011110101000111" + - "0101010101000101010110010100" + - "1011001111101010001110010010" + - "1000110001101000111010111000" + - "1100101011001000000111100111" + - "1000010001010011011100000110" + - "0111110110111110000010011101" + - "0000100000111110000010101011" + - "0010001111010011100011011110" + - "1011110001000011010010011000" + - "1000000011100100011101010100" + - "1000000100000001010010111111" + - "0101000001011110010000100111" + - "1011001000100010010110001010" + - "0011100001111101000001001110" + - "1000010100001000011111001110" + - "1001101000011100001110110110" + - "0111101001001010010001100110" + - "0011000110110110100001001111" + - "1011110011001110101110111111" + - "0100000000110110011100011110" + - "1000000010001010000000001010" + - "0011110011011111100101110111" + - "100010101111011111100" + "1101101100100110110011000101" + + "1111101111100100010100111110" + + "0011010001001000001000110010" + + "1101000000000010100001110000" + + "0100101010100101100101101010" + + "0111101010010110011101010101" + + "1010000011010011100111010110" + + "1101110100100010110111101010" + + "1011001100000001110110011111" + + "0000000011011011110101000111" + + "0101010101000101010110010100" + + "1011001111101010001110010010" + + "1000110001101000111010111000" + + "1100101011001000000111100111" + + "1000010001010011011100000110" + + "0111110110111110000010011101" + + "0000100000111110000010101011" + + "0010001111010011100011011110" + + "1011110001000011010010011000" + + "1000000011100100011101010100" + + "1000000100000001010010111111" + + "0101000001011110010000100111" + + "1011001000100010010110001010" + + "0011100001111101000001001110" + + "1000010100001000011111001110" + + "1001101000011100001110110110" + + "0111101001001010010001100110" + + "0011000110110110100001001111" + + "1011110011001110101110111111" + + "0100000000110110011100011110" + + "1000000010001010000000001010" + + "0011110011011111100101110111" + + "100010101111011111100" ), hash_x = "446efdcf89b70ba2b03427a0893008181d0fc4e76b84b1a500d7ee523c8e3666", hash_y = "125ee0048efb0372b92c3c15d51a7c5c77a712054cc4fdd0774563da46ec7289" @@ -610,39 +614,39 @@ object TestVectors { personalization = Personalization.MerkleTree_34, input_bits = BitArray.fromString( "0100010011101110010101111111" + - "1000101000110100010110010111" + - "0000101101110100100101101110" + - "1100010001100000111011110100" + - "1111000110101011111101011010" + - "0011100101111111001111010111" + - "0011000010011001011000110011" + - "1111111110110011101100010110" + - "0001000100110100100111100110" + - "0101110011111101111110101110" + - "1110011100000011011100111010" + - "0100010011111101000100101100" + - "0001100100100111001010011101" + - "1000111011111011111101101111" + - "0111101100011001000100100110" + - "0000111111101011110001001110" + - "0010110111010100011001000101" + - "1101010001111110110001010011" + - "1100110111001101011111001101" + - "1011110101000110000101011010" + - "0011101001101000001111010010" + - "1111001010000000000110000011" + - "1110000000101111000110011011" + - "1011101100010011100111010011" + - "1001001000010011100100010000" + - "0110101001110100110110001101" + - "0011001000101010000000100101" + - "0010000011101100110000001100" + - "1110010011011110110111111010" + - "0100110101100001100110001101" + - "0011111100011000011000010100" + - "0000010000010010100110011101" + - "1110111011100001000011010110" + - "1001001001001111101101" + "1000101000110100010110010111" + + "0000101101110100100101101110" + + "1100010001100000111011110100" + + "1111000110101011111101011010" + + "0011100101111111001111010111" + + "0011000010011001011000110011" + + "1111111110110011101100010110" + + "0001000100110100100111100110" + + "0101110011111101111110101110" + + "1110011100000011011100111010" + + "0100010011111101000100101100" + + "0001100100100111001010011101" + + "1000111011111011111101101111" + + "0111101100011001000100100110" + + "0000111111101011110001001110" + + "0010110111010100011001000101" + + "1101010001111110110001010011" + + "1100110111001101011111001101" + + "1011110101000110000101011010" + + "0011101001101000001111010010" + + "1111001010000000000110000011" + + "1110000000101111000110011011" + + "1011101100010011100111010011" + + "1001001000010011100100010000" + + "0110101001110100110110001101" + + "0011001000101010000000100101" + + "0010000011101100110000001100" + + "1110010011011110110111111010" + + "0100110101100001100110001101" + + "0011111100011000011000010100" + + "0000010000010010100110011101" + + "1110111011100001000011010110" + + "1001001001001111101101" ), hash_x = "72723bf0573bcb4b72d4184cfeb707d9556b7f705f56a4652707a36f2edf10f7", hash_y = "3a7f0999a6a1393bd49fc82302e7352e01176fbebb0192bf5e6ef39eb8c585ad" @@ -651,12 +655,12 @@ object TestVectors { personalization = Personalization.MerkleTree_27, input_bits = BitArray.fromString( "1101101101101101101101101101" + - "1011011011011011011011011011" + - "0110110110110110110110110110" + - "1101101101101101101101101101" + - "1011011011011011011011011011" + - "0110110110110110110110110110" + - "110110110110110110110" + "1011011011011011011011011011" + + "0110110110110110110110110110" + + "1101101101101101101101101101" + + "1011011011011011011011011011" + + "0110110110110110110110110110" + + "110110110110110110110" ), hash_x = "414f6ba05f6b92da1f9051950769e1083d05615def32b016ae424309828a11f4", hash_y = "471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9" @@ -665,12 +669,12 @@ object TestVectors { personalization = Personalization.MerkleTree_36, input_bits = BitArray.fromString( "0010010010010010010010010010" + - "0100100100100100100100100100" + - "1001001001001001001001001001" + - "0010010010010010010010010010" + - "0100100100100100100100100100" + - "1001001001001001001001001001" + - "001001001001001001001" + "0100100100100100100100100100" + + "1001001001001001001001001001" + + "0010010010010010010010010010" + + "0100100100100100100100100100" + + "1001001001001001001001001001" + + "001001001001001001001" ), hash_x = "62d6fe1e373225a5695f3115aed8265c59e2d6275ceef6bbc53fde3fc6594024", hash_y = "407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1" @@ -679,12 +683,12 @@ object TestVectors { personalization = Personalization.MerkleTree_0, input_bits = BitArray.fromString( "0000000000000000000000000000" + - "0000000000000000000000000000" + - "0000000000000000000000000000" + - "0000000000000000000000000000" + - "0000000000000000000000000000" + - "0000000000000000000000000000" + - "000000000000000000000" + "0000000000000000000000000000" + + "0000000000000000000000000000" + + "0000000000000000000000000000" + + "0000000000000000000000000000" + + "0000000000000000000000000000" + + "000000000000000000000" ), hash_x = "1116a934f26b57a2c9daa6f25ac9b1a8f9dacddba30f65433ac021bf39a6bfdd", hash_y = "407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1" @@ -693,12 +697,12 @@ object TestVectors { personalization = Personalization.NoteCommitment, input_bits = BitArray.fromString( "1111111111111111111111111111" + - "1111111111111111111111111111" + - "1111111111111111111111111111" + - "1111111111111111111111111111" + - "1111111111111111111111111111" + - "1111111111111111111111111111" + - "111111111111111111111" + "1111111111111111111111111111" + + "1111111111111111111111111111" + + "1111111111111111111111111111" + + "1111111111111111111111111111" + + "1111111111111111111111111111" + + "111111111111111111111" ), hash_x = "329e3bb2ca31ea6e13a986730237f6fd16b842a510cbabe851bdbcf57d75ee0d", hash_y = "471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9" @@ -709,7 +713,7 @@ object TestVectors { val altBabyJubjub = listOf( - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, input_bits = BitArray.fromString("11111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101010"), hash_x = "d799568a2faaebce79310bbb84e454bf934e61f1879c8095ac7c0a45905d2d3", @@ -717,55 +721,53 @@ object TestVectors { ) ) - val altBabyJubjubBytes = listOf( - - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, input_bits = BitArray(arrayOf(2).map { it.toByte() }.toByteArray()), hash_x = "16eaafa8bf93f1f27186cb8771b852a9a3570830eb263c0c39523ab90674e6", hash_y = "b235463d147fc1042a120bdff0a35668ad1d9b8c265c48976086d8807abdfb6" ), - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, input_bits = BitArray(arrayOf(2, 2).map { it.toByte() }.toByteArray()), hash_x = "6273578ac58d3c2f79f2e1c295a5ed3a74a16f1e35661c7bc6592813201835d", hash_y = "187681a9397880994ca3584285e4dc7e9d0aa6fa42e0ff08b1dcb17dc8f3900e" ), - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, input_bits = BitArray(arrayOf(0, 0, 0, 2).map { it.toByte() }.toByteArray()), hash_x = "1ceb95bf288ae7358b559348b56fd36abf9326af4ffe64e2d2b6210c445344b0", hash_y = "159c5863b7f2ad2e3df3c3798625bf2c4a6f7046ea6053a856774e0502de7b2" ), - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), + input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), hash_x = "12a71044d9154787840999c1654d30f1a19422c09897c1511c67068b4f1ec557", hash_y = "6f45fb86387cbf7342be80e0b924420fb42d44c73781d1d07075bb8d9d5fbf9" ), - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), + input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), hash_x = "1651027d8491db883b96a377b0cc885673415f012c2a5b92d3b146e369843257", hash_y = "16b09c34ed5232f658e4c38400bd7b6d0cb9396e10488d4a219d96914e2b438a" ), - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), + input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), hash_x = "104058a28c52d2db3ddb540f03d2c0c798244daee3df59067a101f7679a69d9a", hash_y = "2d6c50a6937223a1f3dd7f90394809356e574f5158f9f6044a5bb4ea3aec81a8" ), - TestVector ( + TestVector( personalization = Personalization.NoteCommitment, - input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), + input_bits = BitArray(arrayOf(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2).map { it.toByte() }.toByteArray()), hash_x = "1b483fbf06bf1a7f139ebed40ede666708616fadad90ab99a1475ab4dea7227", hash_y = "27a8660e4da972407d3156e2fd06de6ae0226459de30da24473e72b079ec836e" ) @@ -789,4 +791,4 @@ object TestVectors { const val MerkleTree_36 = "" const val MerkleTree_27 = "" } -} \ No newline at end of file +} diff --git a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHashTest.kt b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHashTest.kt index ee691e8..9ac5f5f 100644 --- a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHashTest.kt +++ b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/poseidon/PoseidonHashTest.kt @@ -22,31 +22,29 @@ class PoseidonHashTest { val b6 = BigInteger.valueOf(6) var h = poseidon.hash(listOf(b1)) - + assertEquals("11043376183861534927536506085090418075369306574649619885724436265926427398571", h.toString(10)) h = poseidon.hash(listOf(b1, b2)) - + assertEquals("17117985411748610629288516079940078114952304104811071254131751175361957805920", h.toString(10)) h = poseidon.hash(listOf(b1, b2, b0, b0, b0)) - + assertEquals("3975478831357328722254985704342968745327876719981393787143845259590563829094", h.toString(10)) h = poseidon.hash(listOf(b1, b2, b0, b0, b0, b0)) - - assertEquals("19772360636270345724087386688434825760738403416279047262510528378903625000110", h.toString(10)) + assertEquals("19772360636270345724087386688434825760738403416279047262510528378903625000110", h.toString(10)) h = poseidon.hash(listOf(b3, b4, b0, b0, b0)) - + assertEquals("3181200837746671699652342497997860344148947482942465819251904554707352676086", h.toString(10)) h = poseidon.hash(listOf(b3, b4, b0, b0, b0, b0)) - - assertEquals("8386348873272147968934270337233829407378789978142456170950021426339096575008", h.toString(10)) + assertEquals("8386348873272147968934270337233829407378789978142456170950021426339096575008", h.toString(10)) h = poseidon.hash(listOf(b1, b2, b3, b4, b5, b6)) - + assertEquals("5202465217520500374834597824465244016759843635092906214933648999760272616044", h.toString(10)) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/SchnorrTest.kt b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/SchnorrTest.kt new file mode 100644 index 0000000..d37395e --- /dev/null +++ b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/SchnorrTest.kt @@ -0,0 +1,197 @@ +package com.ing.dlt.zkkrypto.ecc.schnorr + +import com.ing.dlt.zkkrypto.ecc.curves.AltBabyJubjub +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import java.math.BigInteger +import kotlin.random.Random.Default.nextBytes +import kotlin.system.measureNanoTime + +class SchnorrSignatureTest { + + @Test + fun `test raw message signing from Zinc`() { + + listOf(ByteArray(1) { 85 }, "Foo bar pad to16".toByteArray()).forEach { + val schnorr = SchnorrSignature.zinc + + println("\nPublic Key:") + println("\tx coord = " + schnorr.publicKey.x.toString(16)) + println("\ty coord = " + schnorr.publicKey.y.toString(16) + "\n") + + val signature = schnorr.signRawMessage(msgBytes = it, seed = nextBytes(80)) + + println("Signature:") + println("\tR:") + println("\t\tx coord = " + signature.r.x.toString(16)) + println("\t\ty coord = " + signature.r.y.toString(16)) + println("\ts:") + println("\t\tvalue = " + signature.s.toString(16)) + + val verified = schnorr.verifyRawMessage(it, signature) + + if (verified) + println("\nSignature verified!") + + assert(verified) + } + } + + @Test + fun `test hashed message signing from Zinc`() { + + listOf(ByteArray(1) { 85 }, "Foo bar pad to16".toByteArray()).forEach { + val schnorr = SchnorrSignature.zinc + + println("Public Key:") + println("\tx coord = " + schnorr.publicKey.x.toString(16)) + println("\ty coord = " + schnorr.publicKey.y.toString(16) + "\n") + + val signature = schnorr.signHashedMessage(msgBytes = it, seed = nextBytes(80)) + val verified = schnorr.verifyHashedMessage(it, signature) + + println("Signature:") + println("\tR:") + println("\t\tx coord = " + signature.r.x.toString(16)) + println("\t\ty coord = " + signature.r.y.toString(16)) + println("\ts:") + println("\t\tvalue = " + signature.s.toString(16)) + + if (verified) + println("Signature verified!") + + assert(verified) + } + } + + @Test + fun testVectorsPlainMessage() { + + val schnorr = SchnorrSignature.zinc + + TestVectors.testVectorsPlainMessage.forEach { vector -> + + schnorr.setKeys(BigInteger(vector.privateKey, 16)) + val signature = schnorr.signRawMessage( + msgBytes = vector.message.toByteArray(), + seed = vector.seed.split(",").map { it.toInt().toByte() }.toByteArray() + ) + + assertEquals(BigInteger(vector.signatureRX, 16), signature.r.x) + assertEquals(BigInteger(vector.signatureRY, 16), signature.r.y) + + assertEquals(BigInteger(vector.signatureS, 16), signature.s) + + println("Validated!") + } + } + + @Test + fun testVectorsHashedMessage() { + + val schnorr = SchnorrSignature.zinc + + TestVectors.testVectorsHashedMessage.forEach { vector -> + + schnorr.setKeys(BigInteger(vector.privateKey, 16)) + val signature = schnorr.signHashedMessage( + msgBytes = vector.message.toByteArray(), + seed = vector.seed.split(",").map { it.toInt().toByte() }.toByteArray() + ) + + assertEquals(BigInteger(vector.signatureRX, 16), signature.r.x) + assertEquals(BigInteger(vector.signatureRY, 16), signature.r.y) + + assertEquals(BigInteger(vector.signatureS, 16), signature.s) + + println("Validated!") + } + } + + @Test + @Tag("benchmark") + fun benchmarkRawMessage() { + val numRuns = 1000 + val schnorr = SchnorrSignature.zinc + + var keyGenTimeElapsed: Long = 0 + var signTimeElapsed: Long = 0 + var verifyTimeElapsed: Long = 0 + + for (m in 1..numRuns) { + + // measure KeyGen + keyGenTimeElapsed += measureNanoTime { + schnorr.nextKeyPair() + } + + // measure sign + var signature = Signature(AltBabyJubjub.zero, BigInteger.ZERO) + + signTimeElapsed += measureNanoTime { + signature = schnorr.signRawMessage(msgBytes = byteArrayOf(m.toByte()), seed = nextBytes(80)) + } + + // measure verify + verifyTimeElapsed += measureNanoTime { + schnorr.verifyRawMessage(byteArrayOf(m.toByte()), signature) + } + } + + println("Key generation:") + println("Total time (nanos): $keyGenTimeElapsed") + println("Average time per operation (nanos): ${keyGenTimeElapsed / numRuns}\n\n") + + println("Sign Raw Message:") + println("Total time (nanos): $signTimeElapsed") + println("Average time per operation (nanos): ${signTimeElapsed / numRuns}\n\n") + + println("Verify Raw Message:") + println("Total time (nanos): $verifyTimeElapsed") + println("Average time per operation (nanos): ${verifyTimeElapsed / numRuns}\n\n") + } + + @Test + @Tag("benchmark") + fun benchmarkHashedMessage() { + val numRuns = 1000 + val schnorr = SchnorrSignature.zinc + + var keyGenTimeElapsed: Long = 0 + var signTimeElapsed: Long = 0 + var verifyTimeElapsed: Long = 0 + + for (m in 1..numRuns) { + + // measure KeyGen + keyGenTimeElapsed += measureNanoTime { + schnorr.nextKeyPair() + } + + // measure sign + var signature = Signature(AltBabyJubjub.zero, BigInteger.ZERO) + + signTimeElapsed += measureNanoTime { + signature = schnorr.signHashedMessage(msgBytes = byteArrayOf(m.toByte()), seed = nextBytes(80)) + } + + // measure verify + verifyTimeElapsed += measureNanoTime { + schnorr.verifyHashedMessage(byteArrayOf(m.toByte()), signature) + } + } + + println("Key generation:") + println("Total time (nanos): $keyGenTimeElapsed") + println("Average time per operation (nanos): ${keyGenTimeElapsed / numRuns}\n\n") + + println("Sign Hashed Message:") + println("Total time (nanos): $signTimeElapsed") + println("Average time per operation (nanos): ${signTimeElapsed / numRuns}\n\n") + + println("Verify Hashed Message:") + println("Total time (nanos): $verifyTimeElapsed") + println("Average time per operation (nanos): ${verifyTimeElapsed / numRuns}\n\n") + } +} diff --git a/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/TestVectors.kt b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/TestVectors.kt new file mode 100644 index 0000000..e76ce85 --- /dev/null +++ b/src/test/kotlin/com/ing/dlt/zkkrypto/ecc/schnorr/TestVectors.kt @@ -0,0 +1,128 @@ +package com.ing.dlt.zkkrypto.ecc.schnorr + +object TestVectors { + + val testVectorsPlainMessage = listOf( + + // Message values from Corda EdDSA tests + TestVector( + privateKey = "038cb2eced2553b53133ff70f2d28b6fd4760bf4d4a64bbde4ff5f1e446a6251", + publicKeyX = "19e177e8998d7d6a9bba8c0d399b07275da9908d74c5adb36c7a84611e7a7abd", + publicKeyY = "10de9f775acede9cd781e13b5205637fd89c557621916bb2fb4c2512fac45c78", + message = "", // empty message + seed = "88,91,244,149,205,193,80,4,23,180,91,192,139,202,216,176,208,166,95,177,125,117,195,70,113,211,93,203,182,142,243,109,37,184,56,173,130,97,188,157,162,110,150,170,183,112,208,196,77,136,156,179,129,245,33,12,142,113,151,91,35,82,228,9,28,41,215,22,207,230,69,169,60,159,83,120,188,25,127,121", + signatureRX = "07b59bcca12d60bb8870c427e30c4a798beaf32fe241ef9989f8c540db5a93dc", + signatureRY = "20ffb2cf167ca64add9600be6241b7ede765db1a1d55a1c78f1978a6c4113c0b", + signatureS = "03cb643f7802037406e7f2d5e11b006f2ea43bd433e6f23a5b040c0584b017d1" + ), + TestVector( + privateKey = "039a36bb2b19494c1c0fed77f7ddfe73297ef9af33a41653ce0675ea66133b88", + publicKeyX = "1266034645de82aa40399d70f590d138e3a687c5dd10d1912baa09804a843365", + publicKeyY = "036cf1a11d4cdde482d179582cb0f9393c2935f6db099a1f7070e47cd2dac7da", + message = "114", // hex = 72 + seed = "241,107,170,171,219,102,219,79,229,151,94,185,50,182,251,81,127,126,138,237,52,70,251,59,99,178,9,221,158,98,150,162,171,195,26,168,197,172,180,18,64,109,102,86,160,37,139,141,166,112,208,191,134,223,194,78,234,5,240,47,187,104,48,174,96,210,117,37,171,203,177,37,237,177,177,227,40,218,249,252", + signatureRX = "2632e529ce386e2a582056c48fc6a082dec26fc4521567163b7afa0fd56ae967", + signatureRY = "1239365c2e746ba67e93d1a0fd70bd85bb9c4bdb8ac2a2a0c1352f7553123334", + signatureS = "034c6ae88222fdc8d33768fed32cdebdc8b9a589d24da0158797af8d8ac9df98" + ), + TestVector( + privateKey = "025c8c6e1ceb477f5c0cf22b890dc3eac3c9c74a35d45e56744d2297cdc1a93a", + publicKeyX = "16f33668fd33167d1143056b2bb8b69d5ffe5c4bdc1a5026e311a125e11a40a6", + publicKeyY = "07a3cbb622b1e841ad4438b00bf551b79d20157fba1667839b2151caa1cc8ac1", + message = "44930", // hex = af82 + seed = "111,138,202,167,181,181,163,122,36,101,151,201,204,243,20,119,82,25,185,94,251,154,72,253,223,80,224,224,166,120,108,193,53,160,71,201,132,63,208,125,4,133,165,133,233,219,90,225,136,3,126,17,112,190,176,193,209,225,2,217,188,65,236,79,124,114,24,161,4,33,74,29,102,198,51,119,24,199,43,151", + signatureRX = "23d6f4c36141c6967fd01e4fe4acb40697c77c2ebb07fc35e1634212badad626", + signatureRY = "1dcd19392fa7563c6b8a7eb4aeea797c5b2bba633abda4b388c5c70697488e96", + signatureS = "03181ab699c14397c578462c49becf0b821ef87f8461fdd066cf9e81ffd5124d" + ), + + // Message values from Zinc EdDSA tests + TestVector( + privateKey = "05368b800322fad50e74d9b1eab3364570d67a56ef133de0c8dbf1deaf2a474e", + publicKeyX = "2d3801d48de21c009f4329af753cc554793c98c0c9594f4a20f7e7d23608d69d", + publicKeyY = "2e55266f6fb271ccd351cbb10cf953adafcafe7c6785375f583611063ddf93cb", + message = "Foo bar pad to16", // hex = 466f6f206261722070616420746f3136 + seed = "134,245,113,236,136,59,19,27,76,5,253,165,115,138,202,147,181,185,14,68,0,165,176,39,22,152,202,206,85,58,80,131,80,99,2,93,106,188,240,108,249,81,18,197,55,120,130,95,243,72,190,98,221,182,232,44,229,198,123,121,83,199,177,46,99,226,37,128,73,201,76,16,97,128,229,135,107,38,14,32", + signatureRX = "1e28502328d10991706fa7566e753be3c5d63c03f3c22a44f1b9fe7de01468f5", + signatureRY = "15066772958ad66ac1257bb320eec3878ef542099b94dd0d4abb3c65becffe63", + signatureS = "0118041f1d74e9a8488c5a52c51708b733d63b90caadc4990d15fd854e3e6e87" + ), + TestVector( + privateKey = "01c168e3e5d576d21db750ad9164281118a8cfcdeaf0c1fc9e795ead24311269", + publicKeyX = "081df10662923d7a3ab07661d7f84ba719c453a4a25153428feda227ad316db2", + publicKeyY = "0c4a7e307278f2aceaab5825d3cb9db9f83d14d4cbb011f531e3af3ddd6b9866", + message = "85", // hex = 55 + seed = "175,64,254,140,185,105,89,5,159,233,108,177,211,223,17,153,223,63,176,233,33,78,147,242,1,166,201,125,198,202,151,214,103,13,36,200,108,181,238,95,241,87,94,192,199,228,203,7,107,133,2,168,114,122,156,48,55,4,7,241,72,75,97,11,12,221,181,118,12,103,110,30,136,57,86,237,23,98,167,52", + signatureRX = "040d93fcdb43838facdd86f61c1de5776fa37c98fb45c094fd1b62b6730d23ed", + signatureRY = "2097fd3ba4e104d052a3ba43e90c62453a137dd082ee13da093751212cd9f83f", + signatureS = "02f872b014f7b85c21001032f03418e21872dd478cfa8a58b9feaaa0499c08d4" + ) + ) + + val testVectorsHashedMessage = listOf( + + // Message values from Corda EdDSA tests + TestVector( + privateKey = "0221685bd28aba5c2db6e7b56b20dafe00f61f83f174d5d5afaf3aa1c601d97b", + publicKeyX = "153a7c3f2f01068a00f69b3f6c5bd9dc1dd7bc9e6a9749a1706e2a3f75269b7d", + publicKeyY = "04bcb9b3237cb96a98b89bcf96cc7e9ded03336a9fc4867e3fd0a45a37a77c62", + message = "", // empty message + seed = "153,132,33,210,245,249,24,102,201,202,138,234,50,193,78,175,239,7,124,243,241,63,88,8,19,68,157,193,201,174,91,66,218,183,146,20,16,197,197,43,234,33,231,171,58,59,193,49,90,198,55,56,206,196,163,107,128,138,48,35,30,135,79,29,76,54,36,34,225,167,61,26,113,72,84,75,160,163,252,195", + signatureRX = "1b8ff09fb2e74999bdf25f8371e4345dae0ef463c4317c19ba0b75cbf9e0e63b", + signatureRY = "239481a754cf8b274cec444b7ae6909937927d545cbcf8b463106e85c77f15a3", + signatureS = "01c3b69e088c6bcff3eac2b996370a0459cdb7551b4d379997dc6a47ae252a25" + ), + TestVector( + privateKey = "04fd1a8d01884a505336b038824cb93b28fb9b1bea74cdc8f0b378271990994f", + publicKeyX = "2cd65017aa374562cb29873070e3e15dc0c32edff15592354236ae43c131c002", + publicKeyY = "1c289a5fa9cf4e75f588f1602c42e7db99dc4e50e68933fdb06b02b13381affc", + message = "114", + seed = "79,190,111,253,67,76,192,160,166,221,114,125,76,211,238,76,41,125,218,159,73,96,21,121,101,246,226,65,50,28,233,104,183,201,109,24,73,118,56,41,33,68,209,127,197,74,176,7,182,155,181,31,192,164,158,38,193,204,11,96,218,60,132,180,210,197,17,223,129,157,40,10,28,113,103,40,44,101,185,62", + signatureRX = "0fcfcb5dc87336c22864d04df03f5469337164b3ad5c4e46e508b7036e6f73b0", + signatureRY = "0141648c840ed67ed068fa08d55bd41afa4627e2fdd189c281d71b3fbb55c81b", + signatureS = "053c4f71fdb4a0410bbb06d2ca4f57223a5420b0d769031d3e66b8ffd6f61af7" + ), + TestVector( + privateKey = "001dd6fc631336f133c2080b29f8fe9c7d6a23bc8a65a0421a47490402ef94e1", + publicKeyX = "0fc4a18ac3079e2e29592637078c0a2f4e2d049e550cf77d14feaf0b715abc01", + publicKeyY = "148ae1ac557c1eb2aa0d5f5761c9133520632a7340745e5f4079b6e14de36c4b", + message = "44930", + seed = "43,128,86,219,211,163,3,4,172,151,115,34,168,178,86,174,40,229,188,154,226,197,13,5,153,123,214,13,143,128,29,122,86,31,248,204,116,175,205,139,190,157,54,215,150,55,159,212,154,120,230,56,122,182,149,143,23,232,31,22,63,124,249,34,56,190,11,236,123,204,50,192,109,42,150,84,162,183,49,108", + signatureRX = "15aac870d3ca8f2f5532be509231253d0ec8368b7ab800f1cf464d78cebe97a5", + signatureRY = "1852f2d83de46c3c0c852a710ca528653d4c2e025e2adab5883e96852acf996e", + signatureS = "04fb958b6e923fa17540400e5b273ee9be27e90359e750b1e4bf1ef0602a3d71" + ), + // Message values from Zinc EdDSA tests + TestVector( + privateKey = "05368b800322fad50e74d9b1eab3364570d67a56ef133de0c8dbf1deaf2a474e", + publicKeyX = "2d3801d48de21c009f4329af753cc554793c98c0c9594f4a20f7e7d23608d69d", + publicKeyY = "2e55266f6fb271ccd351cbb10cf953adafcafe7c6785375f583611063ddf93cb", + message = "Foo bar pad to16", + seed = "134,245,113,236,136,59,19,27,76,5,253,165,115,138,202,147,181,185,14,68,0,165,176,39,22,152,202,206,85,58,80,131,80,99,2,93,106,188,240,108,249,81,18,197,55,120,130,95,243,72,190,98,221,182,232,44,229,198,123,121,83,199,177,46,99,226,37,128,73,201,76,16,97,128,229,135,107,38,14,32", + signatureRX = "1e28502328d10991706fa7566e753be3c5d63c03f3c22a44f1b9fe7de01468f5", + signatureRY = "15066772958ad66ac1257bb320eec3878ef542099b94dd0d4abb3c65becffe63", + signatureS = "00ae07f728917c50fcfbe11f9946baa3851cfc410698069ed157b5704f1f2e08" + ), + TestVector( + privateKey = "00b647a4a9faad77d1cc52f9dc3d103b79439399d4ff7effd073dd25d3fec3bc", + publicKeyX = "27fb8e130f0bf2cf48af0cad462f0b8b9882ceb6b04198af9b03822c66f66226", + publicKeyY = "2232246bcd1968cef89508e65fe8a670005b1e55265f8b2e0cc9c1ca218d7407", + message = "85", + seed = "86,90,37,124,65,244,182,229,141,100,56,54,103,190,64,25,176,96,100,19,229,232,117,65,68,57,133,20,77,170,71,99,48,107,36,251,142,102,87,146,83,11,12,60,9,74,210,123,99,246,40,143,96,254,19,65,124,10,69,32,93,47,239,193,224,183,31,49,149,80,201,110,171,192,244,132,57,235,193,235", + signatureRX = "26de31489e9f36b11845d8aa96055f7af23184daea613adf1916bd12a270f1c0", + signatureRY = "16c0422abf353dd7b51d8143c1d36fc5feaefe61c127ad125066409b827559f9", + signatureS = "04357e3a31baa5f846dc6bb7113f2d9c068977d2481c82d263f6e9535ab75743" + ) + ) + + data class TestVector( + val privateKey: String, + val publicKeyX: String, + val publicKeyY: String, + val message: String, + val seed: String, + val signatureRX: String, + val signatureRY: String, + val signatureS: String + ) +}