diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/CurveProcessor.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/CurveProcessor.java new file mode 100644 index 0000000000..66d20e892b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/CurveProcessor.java @@ -0,0 +1,47 @@ +package org.bouncycastle.crypto.hash2curve; + +import org.bouncycastle.crypto.hash2curve.data.AffineXY; +import org.bouncycastle.math.ec.ECPoint; + +/** + * Process curve specific functions + */ +public interface CurveProcessor { + + /** + * Add two points in the curve group. + * Semantics are curve-model specific. + */ + ECPoint add(ECPoint p, ECPoint q); + + /** + * Clears the cofactor from the given elliptic curve point. + * + * @param ecPoint the elliptic curve point to process + * @return the elliptic curve point with the cofactor cleared + */ + ECPoint clearCofactor(ECPoint ecPoint); + + /** + * Converts an elliptic-curve point into the affine (x, y) coordinate representation + * defined by the hash-to-curve suite. + * + *

The returned coordinates are intended for serialization, testing, and + * interoperability with the reference outputs defined in RFC 9380. + * For most Weierstrass curves, this is simply the affine (x, y) coordinates of + * the given point. For curves that use a different coordinate model in the + * specification (e.g. Montgomery curves such as curve25519), this method applies + * the appropriate coordinate transformation.

+ * + *

This method does not change the underlying group element represented + * by the point. It only changes how that point is expressed as field elements. + * The input point is expected to be a valid point on the curve used by the + * implementation.

+ * + * @param p a valid elliptic-curve point + * @return the affine (x, y) coordinates corresponding to the suite-specific + * representation of the given point + */ + AffineXY mapToAffineXY(ECPoint p); + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/H2cUtils.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/H2cUtils.java new file mode 100644 index 0000000000..10b48f87ec --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/H2cUtils.java @@ -0,0 +1,194 @@ +package org.bouncycastle.crypto.hash2curve; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Arrays; + +import java.math.BigInteger; +import java.util.Objects; + +/** + * Utility functions for hash 2 curve + *

+ * This implementation follows the straight-line, branch-free algorithmic structure required by RFC 9380, ensuring that + * all code paths perform the same sequence of mathematical operations regardless of input values. However, it relies on + * Java’s BigInteger arithmetic and standard JVM execution characteristics, neither of which provides strict guarantees + * of constant-time behavior at the microarchitectural level. Operations such as modular exponentiation, multiplication, + * inversion, and even conditional value selection (cmov) may execute in variable time depending on internal + * optimizations, operand size, and JIT behavior. + *

+ * For most applications, this is sufficient to avoid the major side-channel pitfalls associated with probabilistic or + * data-dependent loops (e.g., try-and-increment). But if your threat model requires strong, formally constant-time + * guarantees, such as protection against local timing attacks or hostile co-tenant environments, you should consider + * using a lower-level language with fixed-limb field arithmetic and verifiable constant-time primitives. Java cannot + * practically provide such guarantees with BigInteger-based implementations. + */ +public class H2cUtils { + + /** + * Constant time implementation of selection of value based on condition + * + * @param a value selected on condition = false + * @param b value selected on condition = true + * @param condition condition + * @param the type of object to select + * @return 'a' if condition is false, else 'b' + */ + public static T cmov(final T a, final T b, final boolean condition) { + return condition ? b : a; + } + + /** + * Test if a value is square in a prime field order + * + * @param val value to test + * @param order prime field order + * @return true if val is square + */ + public static boolean isSquare(final BigInteger val, final BigInteger order) { + final BigInteger modPow = val.modPow(order.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)), order); + return modPow.equals(BigInteger.ONE) || modPow.equals(BigInteger.ZERO); + } + + /** + * Calculate the square root of val in a prime field order + * + * @param val value + * @param order prime field order + * @return square root of val in field order + */ + public static BigInteger sqrt(final BigInteger val, final BigInteger order) { + // Get the largest integer c1 where 2^c1 divides order - 1 + final int c1 = order.subtract(BigInteger.ONE).getLowestSetBit(); + final BigInteger c2 = order.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2).pow(c1)); + final BigInteger c3 = c2.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + final BigInteger c4 = getFirstNonSquare(order); + final BigInteger c5 = c4.modPow(c2, order); + + // Procedure + BigInteger z = val.modPow(c3, order); + BigInteger t = (z.multiply(z).multiply(val)).mod(order); + z = (z.multiply(val)).mod(order); + BigInteger b = t; + BigInteger c = c5; + for (int i = c1; i >= 2; i--) { + for (int j = 1; j <= i - 2; j++) { + b = (b.multiply(b)).mod(order); + } + final boolean e = b.equals(BigInteger.ONE); + final BigInteger zt = (z.multiply(c)).mod(order); + z = cmov(zt, z, e); + c = (c.multiply(c)).mod(order); + final BigInteger tt = (t.multiply(c)).mod(order); + t = cmov(tt, t, e); + b = t; + } + return z; + } + + /** + * Returns the sign of the BigInteger 'val' using the given ECParameterSpec 'spec'. + * + * @param val the BigInteger value + * @param curve the EC curve specifying the curve field + * @return the sign of 'val' + * @throws IllegalArgumentException if spec.getCurve().getField().getDimension() != 1 + */ + public static int sgn0(final BigInteger val, final ECCurve curve) { + if (curve.getField().getDimension() == 1) { + return val.mod(BigInteger.valueOf(2)).intValue(); + } + throw new IllegalArgumentException("Extension fields must be 1 for supported elliptic curves"); + } + + /** + * Calculates the modular inverse of a BigInteger 'val' with respect to a given BigInteger 'order'. + * + * @param val the BigInteger value to calculate the inverse for + * @param order the BigInteger representing the order + * @return the modular inverse of 'val' with respect to 'order' + */ + public static BigInteger inv0(final BigInteger val, final BigInteger order) { + return val.modInverse(order); + } + + /** + * Convert an integer value to a byte array of a specified length. + * + * @param val the integer value to be converted + * @param len the length of the resulting byte array + * @return the byte array representation of the integer value + * @throws IllegalArgumentException if the value requires more bytes than the assigned length size + */ + public static byte[] i2osp(final int val, final int len) { + final byte[] lengthVal = new BigInteger(String.valueOf(val)).toByteArray(); + byte[] paddedLengthVal = lengthVal.clone(); + if (paddedLengthVal.length > 1 && paddedLengthVal[0] == 0x00) { + // Remove leading 00 + paddedLengthVal = Arrays.copyOfRange(paddedLengthVal, 1, paddedLengthVal.length); + } + if (paddedLengthVal.length > len) { + throw new IllegalArgumentException("Value require more bytes than the assigned length size"); + } + + if (paddedLengthVal.length < len) { + // Pad up to expected size + for (int i = paddedLengthVal.length; i < len; i++) { + paddedLengthVal = Arrays.concatenate(new byte[] { 0x00 }, paddedLengthVal); + } + } + return paddedLengthVal; + } + + /** + * Converts a byte array to a BigInteger. + * + * @param val the byte array to convert + * @return the BigInteger representation of the byte array + */ + public static BigInteger os2ip(final byte[] val) { + // Make sure we get a positive value by adding 0x00 as leading byte in the value byte array + return new BigInteger(Arrays.concatenate(new byte[] { 0x00 }, val)); + } + + /** + * Performs bitwise XOR operation on two byte arrays. + * + * @param arg1 the first byte array + * @param arg2 the second byte array + * @return the result of the XOR operation as a new byte array + * @throws NullPointerException if either arg1 or arg2 is null + * @throws IllegalArgumentException if arg1 and arg2 have different lengths + */ + public static byte[] xor(final byte[] arg1, final byte[] arg2) { + Objects.requireNonNull(arg1, "XOR argument must not be null"); + Objects.requireNonNull(arg2, "XOR argument must not be null"); + + if (arg1.length != arg2.length) { + throw new IllegalArgumentException("XOR operation on parameters of different lengths"); + } + final byte[] xorArray = new byte[arg1.length]; + for (int i = 0; i < arg1.length; i++) { + xorArray[i] = (byte) (arg1[i] ^ arg2[i]); + } + return xorArray; + } + + /** + * Get the first non-square member of the curve order + * + * @param order curve order + * @return first non-square member of the curve order + */ + private static BigInteger getFirstNonSquare(final BigInteger order) { + final BigInteger maxCount = new BigInteger("1000"); + BigInteger nonSquare = BigInteger.ONE; + while (isSquare(nonSquare, order)) { + nonSquare = nonSquare.add(BigInteger.ONE); + if (nonSquare.compareTo(maxCount) > 0) { + throw new RuntimeException("Illegal Field. No non square value can be found"); + } + } + return nonSquare; + } + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToCurveProfile.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToCurveProfile.java new file mode 100644 index 0000000000..4f913a0ce0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToCurveProfile.java @@ -0,0 +1,109 @@ +package org.bouncycastle.crypto.hash2curve; + +import java.math.BigInteger; + +/** + * Supported profiles for instantiating an instance of HashToEllipticCurve. + * Each profile supports both hash_to_curve and encode_to_curve operations, according to RFC 9380 + *

+ * _NU_ is identical to _RO_, except that the encoding type is encode_to_curve. encode_to_curve is not yet + * implemented in this lib, thus these options are not yet included + */ +public enum HashToCurveProfile { + + P256_XMD_SHA_256(BigInteger.valueOf(-10), 48, 128, 1, null, null), + P384_XMD_SHA_384(BigInteger.valueOf(-12), 72, 192, 1, null, null), + P521_XMD_SHA_512(BigInteger.valueOf(-4), 98, 256, 1, null, null), + CURVE25519W_XMD_SHA_512_ELL2(BigInteger.valueOf(2), 48, 128, 8, 486662, 1); + // For future considerations + // curve448_XOF_SHAKE256_ELL2_RO_(BigInteger.valueOf(-1), 84, 224, 4, 156326, 1), + // edwards25519_XMD_SHA_512_ELL2_RO_(BigInteger.valueOf(2), 48, 224, 8, 486662, 1), + // edwards448_XOF_SHAKE256_ELL2_RO_(BigInteger.valueOf(-1), 84, 224, 4, 156326, 1), + + /** + * The z value is a value of the curve field that satisfies the following criteria: + *

    + *
  1. Z is non-square in F. This is a field object e.g., F = GF(2^521 - 1).
  2. + *
  3. Z is not equal to negative one -1 in the field F.
  4. + *
  5. The polynomial g(x) - Z is irreducible over the field F. In this context, an irreducible polynomial cannot be factored into polynomials of lower degree, also in the field F
  6. + *
  7. The polynomial g(B / (Z * A)) should be a square number in the field F
  8. + *
+ */ + private final BigInteger Z; + /** Block length */ + private final int L; + /** The target security level in bits for the curve */ + private final int k; + /** Effective cofactor */ + private final int h; + /** Montgomery A parameter */ + private final Integer mJ; + /** Montgomery B parameter */ + private final Integer mK; + + HashToCurveProfile(final BigInteger z, final int l, final int k, int h, Integer mJ, Integer mK) { + this.Z = z; + this.L = l; + this.k = k; + this.h = h; + this.mJ = mJ; + this.mK = mK; + } + + + /** + * Retrieves the security level in bits associated with this instance. + * + * @return the value of the field 'k' representing security level in bits + */ + public int getK() { + return k; + } + + /** + * Retrieves the value of the field 'L' representing the internal block size in bytes associated with this instance. + * + * @return the value of the field 'L' representing the internal block size + */ + public int getL() { + return L; + } + + /** + * Retrieves the value of the field 'Z'. + * + * @return the value of the field 'Z' as a BigInteger + */ + public BigInteger getZ() { + return Z; + } + + /** + * Retrieves the value of the field 'h', representing the cofactor associated + * with this instance. + * + * @return the value of the field 'h' as an integer + */ + public int getH() { + return h; + } + + /** + * Retrieves the value of the field 'mJ' representing the associated Montgomery equation parameter A + * + * @return the value of the field 'mJ' as an Integer + */ + public Integer getmJ() { + return mJ; + } + + /** + * Retrieves the value of the field 'mK' representing the associated Montgomery equation parameter B + * specific to the hash-to-curve profile. + * + * @return the value of the field 'mK' as an Integer + */ + public Integer getmK() { + return mK; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToEllipticCurve.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToEllipticCurve.java new file mode 100644 index 0000000000..411c0b9018 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToEllipticCurve.java @@ -0,0 +1,126 @@ +package org.bouncycastle.crypto.hash2curve; + +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.hash2curve.data.AffineXY; +import org.bouncycastle.crypto.hash2curve.impl.Elligator2MapToCurve; +import org.bouncycastle.crypto.hash2curve.impl.MontgomeryCurveProcessor; +import org.bouncycastle.crypto.hash2curve.impl.NistCurveProcessor; +import org.bouncycastle.crypto.hash2curve.impl.SimplifiedShallueVanDeWoestijneMapToCurve; +import org.bouncycastle.crypto.hash2curve.impl.XmdMessageExpansion; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.custom.djb.Curve25519; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; + +/** + * Main class for implementing hash to elliptic curve according to RFC 9380 + *

+ * + * Steps: 1. u = hash_to_field(msg, 2) 2. Q0 = map_to_curve(u[0]) 3. Q1 = map_to_curve(u[1]) 4. R = Q0 + Q1 + * # Point addition 5. P = clear_cofactor(R) 6. return P + * + */ +public class HashToEllipticCurve { + + protected final HashToField hashToField; + protected final MapToCurve mapToCurve; + protected final CurveProcessor curveProcessor; + + protected HashToEllipticCurve(final HashToField hashToField, + final MapToCurve mapToCurve, final CurveProcessor curveProcessor) { + this.curveProcessor = curveProcessor; + this.hashToField = hashToField; + this.mapToCurve = mapToCurve; + } + + public static HashToEllipticCurve getInstance(final HashToCurveProfile profile, String dst) { + byte[] dstBytes = dst.getBytes(StandardCharsets.UTF_8); + ECCurve curve; + switch (profile) { + case P256_XMD_SHA_256: + curve = new SecP256R1Curve(); + return new HashToEllipticCurve(new HashToField(dstBytes, curve, new XmdMessageExpansion(new SHA256Digest(), + profile.getK()), profile.getL()), new SimplifiedShallueVanDeWoestijneMapToCurve(curve, profile.getZ()), + new NistCurveProcessor()); + case P384_XMD_SHA_384: + curve = new SecP384R1Curve(); + return new HashToEllipticCurve(new HashToField(dstBytes, curve, new XmdMessageExpansion(new SHA384Digest(), + profile.getK()), profile.getL()), new SimplifiedShallueVanDeWoestijneMapToCurve(curve, profile.getZ()), + new NistCurveProcessor()); + case P521_XMD_SHA_512: + curve = new SecP521R1Curve(); + return new HashToEllipticCurve(new HashToField(dstBytes, curve, new XmdMessageExpansion(new SHA512Digest(), + profile.getK()), profile.getL()), new SimplifiedShallueVanDeWoestijneMapToCurve(curve, profile.getZ()), + new NistCurveProcessor()); + case CURVE25519W_XMD_SHA_512_ELL2: + curve = new Curve25519(); + return new HashToEllipticCurve(new HashToField(dstBytes, curve, new XmdMessageExpansion(new SHA512Digest(), + profile.getK()), profile.getL()), new Elligator2MapToCurve(curve, profile.getZ(), BigInteger.valueOf( + profile.getmJ()), BigInteger.valueOf(profile.getmK())), + new MontgomeryCurveProcessor(curve, profile.getmJ(), profile.getmK(), profile.getH())); + default: + throw new IllegalArgumentException("Unsupported profile: " + profile); + } + } + + /** + * Hashes a message to an elliptic curve point using the RFC 9380 hash_to_curve function. + * This function provides a uniform distribution of resulting points. + * + * @param message the message to be hashed + * @return the resulting elliptic curve point P + */ + public ECPoint hashToCurve(final byte[] message) { + final BigInteger[][] u = this.hashToField.process(message, 2); + final ECPoint Q0 = this.mapToCurve.process(u[0][0]); + final ECPoint Q1 = this.mapToCurve.process(u[1][0]); + final ECPoint R = curveProcessor.add(Q0, Q1); + return this.curveProcessor.clearCofactor(R); + } + + /** + * Encode a message to an elliptic curve point using the RFC 9380 encode_to_curve function. + * This function does not provide a uniform distribution of resulting points. This function MUST NOT + * be used when uniform distribution is a security requirement. + * + * @param message the message to be hashed + * @return the resulting elliptic curve point P + */ + public ECPoint encodeToCurve(final byte[] message) { + final BigInteger[][] u = this.hashToField.process(message, 1); + final ECPoint Q0 = this.mapToCurve.process(u[0][0]); + return this.curveProcessor.clearCofactor(Q0); + } + + /** + * Converts an elliptic-curve point into the affine (x, y) coordinate representation + * defined by the hash-to-curve suite. + * + *

The returned coordinates are intended for serialization, testing, and + * interoperability with the reference outputs defined in RFC 9380. + * For most Weierstrass curves, this is simply the affine (x, y) coordinates of + * the given point. For curves that use a different coordinate model in the + * specification (e.g. Montgomery curves such as curve25519), this method applies + * the appropriate coordinate transformation.

+ * + *

This method does not change the underlying group element represented + * by the point. It only changes how that point is expressed as field elements. + * The input point is expected to be a valid point on the curve used by the + * implementation.

+ * @param point point on the chosen ECCurve for the selected hash2Curve profile + * @return AffineXY coordinates for the point on the curve defined in RFC 9380 for the selected profile + */ + public AffineXY getAffineXY(ECPoint point) { + return curveProcessor.mapToAffineXY(point); + } + + + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToField.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToField.java new file mode 100644 index 0000000000..8813a6e247 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/HashToField.java @@ -0,0 +1,80 @@ +package org.bouncycastle.crypto.hash2curve; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Arrays; + +import java.math.BigInteger; + +/** + * Generic implementation of hash to field + *

+ * This implementation is restricted to hashing to a field where the field + * being hashed to is derived from an Elliptic curve + *

+ * The HashToField function can be used to hash to any field such as a scalar field (group order) + * This implementation is not suitable for such cases as described in more detail in the + * GenericOPRFHashToScalar function. Instead, this class is strictly used to implement + * HashToField when hashing is done to curve order as this is the way the function is + * used in HashToEllipticCurve operations. + */ +public class HashToField { + + protected final byte[] dst; + protected final ECCurve curve; + protected final MessageExpansion messageExpansion; + /** Security parameter for the suite */ + protected int L; + protected int m; + protected BigInteger p; + + /** + * Constructs a new instance of the HashToCurveField class. + *

+ * This constructor allows the creation of a hash-to-field mechanism tied to an elliptic curve, + * with parameters specifying domain separation, message expansion mechanics, security level, + * and the count of resulting field elements. + * + * @param dst The domain separation tag, used to separate different domains of usage to + * ensure distinct use cases do not produce the same output for the same input. + * @param curve The elliptic curve from which the field to hash to is derived. + * @param messageExpansion The mechanism for expanding input messages, ensuring the + * required cryptographic properties for subsequent field hashing. + * @param L The security parameter for the suite, determining the byte length of + * individual elements used in the computation. + */ + public HashToField(final byte[] dst, final ECCurve curve, final MessageExpansion messageExpansion, final int L) { + this.dst = dst; + this.curve = curve; + this.L = L; + this.messageExpansion = messageExpansion; + this.p = curve.getField().getCharacteristic(); + this.m = curve.getField().getDimension(); + } + + /** + * Processes the input message and hashes it into a multidimensional array of elements + * in a finite field derived from an elliptic curve. The hashing mechanism leverages + * message expansion and modular arithmetic to ensure cryptographic security. + * + * @param message The input message to be hashed into field elements. + * @param count The number of resulting field elements to be produced during the hashing process. + * @return A two-dimensional array of BigInteger, where each entry represents a field + * element derived from the input message. + */ + public BigInteger[][] process(final byte[] message, final int count) { + + final int byteLen = count * this.m * this.L; + final byte[] uniformBytes = this.messageExpansion.expandMessage(message, this.dst, byteLen); + final BigInteger[][] u = new BigInteger[count][this.m]; + for (int i = 0; i < count; i++) { + final BigInteger[] e = new BigInteger[this.m]; + for (int j = 0; j < this.m; j++) { + final int elmOffset = this.L * (j + i * this.m); + final byte[] tv = Arrays.copyOfRange(uniformBytes, elmOffset, elmOffset + this.L); + e[j] = H2cUtils.os2ip(tv).mod(this.p); + } + u[i] = e; + } + return u; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/MapToCurve.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/MapToCurve.java new file mode 100644 index 0000000000..fcbb9d428f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/MapToCurve.java @@ -0,0 +1,21 @@ +package org.bouncycastle.crypto.hash2curve; + +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +/** + * Interface for Map to Curve + */ +public interface MapToCurve { + + /** + * Processes the given BigInteger element and maps it to a point on the elliptic curve, as defined + * by the hash 2 curve specification + * + * @param element the input BigInteger element to be mapped to a point on the curve + * @return the elliptic curve point corresponding to the input element + */ + ECPoint process(BigInteger element); + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/MessageExpansion.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/MessageExpansion.java new file mode 100644 index 0000000000..4d01d0f7c4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/MessageExpansion.java @@ -0,0 +1,18 @@ +package org.bouncycastle.crypto.hash2curve; + +/** + * The MessageExpansion interface defines a contract for expanding a message. + */ +public interface MessageExpansion { + + /** + * Expands the given message to match the specified length in bytes. + * + * @param msg the original message to be expanded + * @param dst domain separation tag + * @param lenInBytes the desired length of the expanded message in bytes + * @return the expanded message as a byte array + */ + byte[] expandMessage(byte[] msg, byte[] dst, int lenInBytes); + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/OPRFHashToScalar.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/OPRFHashToScalar.java new file mode 100644 index 0000000000..e58c82d978 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/OPRFHashToScalar.java @@ -0,0 +1,95 @@ +package org.bouncycastle.crypto.hash2curve; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.hash2curve.impl.XmdMessageExpansion; +import org.bouncycastle.math.ec.ECCurve; + +import java.math.BigInteger; + +/** + * Generic implementation of HashToScalar as used in OPRF (RFC 9497). + * + *

This implementation intentionally provides a *single* unified HashToScalar construction for + * all supported prime-order elliptic curve groups (P-256, P-384, P-521, Curve25519, Ristretto255, + * and Decaf448). Although RFC 9497 appears to specify different procedures for NIST curves and + * Edwards-family curves, these procedures are mathematically equivalent to one another and can be + * implemented using one common algorithm.

+ * + *

Background

+ * + *

RFC 9497 defines HashToScalar as follows:

+ * + * + *

At first glance these appear to be fundamentally different algorithms. However, the use + * of hash_to_field for NIST curves is 100% equivalent to doing the same message_expansion_xmd + * operation described for other curves. That is:

+ * + *
+ *   uniform_bytes = expand_message_xmd(msg, DST, L)
+ *   scalar        = OS2IP(uniform_bytes) mod q
+ * 
+ * + *

where {@code L = ceil((log2(q) + k) / 8)} and {@code k} is the security parameter for the + * ciphersuite. This is precisely the construction used for the Edwards-family curves. In other + * words, *both branches of RFC 9497 ultimately specify the same mathematical operation*.

+ * + *

Rationale for a unified implementation

+ * + *

Using a single generic implementation has several advantages:

+ * + * + *

For these reasons, this class implements the general form:

+ * + *
+ *   uniform_bytes = expand_message_xmd(msg, DST, L)
+ *   scalar        = OS2IP(uniform_bytes) mod group_order
+ * 
+ * + *

This behavior is fully compliant with RFC 9497 and RFC 9380 and is applicable to all + * prime-order elliptic-curve groups.

+ */ +public class OPRFHashToScalar { + + private final ECCurve curve; + private final MessageExpansion messageExpansion; + + private final int L; + + /** + * Constructs an instance of the OPRFHashToScalar class, which handles the process of encoding + * a message into a scalar value based on the provided elliptic curve and digest algorithm. + * + * @param curve the elliptic curve (ECCurve) used for the hashing process + * @param digest the digest algorithm (Digest) used for message hashing and expansion + * @param k the security parameter affecting the size of hashed output + */ + public OPRFHashToScalar(final ECCurve curve, final Digest digest, final int k) { + this.curve = curve; + this.L = + (int) Math.ceil(((double) curve.getOrder().subtract(BigInteger.ONE).bitLength() + k) / 8); + this.messageExpansion = new XmdMessageExpansion(digest, k); + } + + /** + * Hash the input message to a uniformly distributed scalar value on the elliptic curve. + * + * @param input the input message as a byte array + * @param dst the domain separation tag as a byte array + * @return a scalar value (BigInteger) derived from the input message + */ + public BigInteger process(final byte[] input, final byte[] dst) { + final byte[] expandMessage = this.messageExpansion.expandMessage(input, dst, this.L); + return new BigInteger(1, expandMessage).mod(this.curve.getOrder()); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/SqrtRatioCalculator.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/SqrtRatioCalculator.java new file mode 100644 index 0000000000..213c5ae51f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/SqrtRatioCalculator.java @@ -0,0 +1,22 @@ +package org.bouncycastle.crypto.hash2curve; + + +import org.bouncycastle.crypto.hash2curve.impl.SqrtRatio; + +import java.math.BigInteger; + +/** + * Interface for a calculator of SqrtRatio + */ +public interface SqrtRatioCalculator { + + /** + * he sqrtRatio subroutine of hash2Curve in the field F + * + * @param u u parameter, element of F + * @param v v parameter, element of F, such that v != 0 + * @return SqrtRatio result + */ + SqrtRatio sqrtRatio(BigInteger u, BigInteger v); + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/data/AffineXY.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/data/AffineXY.java new file mode 100644 index 0000000000..c014aac188 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/data/AffineXY.java @@ -0,0 +1,81 @@ +package org.bouncycastle.crypto.hash2curve.data; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +/** Simple holder for affine field coordinates. */ +public final class AffineXY { + private final BigInteger x; + private final BigInteger y; + + /** + * Constructs an {@code AffineXY} object representing the affine coordinates of an elliptic curve point. + * + * @param x the x-coordinate of the affine point + * @param y the y-coordinate of the affine point + */ + public AffineXY(BigInteger x, BigInteger y) { + this.x = x; + this.y = y; + } + + /** + * Constructs an {@code AffineXY} object representing the affine coordinates of the provided elliptic curve point. + * + * @param point the elliptic curve point from which the affine coordinates will be extracted + * @throws IllegalArgumentException if the provided point is at infinity + */ + public AffineXY(ECPoint point) { + this(point, true); + } + + /** + * Constructs an {@code AffineXY} object representing the affine coordinates of the provided elliptic curve point. + * + * @param point the elliptic curve point from which the affine coordinates will be extracted + * @param normalize {@code true} if the point should be normalized before extracting coordinates, {@code false} otherwise + * @throws IllegalArgumentException if the provided point is at infinity + */ + public AffineXY(ECPoint point, boolean normalize) { + if (point.isInfinity()) { + throw new IllegalArgumentException("Cannot extract affine coordinates from point at infinity"); + } + if (normalize) { + point = point.normalize(); + } + this.x = point.getAffineXCoord().toBigInteger(); + this.y = point.getAffineYCoord().toBigInteger(); + } + + /** + * Converts the affine coordinates of this object into an elliptic curve point + * on the specified curve. + * + * @param curve the elliptic curve to which the point belongs + * @return an {@code ECPoint} object created using the affine coordinates + * of this object on the given curve + */ + public ECPoint toPoint(ECCurve curve) { + return curve.createPoint(getX(), getY()).normalize(); + } + + /** + * Retrieves the x-coordinate of the affine point. + * + * @return the x-coordinate as a {@code BigInteger} + */ + public BigInteger getX() { + return x; + } + + /** + * Retrieves the y-coordinate of the affine point. + * + * @return the y-coordinate as a {@code BigInteger} + */ + public BigInteger getY() { + return y; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/Elligator2MapToCurve.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/Elligator2MapToCurve.java new file mode 100644 index 0000000000..25ea25ea35 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/Elligator2MapToCurve.java @@ -0,0 +1,119 @@ +package org.bouncycastle.crypto.hash2curve.impl; + +import org.bouncycastle.crypto.hash2curve.H2cUtils; +import org.bouncycastle.crypto.hash2curve.MapToCurve; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +/** + * Implements the Elligator 2 Map to curve according to section 6.7.1 of RFC 9380 This is the + * straight-line implementation optimized for Montgomery curves as defined in section F.3. + */ +public class Elligator2MapToCurve implements MapToCurve { + + /** The elliptic curve for the instance */ + private final ECCurve curve; + /** A non-square element of F */ + private final BigInteger z; + /** Montgomery equation A constant */ + private final BigInteger J; + /** Montgomery equation B constant */ + private final BigInteger K; + private final BigInteger c1; // J / K + private final BigInteger c2; // 1 / K^2 + /** Curve field characteristic */ + private final BigInteger p; + + /** + * Constructs an Elligator2MapToCurve instance using the provided elliptic curve parameters and constants. + * + * @param curve the elliptic curve (ECCurve) to which the input values will be mapped + * @param z a non-square element of the elliptic curve field + * @param J the Montgomery curve equation A value (Named J in RFC 9380) + * @param K the Montgomery curve equation B value (Named K in RFC 9380) + */ + public Elligator2MapToCurve(final ECCurve curve, final BigInteger z, final BigInteger J, + final BigInteger K) { + this.curve = curve; + this.z = z; + this.J = J; + this.K = K; + + this.p = curve.getField().getCharacteristic(); + + // c1 = J / K + final BigInteger Kinv = K.modInverse(p); + this.c1 = J.multiply(Kinv).mod(p); + + // c2 = 1 / K^2 = (K^2)^(-1) + final BigInteger K2inv = Kinv.multiply(Kinv).mod(p); + this.c2 = K2inv; + } + + /** + * Processes the given input value to map it to an elliptic curve point using the Elligator 2 + * algorithm, optimized for Montgomery curves. This implementation adheres to the specifications outlined + * in RFC 9380, section 6.7.1, and section F.3 for efficient computation. + * + * @param u the input value to be mapped to a point on the elliptic curve + * @return the computed point on the elliptic curve represented as an ECPoint + */ + @Override + public ECPoint process(final BigInteger u) { + + // map_to_curve_elligator2(u) + + BigInteger tv1 = u.multiply(u).mod(p); // tv1 = u^2 + tv1 = z.multiply(tv1).mod(p); // tv1 = Z * u^2 + + // e1 = (tv1 == -1) + final BigInteger minusOne = p.subtract(BigInteger.ONE); + final boolean e1 = tv1.equals(minusOne); + + // if tv1 == -1 then tv1 = 0 + tv1 = H2cUtils.cmov(tv1, BigInteger.ZERO, e1); + + BigInteger x1 = tv1.add(BigInteger.ONE).mod(p); // x1 = 1 + tv1 + x1 = H2cUtils.inv0(x1, p); // x1 = inv0(x1) + x1 = x1.multiply(c1).negate().mod(p); // x1 = -c1 * x1 + + // gx1 = x1^3 + (J / K)*x1^2 + x1 / K^2 + BigInteger gx1 = x1.add(c1).mod(p); // gx1 = x1 + c1 + gx1 = gx1.multiply(x1).mod(p); // gx1 = (x1 + c1)*x1 + gx1 = gx1.add(c2).mod(p); // gx1 = gx1 + c2 + gx1 = gx1.multiply(x1).mod(p); // gx1 = gx1 * x1 + + BigInteger x2 = x1.negate().subtract(c1).mod(p); // x2 = -x1 - c1 + BigInteger gx2 = tv1.multiply(gx1).mod(p); // gx2 = tv1 * gx1 + + // e2 = is_square(gx1) + final boolean e2 = H2cUtils.isSquare(gx1, p); + + // x = e2 ? x1 : x2 + BigInteger x = H2cUtils.cmov(x2, x1, e2); + + // y2 = e2 ? gx1 : gx2 + BigInteger y2 = H2cUtils.cmov(gx2, gx1, e2); + + // y = sqrt(y2) + BigInteger y = H2cUtils.sqrt(y2, p); + + // e3 = (sgn0(y) == 1) + final boolean e3 = H2cUtils.sgn0(y, curve) == 1; + + // y = CMOV(y, -y, e2 XOR e3) + final boolean flip = e2 ^ e3; + final BigInteger yNeg = y.negate().mod(p); + y = H2cUtils.cmov(y, yNeg, flip); + + // s = x * K + // t = y * K + BigInteger s = x.multiply(K).mod(p); + BigInteger t = y.multiply(K).mod(p); + + return this.curve.createPoint(s, t); + } + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/GenericSqrtRatioCalculator.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/GenericSqrtRatioCalculator.java new file mode 100644 index 0000000000..3724db7501 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/GenericSqrtRatioCalculator.java @@ -0,0 +1,106 @@ +package org.bouncycastle.crypto.hash2curve.impl; + + +import org.bouncycastle.crypto.hash2curve.H2cUtils; +import org.bouncycastle.crypto.hash2curve.SqrtRatioCalculator; +import org.bouncycastle.math.ec.ECCurve; + +import java.math.BigInteger; + +/** + * Generic implementation of the sqrt_ratio(u, v) operation defined in RFC 9380. + * + *

This computes a square root of u/v in the prime field Fp associated with an + * elliptic curve, when such a square root exists, and otherwise returns a valid + * square root of z·u/v for a fixed quadratic non-residue z. This function is a + * required component of all map-to-curve constructions in RFC 9380, including + * the Simplified SWU and Elligator 2 maps.

+ * + *

RFC 9380 defines optimized sqrt_ratio formulas for certain curves where + * the field prime p satisfies special congruences (e.g. p ≡ 3 mod 4 or p ≡ 5 mod 8). + * However, those optimizations are curve-specific and do not apply to all hash-to-curve + * suites. This implementation instead follows the fully generic algorithm from + * Section 5.6.3 of RFC 9380, which is valid for any elliptic curve defined over a + * prime field Fp.

+ * + *

This generic version supports all curves used in the RFC 9830 test vectors, + * including the NIST P-256 / P-384 / P-521 curves, Curve25519, Edwards25519 + * (Ristretto255), Curve448, and Edwards448 (Decaf448). It provides a single uniform + * implementation suitable for all supported hash-to-curve suites.

+ */ +public class GenericSqrtRatioCalculator implements SqrtRatioCalculator { + + /** The elliptic curve for the instance */ + private final ECCurve curve; + /** A non-square element of F */ + private final BigInteger z; + + private final BigInteger q; + + private final int c1; + private final BigInteger c2, c3, c4, c5, c6, c7; + + /** + * Constructs a {@code GenericSqrtRatioCalculator} instance with the specified elliptic curve and a given value z. + * + * @param curve the elliptic curve over a finite field to be used for square root and ratio calculations + * @param z a non-square element of F + */ + public GenericSqrtRatioCalculator(final ECCurve curve, final BigInteger z) { + this.curve = curve; + this.q = curve.getField().getCharacteristic(); + this.z = z; + this.c1 = this.calculateC1(); + + this.c2 = this.q.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2).pow(this.c1)); + this.c3 = this.c2.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + this.c4 = BigInteger.valueOf(2).pow(this.c1).subtract(BigInteger.ONE); + this.c5 = BigInteger.valueOf(2).pow(this.c1 - 1); + this.c6 = z.modPow(this.c2, this.q); + this.c7 = z.modPow(this.c2.add(BigInteger.ONE).divide(BigInteger.valueOf(2)), q); + } + + private int calculateC1() { + BigInteger qMinusOne = this.q.subtract(BigInteger.ONE); + int c1 = 0; + while (qMinusOne.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) { + qMinusOne = qMinusOne.divide(BigInteger.valueOf(2)); + c1++; + } + return c1; + } + + /** {@inheritDoc} */ + @Override + public SqrtRatio sqrtRatio(final BigInteger u, final BigInteger v) { + + BigInteger tv1 = this.c6; + BigInteger tv2 = v.modPow(this.c4, this.q); + BigInteger tv3 = tv2.modPow(BigInteger.valueOf(2), this.q); + tv3 = tv3.multiply(v).mod(this.q); + BigInteger tv5 = u.multiply(tv3).mod(this.q); + tv5 = tv5.modPow(this.c3, this.q); + tv5 = tv5.multiply(tv2).mod(this.q); + tv2 = tv5.multiply(v).mod(this.q); + tv3 = tv5.multiply(u).mod(this.q); + BigInteger tv4 = tv3.multiply(tv2).mod(this.q); + tv5 = tv4.modPow(this.c5, this.q); + final boolean isQR = tv5.equals(BigInteger.ONE); + tv2 = tv3.multiply(this.c7).mod(this.q); + tv5 = tv4.multiply(tv1).mod(this.q); + tv3 = H2cUtils.cmov(tv2, tv3, isQR); + tv4 = H2cUtils.cmov(tv5, tv4, isQR); + for (int i = this.c1; i >= 2; i--) { + tv5 = BigInteger.valueOf(i - 2); + tv5 = BigInteger.valueOf(2).pow(tv5.intValue()); + tv5 = tv4.modPow(tv5, this.q); + final boolean e1 = tv5.equals(BigInteger.ONE); + tv2 = tv3.multiply(tv1).mod(this.q); + tv1 = tv1.multiply(tv1).mod(this.q); + tv5 = tv4.multiply(tv1).mod(this.q); + tv3 = H2cUtils.cmov(tv2, tv3, e1); + tv4 = H2cUtils.cmov(tv5, tv4, e1); + } + return new SqrtRatio(isQR, tv3); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/MontgomeryCurveProcessor.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/MontgomeryCurveProcessor.java new file mode 100644 index 0000000000..b624f4abb9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/MontgomeryCurveProcessor.java @@ -0,0 +1,197 @@ +package org.bouncycastle.crypto.hash2curve.impl; + +import org.bouncycastle.crypto.hash2curve.CurveProcessor; +import org.bouncycastle.crypto.hash2curve.data.AffineXY; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +/** + Curve processor for Montgomery curves of the form + B * y^2 = x^3 + A * x^2 + x + + Internally we treat this as a long Weierstrass curve + y^2 = x^3 + a2 * x^2 + a4 * x + a6 + with + a2 = A / B, a4 = 1 / B, a6 = 0. + All arithmetic is done explicitly in F_p using these formulas, + not via the ECPoint group operations, because BouncyCastle's + Montgomery implementation does not use this model directly. + */ +public class MontgomeryCurveProcessor implements CurveProcessor { + + /** The elliptic curve for the instance */ + private final ECCurve curve; + /** The curve field characteristic */ + private final BigInteger p; + + // Weierstrass-style coefficients derived from Montgomery (A, B) + private final BigInteger a2; // = A / B mod p + private final BigInteger a4; // = 1 / B mod p + private final BigInteger a6; // = 0 + + // Effective cofactor h_eff (e.g. 8 for curve25519_XMD:SHA-512_ELL2_RO_) + private final BigInteger hEff; + private final int J; + private final int K; + + /** + * Constructs a MontgomeryCurveProcessor object for processing elliptic curves + * represented in the Montgomery model. Computes and initializes curve parameters + * for use in point operations and transformations. + * + * @param curve the elliptic curve to be processed, represented using the ECCurve class + * @param J parameter J of the Montgomery curve equation, used for internal calculations + * @param K parameter K of the Montgomery curve equation, used for internal calculations + * @param hEff the effective cofactor value for the curve, utilized in certain operations + */ + public MontgomeryCurveProcessor(ECCurve curve, + int J, + int K, + int hEff) { + this.J = J; + this.K = K; + this.curve = curve; + this.p = curve.getField().getCharacteristic(); + BigInteger Binv = BigInteger.valueOf(K).modInverse(p); + this.a2 = BigInteger.valueOf(J).multiply(Binv).mod(p); // A/B + this.a4 = Binv; + this.a6 = BigInteger.ZERO; + this.hEff = BigInteger.valueOf(hEff); + } + + /** + * Adds two elliptic curve points on the Montgomery curve model and returns the resulting point. + * The method internally converts Montgomery coordinates to Weierstrass coordinates + * to perform the group law, then converts the result back to Montgomery coordinates. + * + * @param P the first elliptic curve point on the Montgomery curve model + * @param Q the second elliptic curve point on the Montgomery curve model + * @return the resulting elliptic curve point on the Montgomery curve model after addition + */ + @Override + public ECPoint add(final ECPoint P, final ECPoint Q) { + // Convert Montgomery-coded inputs to real Weierstrass ECPoints + final ECPoint Pw = Fmtow(P).toPoint(curve); + final ECPoint Qw = Fmtow(Q).toPoint(curve); + + // Do group law using BC's Weierstrass implementation + final ECPoint Rw = Pw.add(Qw).normalize(); + + // Convert back to Montgomery coordinates, then pack into an ECPoint carrier + return Fwtom(Rw).toPoint(curve); + } + + /** + * Clears the cofactor of the given elliptic curve point using the efficient cofactor value. + * If the input point is at infinity, the same point is returned. Otherwise, it transforms + * the point into the short-Weierstrass model, multiplies by the effective cofactor, and + * normalizes the resulting point. + * + * @param P the elliptic curve point on the Montgomery curve model + * @return the resulting elliptic curve point in the short-Weierstrass model with the cofactor cleared + */ + @Override + public ECPoint clearCofactor(final ECPoint P) { + if (P.isInfinity()) { + return P; + } + final ECPoint Pw = Fmtow(P).toPoint(curve); + return Pw.multiply(hEff).normalize(); + } + + @Override + public AffineXY mapToAffineXY(final ECPoint p) { + return Fwtom(p.normalize()); + } + + /** + * Convert Montgomery-model coordinates (xM, yM) to the corresponding + * short-Weierstrass coordinates (xW, yW) using the standard change of variables: + * + * xW = xM + A/3 + * yW = yM / K + * + * where A = J/K (mod p) and B = 1/K^2 (so sqrt(B) = 1/K exists). + * + * IMPORTANT: This returns coordinates only. It does NOT create a BC ECPoint. + */ + private AffineXY Fmtow(final BigInteger xM, final BigInteger yM) { + final BigInteger inv3 = BigInteger.valueOf(3).modInverse(p); + + // A = J/K + final BigInteger A = BigInteger.valueOf(J).mod(p) + .multiply(BigInteger.valueOf(K).mod(p).modInverse(p)) + .mod(p); + + // xW = xM + A/3 + final BigInteger xW = xM.mod(p).add(A.multiply(inv3).mod(p)).mod(p); + + // yW = yM / K + final BigInteger invK = BigInteger.valueOf(K).mod(p).modInverse(p); + final BigInteger yW = yM.mod(p).multiply(invK).mod(p); + + return new AffineXY(xW, yW); + } + + /** + * Convert short-Weierstrass coordinates (xW, yW) to Montgomery-model coordinates (xM, yM): + * + * xM = xW - A/3 + * yM = yW * K + * + * IMPORTANT: This returns coordinates only. It does NOT create a BC ECPoint. + */ + private AffineXY Fwtom(final BigInteger xW, final BigInteger yW) { + final BigInteger inv3 = BigInteger.valueOf(3).modInverse(p); + + // A = J/K + final BigInteger A = BigInteger.valueOf(J).mod(p) + .multiply(BigInteger.valueOf(K).mod(p).modInverse(p)) + .mod(p); + + // xM = xW - A/3 + final BigInteger xM = xW.mod(p).subtract(A.multiply(inv3).mod(p)).mod(p); + + // yM = yW * K + final BigInteger yM = yW.mod(p).multiply(BigInteger.valueOf(K).mod(p)).mod(p); + + return new AffineXY(xM, yM); + } + + /** + * Converts the given elliptic curve point from its Montgomery-model representation + * to the corresponding short-Weierstrass affine coordinates. If the input point is + * at infinity, it returns coordinates (0, 0). Otherwise, the point is normalized + * before extracting and transforming its affine coordinates. + * + * @param Pm the elliptic curve point on the Montgomery model to be converted + * @return the affine coordinates in the short-Weierstrass representation + */ + private AffineXY Fmtow(final ECPoint Pm) { + if (Pm.isInfinity()) { + return new AffineXY(BigInteger.ZERO, BigInteger.ZERO); + } + final ECPoint Pn = Pm.normalize(); + return Fmtow(Pn.getAffineXCoord().toBigInteger(), Pn.getAffineYCoord().toBigInteger()); + } + + /** + * Converts the given elliptic curve point from its short-Weierstrass affine coordinates + * to the corresponding Montgomery-model representation. If the point is at infinity, + * it returns coordinates (0, 0). Otherwise, the point is normalized before extracting + * and transforming its affine coordinates. + * + * @param Pw the elliptic curve point in the short-Weierstrass representation to be converted + * @return the affine coordinates in the Montgomery-model representation + */ + private AffineXY Fwtom(final ECPoint Pw) { + if (Pw.isInfinity()) { + return new AffineXY(BigInteger.ZERO, BigInteger.ZERO); + } + final ECPoint Pn = Pw.normalize(); + return Fwtom(Pn.getAffineXCoord().toBigInteger(), Pn.getAffineYCoord().toBigInteger()); + } + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/NistCurveProcessor.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/NistCurveProcessor.java new file mode 100644 index 0000000000..f574cfd913 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/NistCurveProcessor.java @@ -0,0 +1,52 @@ +package org.bouncycastle.crypto.hash2curve.impl; + +import org.bouncycastle.crypto.hash2curve.CurveProcessor; +import org.bouncycastle.crypto.hash2curve.data.AffineXY; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +/** + * Curve processor for NIST curves (P-256, P-384, P-521) where the cofactor is 1. + *

+ * Although the cofactor is 1 for all NIST curves, RFC 9380 still requires the + * "clear_cofactor" step for consistency. In Bouncy Castle, invoking + * {@code ECPoint.multiply(BigInteger.ONE)} is not a trivial no-op: it forces + * normalization of the internal point representation and ensures that the + * returned point is in canonical affine form. + *

+ * This normalization step is required for correct alignment with the + * specification and for matching the published test vectors. Returning the + * input point directly (without normalization) may leave the point in a + * projective or mixed representation, which causes test vector comparisons + * to fail even though the mathematical value of the point is the same. + */ +public class NistCurveProcessor implements CurveProcessor { + + /** + * Constructs a new instance of NistCurveProcessor. + * This class processes elliptic curve operations for NIST curves (P-256, P-384, P-521) + * with a cofactor of 1. It ensures compliance with RFC 9380 by performing required normalization + * steps, such as the "clear_cofactor" operation, to align the elliptic curve points with their + * canonical affine form and match published test vectors. + */ + public NistCurveProcessor() { + } + + /** {@inheritDoc} */ + @Override + public ECPoint add(final ECPoint p, final ECPoint q) { + return p.add(q); + } + + /** {@inheritDoc} */ + @Override + public ECPoint clearCofactor(final ECPoint ecPoint) { + return ecPoint.multiply(BigInteger.ONE); + } + + @Override + public AffineXY mapToAffineXY(final ECPoint p) { + return new AffineXY(p); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/SimplifiedShallueVanDeWoestijneMapToCurve.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/SimplifiedShallueVanDeWoestijneMapToCurve.java new file mode 100644 index 0000000000..71aa392652 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/SimplifiedShallueVanDeWoestijneMapToCurve.java @@ -0,0 +1,84 @@ +package org.bouncycastle.crypto.hash2curve.impl; + +import org.bouncycastle.crypto.hash2curve.H2cUtils; +import org.bouncycastle.crypto.hash2curve.MapToCurve; +import org.bouncycastle.crypto.hash2curve.SqrtRatioCalculator; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +/** + * Implements the Simplified Shallue van de Woestijne Map to curve according to section 6.6.2 of RFC 9380 This is the + * straight-line implementation optimized for Weierstrass curves as defined in section F.2. + */ +public class SimplifiedShallueVanDeWoestijneMapToCurve implements MapToCurve { + + private final ECCurve curve; + private final BigInteger z; + + private final SqrtRatioCalculator sqrtRatioCalculator; + + /** + * Constructs an instance of the SimplifiedShallueVanDeWoestijneMapToCurve mapping mechanism for mapping values + * onto a Weierstrass elliptic curve. This implementation is based on section 6.6.2 of RFC 9380 and optimizations + * defined in section F.2. + * + * @param curve the elliptic curve to which the mapping will be applied; must conform to the Weierstrass form + * @param z a non-zero constant value used as a parameter in the mapping algorithm + */ + public SimplifiedShallueVanDeWoestijneMapToCurve(final ECCurve curve, final BigInteger z) { + this.curve = curve; + this.z = z; + this.sqrtRatioCalculator = new GenericSqrtRatioCalculator(curve, z); + } + + /** + * Processes the given input value to map it to an elliptic curve point using the Shallue-van de Woestijne + * algorithm, optimized for Weierstrass curves. This implementation adheres to the specifications outlined + * in RFC 9380, section 6.6.2, and section F.2 for efficient computation. + *

+ * The method computes the x and y coordinates for the point on the elliptic curve, using modular arithmetic + * and auxiliary functions for square root computation and conditional assignments. + * + * @param u the input value to be mapped to a point on the elliptic curve + * @return the computed point on the elliptic curve represented as an ECPoint + */ + @Override + public ECPoint process(final BigInteger u) { + + final BigInteger A = this.curve.getA().toBigInteger(); + final BigInteger B = this.curve.getB().toBigInteger(); + final BigInteger p = this.curve.getField().getCharacteristic(); + + BigInteger tv1 = u.modPow(BigInteger.valueOf(2), p); + tv1 = this.z.multiply(tv1).mod(p); + BigInteger tv2 = tv1.modPow(BigInteger.valueOf(2), p); + tv2 = tv2.add(tv1).mod(p); + BigInteger tv3 = tv2.add(BigInteger.ONE).mod(p); + tv3 = B.multiply(tv3).mod(p); + BigInteger tv4 = H2cUtils.cmov(this.z, tv2.negate(), !tv2.equals(BigInteger.ZERO)); + tv4 = A.multiply(tv4).mod(p); + tv2 = tv3.modPow(BigInteger.valueOf(2), p); + BigInteger tv6 = tv4.modPow(BigInteger.valueOf(2), p); + BigInteger tv5 = A.multiply(tv6).mod(p); + tv2 = tv2.add(tv5).mod(p); + tv2 = tv2.multiply(tv3).mod(p); + tv6 = tv6.multiply(tv4).mod(p); + tv5 = B.multiply(tv6).mod(p); + tv2 = tv2.add(tv5).mod(p); + BigInteger x = tv1.multiply(tv3).mod(p); + final SqrtRatio sqrtRatio = this.sqrtRatioCalculator.sqrtRatio(tv2, tv6); + final boolean isGx1Square = sqrtRatio.isQR(); + final BigInteger y1 = sqrtRatio.getRatio(); + BigInteger y = tv1.multiply(u).mod(p); + y = y.multiply(y1).mod(p); + x = H2cUtils.cmov(x, tv3, isGx1Square); + y = H2cUtils.cmov(y, y1, isGx1Square); + final boolean e1 = H2cUtils.sgn0(u, this.curve) == H2cUtils.sgn0(y, this.curve); + y = H2cUtils.cmov(y.negate(), y, e1).mod(p); + x = x.multiply(tv4.modPow(BigInteger.ONE.negate(), p)).mod(p); + return this.curve.createPoint(x, y); + } + +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/SqrtRatio.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/SqrtRatio.java new file mode 100644 index 0000000000..92a88ea688 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/SqrtRatio.java @@ -0,0 +1,52 @@ +package org.bouncycastle.crypto.hash2curve.impl; + +import java.math.BigInteger; + +/** + * The result of a sqrt_ration calculation + */ +public class SqrtRatio{ + + /** + * A boolean flag indicating whether the computed value is a quadratic residue (QR) + * modulo a specific field. In the context of square root calculations or related + * operations, this variable helps distinguish cases where the ratio under consideration + * has a valid square root (is a QR) or not. + */ + private final boolean isQR; + /** + * Represents the ratio value resulting from the square root ratio computation. + */ + private final BigInteger ratio; + + /** + * Constructs an instance of SqrtRatio representing the result of a square root ratio computation. + * + * @param isQR A boolean flag indicating whether the computed value is a quadratic residue (QR) + * modulo a specific field. This helps determine if the ratio under consideration + * has a valid square root. + * @param ratio The ratio value resulting from the square root ratio computation. + */ + protected SqrtRatio(final boolean isQR, final BigInteger ratio) { + this.isQR = isQR; + this.ratio = ratio; + } + + /** + * Checks whether the computed value is a quadratic residue (QR) modulo a specific field. + * + * @return true if the computed value is a quadratic residue (QR); false otherwise. + */ + public boolean isQR() { + return isQR; + } + + /** + * Retrieves the ratio value resulting from the square root ratio computation. + * + * @return the ratio value as a BigInteger. + */ + public BigInteger getRatio() { + return ratio; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/XmdMessageExpansion.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/XmdMessageExpansion.java new file mode 100644 index 0000000000..e726609244 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/impl/XmdMessageExpansion.java @@ -0,0 +1,151 @@ +package org.bouncycastle.crypto.hash2curve.impl; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA3Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.hash2curve.H2cUtils; +import org.bouncycastle.crypto.hash2curve.MessageExpansion; +import org.bouncycastle.crypto.util.DigestFactory; +import org.bouncycastle.util.Arrays; + +/** + * XmdMessageExpansion is an implementation of the MessageExpansion interface, used to expand a given message to a + * specified length in bytes while following cryptographic domain separation principles. The implementation uses a + * selected hash function to achieve the expansion. + */ +public class XmdMessageExpansion implements MessageExpansion { + + /** The Digest function for this instance */ + private final Digest digest; + + /** The input block size of the selected hash algorithm */ + private final int s; + + /** The size in bytes of hash outputs */ + private final int hashOutputBytes; + + /** + * Constructs an XmdMessageExpansion instance capable of performing cryptographic + * message expansion using the specified digest algorithm, security parameter, + * and custom input block size parameter. The security of the curve's operations + * is validated against the output size of the digest algorithm. + * + * @param digest the cryptographic digest algorithm to be used + * @param k the security parameter defining the required minimum security strength, in bits + * @param s the input block size parameter for the cryptographic digest algorithm + * @throws IllegalArgumentException if the hash output size is too small for the specified security level + */ + public XmdMessageExpansion(final Digest digest, final int k, final int s) { + this.digest = digest; + this.s = s; + this.hashOutputBytes = digest.getDigestSize(); + if (this.hashOutputBytes < (int) Math.ceil((double) (k * 2) / 8)) { + throw new IllegalArgumentException("Hash output size is too small for the security level of the curve"); + } + } + + /** + * Constructs an XmdMessageExpansion instance with the given digest algorithm and security parameter. + * + * @param digest the cryptographic digest algorithm to be used + * @param k the security parameter defining the required minimum security strength + */ + public XmdMessageExpansion(final Digest digest, final int k) { + this(digest, k, getInputBlockSize(digest)); + } + + /** + * Determines the input block size for a given cryptographic digest algorithm. + * + * @param digest the cryptographic digest algorithm whose input block size is to be determined + * @return the input block size in bits for the provided digest algorithm + * @throws IllegalArgumentException if the provided digest algorithm is not supported or has an illegal configuration + */ + private static int getInputBlockSize(final Digest digest) { + if (digest instanceof SHA256Digest) { + return 512; + } + if (digest instanceof SHA384Digest) { + return 1024; + } + if (digest instanceof SHA512Digest) { + return 1024; + } + if (digest instanceof SHA3Digest) { + final SHA3Digest sha3Digest = (SHA3Digest) digest; + switch (sha3Digest.getDigestSize()) { + case 224: + return 1152; + case 256: + return 1088; + case 384: + return 832; + case 512: + return 576; + default: + throw new IllegalArgumentException("Illegal SHA3 digest size"); + } + } + throw new IllegalArgumentException("Unsupported digest algorithm"); + } + + /** + * Expands a given input message to a fixed-length output, using a cryptographic digest and + * additional parameters such as domain separation tag (DST) and desired output length. + * This method is compliant with hash-to-curve message expansion defined in certain cryptographic + * algorithms and standards. + * + * @param msg the input message to be expanded + * @param dst the domain separation tag used to isolate cryptographic domains + * @param lenInBytes the desired byte-length of the output message + * @return the byte array resulting from the message expansion process + * @throws IllegalArgumentException if ell exceeds 255, lenInBytes exceeds 65535, + * or dst length is greater than 255 + */ + @Override + public byte[] expandMessage(final byte[] msg, final byte[] dst, final int lenInBytes) { + final int ell = (int) Math.ceil((double) lenInBytes / this.hashOutputBytes); + if (ell > 255) { + throw new IllegalArgumentException("Ell parameter must not be greater than 255. Current value = " + ell); + } + if (lenInBytes > 65535) { + throw new IllegalArgumentException("Output size must not be greater than 65535. Current value = " + lenInBytes); + } + if (dst.length > 255) { + throw new IllegalArgumentException("DST size must not be greater than 255. Current value = " + dst.length); + } + final byte[] dstPrime = Arrays.concatenate(dst, H2cUtils.i2osp(dst.length, 1)); + final byte[] zPad = H2cUtils.i2osp(0, this.s / 8); + final byte[] libStr = H2cUtils.i2osp(lenInBytes, 2); + final byte[] msgPrime = Arrays.concatenate(new byte[][] { zPad, msg, libStr, H2cUtils.i2osp(0, 1), dstPrime }); + final byte[][] b = new byte[ell + 1][this.hashOutputBytes]; + b[0] = this.hash(msgPrime); + b[1] = this.hash(Arrays.concatenate(b[0], H2cUtils.i2osp(1, 1), dstPrime)); + byte[] uniformBytes = Arrays.clone(b[1]); + for (int i = 2; i <= ell; i++) { + b[i] = this.hash(Arrays.concatenate( + H2cUtils.xor(b[0], b[i - 1]), + H2cUtils.i2osp(i, 1), + dstPrime + )); + uniformBytes = Arrays.concatenate(uniformBytes, b[i]); + } + return Arrays.copyOfRange(uniformBytes, 0, lenInBytes); + } + + /** + * Calculates a hash over a message + * + * @param message message + * @return hash value + */ + private byte[] hash(final byte[] message) { + final Digest digestInstance = DigestFactory.cloneDigest(this.digest); + digestInstance.update(message, 0, message.length); + final byte[] hashResult = new byte[this.digest.getDigestSize()]; + digestInstance.doFinal(hashResult, 0); + return hashResult; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/hash2curve/package-info.java b/core/src/main/java/org/bouncycastle/crypto/hash2curve/package-info.java new file mode 100644 index 0000000000..279847217d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/hash2curve/package-info.java @@ -0,0 +1,4 @@ +/** + * Hash to curve implementation + */ +package org.bouncycastle.crypto.hash2curve; diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/AllTests.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/AllTests.java new file mode 100644 index 0000000000..be7967f81d --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/AllTests.java @@ -0,0 +1,52 @@ +package org.bouncycastle.crypto.hash2curve.test; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.bouncycastle.crypto.hash2curve.test.impl.GenericSqrtRatioCalculatorTest; +import org.bouncycastle.crypto.hash2curve.test.impl.SimplifiedShallueVanDeWoestijneMapToCurveTest; +import org.bouncycastle.test.PrintTestResult; + +public class AllTests + extends TestCase +{ + public static void main(String[] args) + { + PrintTestResult.printResult( junit.textui.TestRunner.run(suite())); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("Hash2Curve Tests"); + + suite.addTestSuite(HashToFieldTest.class); + suite.addTestSuite(OPRFHashToScalarTest.class); + suite.addTestSuite(GenericSqrtRatioCalculatorTest.class); + + suite.addTestSuite(SimplifiedShallueVanDeWoestijneMapToCurveTest.class); + suite.addTestSuite(H2cUtilsTest.class); + suite.addTestSuite(HashToEllipticCurveTest.class); + + return new BCTestSetup(suite); + } + + static class BCTestSetup + extends TestSetup + { + public BCTestSetup(Test test) + { + super(test); + } + + protected void setUp() + { + + } + + protected void tearDown() + { + + } + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/H2cUtilsTest.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/H2cUtilsTest.java new file mode 100644 index 0000000000..1ddc65f22d --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/H2cUtilsTest.java @@ -0,0 +1,73 @@ +package org.bouncycastle.crypto.hash2curve.test; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.hash2curve.H2cUtils; +import org.bouncycastle.crypto.hash2curve.OPRFHashToScalar; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + + +/** + * Testing hash 2 curve utility functions + */ +public class H2cUtilsTest extends TestCase { + + static ECCurve p256Curve = new SecP256R1Curve(); + static OPRFHashToScalar hashToScalar = new OPRFHashToScalar(p256Curve, new SHA256Digest(), 48); + + public void testIsSquare() throws Exception { + + List smallerXValues = new ArrayList<>(); + smallerXValues.add("4fe14bb3946e9c23a1cacb43de358e45a9931786067278f6ae3315c216e39a0"); + smallerXValues.add("d1d12dd2a682259a5dc0da4b79734d4ab6d435c85c8c980e03f8297611e18937"); + smallerXValues.add("497e89c30c3ed11d291aafcefc02be894f4d87cb29467fa0457b9c02366239d8"); + smallerXValues.add("d1359226395e08d382cc7528b4ff8ed7f7ed991783fe0eb0f9a3ef2449fb1079"); + smallerXValues.add("26d12894c6600f99a3ee553a2c339c33058c09f2b7ed184ae9577a0423a9cdf3"); + smallerXValues.add("5f4edc4e4f1f5dc6eb218bf0791cb80dc264e1d0c2dfcd1cbd00f3b969bcaa56"); + smallerXValues.add("e87cfbe1079f777ff54c82b3bef8edb4dba40762c4c12715952195bc4c146030"); + smallerXValues.add("ed1c985837abfb9317126e52849880155a3e70316ac7c4d7ce343024e975b3f5"); + smallerXValues.add("d7e6c6967d58188bf24bd7aaa04747ab1237725f23eaa47c0e3206f8b4a3c5f5"); + smallerXValues.add("163f11e2d45d62ed5d4f4503f8fd095a2c292e27554cf859f436332bc3ce6bbe"); + + boolean[] expectedValues = new boolean[] { true, false, false, true, true, false, false, false, true, false }; + + //log.info("P256 curve order: {}", p256Spec.getCurve().getOrder().toString(16)); + + for (int i = 0; i < 10; i++) { + BigInteger x = hashToScalar.process(String.valueOf(i).getBytes(), "DST".getBytes()); + boolean square = H2cUtils.isSquare(x, p256Curve.getOrder()); + //log.info("Integer {} square in p256 order: {}", x.toString(16), square); + assertEquals(expectedValues[i], square); + } + } + + public void testSqrt() throws Exception { + + String[] expectedValues = { + "323f7ed2e7c1bd98c010e4f7682e424fd7434feeca6a39ad7f80f3dea00eb18d", + "1e5f775dc6b369930f58df140498358437461c96cb2857c489c346e3927b6a83", + "56af41b8f8b6f29f556d1d4471f763a7429d5032fde2156d93d50273858453da", + "2e1d7226dfcd493860543685107d79a684c11c635cec44b0ed1db566cb3c48d2", + "92bbc6e0dc62c4f3488cb336c911c75108bddbcd60ad7a2ad7f62f07ecf5ddd8", + "3f32018e0754b2e744ecd06c9b77e7de171f07e6ad6daf6e914e94108db91073", + "82353b2f3c9505d15429d6a4d5dd4231c3d116e7300efb39f1deca18164bddf6", + "3afc13643cc49fb989bd18bde7c2ac2332a99381f3f6081293346e1595fca93d", + "e4244d900f35a71f23ed02dff6c2bc22f11ca4ebb8dd51e0fcaefd0bd7caeed4", + "b3ed944452119b21901b25b211c0a5d2f9b40384269c77f488064c9503296bd0" + }; + + for (int i = 0; i < 10; i++) { + BigInteger x = hashToScalar.process(String.valueOf(i).getBytes(), "DST".getBytes()); + BigInteger sqrt = H2cUtils.sqrt(x, p256Curve.getOrder()); + //log.info("Integer {} sqrt in p256 order: {}", x.toString(16), sqrt.toString(16)); + assertEquals(expectedValues[i], sqrt.toString(16)); + } + + } + +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/HashToEllipticCurveTest.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/HashToEllipticCurveTest.java new file mode 100644 index 0000000000..79a5066207 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/HashToEllipticCurveTest.java @@ -0,0 +1,116 @@ +package org.bouncycastle.crypto.hash2curve.test; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.hash2curve.HashToCurveProfile; +import org.bouncycastle.crypto.hash2curve.HashToEllipticCurve; +import org.bouncycastle.crypto.hash2curve.data.AffineXY; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + + +/** + * Test suite for HashToEllipticCurve class. + */ +public class HashToEllipticCurveTest extends TestCase { + + + public void testTestVectors() throws Exception { + + List profileList = new ArrayList<>(); + profileList.add(HashToCurveProfile.P256_XMD_SHA_256); + profileList.add(HashToCurveProfile.P384_XMD_SHA_384); + profileList.add(HashToCurveProfile.P521_XMD_SHA_512); + profileList.add(HashToCurveProfile.CURVE25519W_XMD_SHA_512_ELL2); + + for (HashToCurveProfile profile : profileList) { + performTestOnSpecificCurveProfile(profile); + } + } + + private void performTestOnSpecificCurveProfile(HashToCurveProfile profile) throws Exception { + + List testVectorList = new ArrayList<>(); + switch (profile) { + case P256_XMD_SHA_256: + testVectorList.add(TestVectors.P256_HTC_TEST_VECTOR_DATA); + testVectorList.add(TestVectors.P256_ETC_TEST_VECTOR_DATA); + break; + case P384_XMD_SHA_384: + testVectorList.add(TestVectors.P384_HTC_TEST_VECTOR_DATA); + testVectorList.add(TestVectors.P384_ETC_TEST_VECTOR_DATA); + break; + case P521_XMD_SHA_512: + testVectorList.add(TestVectors.P521_HTC_TEST_VECTOR_DATA); + testVectorList.add(TestVectors.P521_ETC_TEST_VECTOR_DATA); + break; + case CURVE25519W_XMD_SHA_512_ELL2: + testVectorList.add(TestVectors.curve25519_HTC_TEST_VECTOR_DATA); + testVectorList.add(TestVectors.curve25519_ETC_TEST_VECTOR_DATA); + break; + default: + throw new IllegalArgumentException("Unsupported profile: " + profile); + } + + for (TestVectorData tvd : testVectorList) { + BigInteger Z = h2bi(tvd.getZ(), tvd.getField().getP()); + int L = h2bi(tvd.getL()).intValue(); + + assertEquals(Z, profile.getZ()); + assertEquals(L, profile.getL()); + + HashToEllipticCurve h2c = HashToEllipticCurve.getInstance(profile, tvd.getDst()); + + // Run individual vectors + List vectors = tvd.getVectors(); + for (TestVectorData.Vector vector : vectors) { + ECPoint point = execute(vector.getMsg(), h2c, + hexStrip(vector.getP().get("x")), hexStrip(vector.getP().get("y")), tvd.getCiphersuite().endsWith("NU_")); + compare(vector.getP().get("x"), vector.getP().get("y"), h2c.getAffineXY(point)); + } + } + + + } + + private void compare(String x, String y, AffineXY point) { + String resultX = point.getX().toString(16); + String resultY = point.getY().toString(16); + hexCompare(hexStrip(x), resultX); + hexCompare(hexStrip(y), resultY); + } + + private void hexCompare(String vectorVal, String resultVal) { + int startIndex = vectorVal.length() - resultVal.length(); + assertEquals(vectorVal.substring(startIndex), resultVal); + } + + public ECPoint execute(String msg, HashToEllipticCurve h2c, String px, String py, boolean encodeToCurve) throws Exception { + return encodeToCurve + ? h2c.encodeToCurve(msg.getBytes(StandardCharsets.UTF_8)) + : h2c.hashToCurve(msg.getBytes(StandardCharsets.UTF_8)); + } + + BigInteger h2bi(String hexStr) { + return new BigInteger(hexStrip(hexStr), 16); + } + + BigInteger h2bi(String hexStr, String hexOrder) { + BigInteger val = h2bi(hexStr); + BigInteger order = h2bi("00" + hexStrip(hexOrder)); + + BigInteger positive = val; + BigInteger negative = order.subtract(val); + BigInteger result = positive.compareTo(negative) > 0 ? negative.negate() : positive; + return result; + } + + private String hexStrip(String hexStr) { + return hexStr.startsWith("0x") || hexStr.startsWith("0X") + ? hexStr.substring(2) + : hexStr; + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/HashToFieldTest.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/HashToFieldTest.java new file mode 100644 index 0000000000..79e5216818 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/HashToFieldTest.java @@ -0,0 +1,32 @@ +package org.bouncycastle.crypto.hash2curve.test; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.hash2curve.MessageExpansion; +import org.bouncycastle.crypto.hash2curve.HashToField; +import org.bouncycastle.crypto.hash2curve.impl.XmdMessageExpansion; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; + +public class HashToFieldTest extends TestCase { + + private static final ECCurve curve; + private static final MessageExpansion messageExpansion; + + static { + curve = new SecP256R1Curve(); + messageExpansion = new XmdMessageExpansion(new SHA256Digest(), 128); + } + + public void testGenericHashToField() { + byte[] message = new byte[] {}; + byte[] dst = "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_".getBytes(StandardCharsets.UTF_8); + HashToField testInstance = new HashToField(dst, curve, messageExpansion, 48); + BigInteger[][] result = testInstance.process(message, 2); + assertEquals("78397231975818298121002851560982570386422970797899025056634496834376049971209", result[0][0].toString(10)); + assertEquals("63350503467990645741152390718511296452551165224812381424345334365447080831578", result[1][0].toString(10)); + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/OPRFHashToScalarTest.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/OPRFHashToScalarTest.java new file mode 100644 index 0000000000..968dd326d7 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/OPRFHashToScalarTest.java @@ -0,0 +1,36 @@ +package org.bouncycastle.crypto.hash2curve.test; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.hash2curve.MessageExpansion; +import org.bouncycastle.crypto.hash2curve.OPRFHashToScalar; +import org.bouncycastle.crypto.hash2curve.impl.XmdMessageExpansion; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; + +import java.math.BigInteger; + +/** + * Test HashToScalar + */ +public class OPRFHashToScalarTest extends TestCase { + + static ECCurve p256Curve = new SecP256R1Curve(); + static OPRFHashToScalar hashToScalar = new OPRFHashToScalar(p256Curve, new SHA256Digest(), 128); + + + + public void testHashToScalar() { + BigInteger scalar = hashToScalar.process("Hej".getBytes(), "DST".getBytes()); + String scalarHex = scalar.toString(16); + assertEquals("a46a5dedfc6254dd60375be2a7e88393de67fbfc1e49d6817c862d18f176409a", scalarHex); + } + + public void testMessageExpansion() { + MessageExpansion messageExpansion = new XmdMessageExpansion(new SHA256Digest(), 48); + byte[] expandMessage = messageExpansion.expandMessage("Hej".getBytes(), "DST".getBytes(), 48); + String emHex = new BigInteger(1, expandMessage).toString(16); + assertEquals("eecb2fbaa0d63c284f61462ab0ee60294486e55b860bf619c9dcb69aa49f72d436bc2a2a862a2f777ab53fc01e4bbeb2", emHex); + } + +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/TestVectorData.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/TestVectorData.java new file mode 100644 index 0000000000..235ac6542d --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/TestVectorData.java @@ -0,0 +1,235 @@ +package org.bouncycastle.crypto.hash2curve.test; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Test vector data + */ +public class TestVectorData { + + private String L; + private String Z; + private String ciphersuite; + private String curve; + private String dst; + private String expand; + private Field field; + private String hash; + private String k; + private Map map; + private boolean randomOracle; + private List vectors; + + private TestVectorData() { + this.map = new HashMap<>(); + this.vectors = new ArrayList<>(); + } + + public static Builder builder() { + return new Builder(); + } + + public String getCiphersuite() { + return ciphersuite; + } + + public String getCurve() { + return curve; + } + + public String getDst() { + return dst; + } + + public String getExpand() { + return expand; + } + + public Field getField() { + return field; + } + + public String getHash() { + return hash; + } + + public String getK() { + return k; + } + + public String getL() { + return L; + } + + public Map getMap() { + return map; + } + + public boolean isRandomOracle() { + return randomOracle; + } + + public List getVectors() { + return vectors; + } + + public String getZ() { + return Z; + } + + public static class Builder { + private final TestVectorData data; + + private Builder() { + this.data = new TestVectorData(); + } + public Builder L(final String L) { + this.data.L = L; + return this; + } + public Builder Z(final String Z) { + this.data.Z = Z; + return this; + } + public Builder ciphersuite(final String ciphersuite) { + this.data.ciphersuite = ciphersuite; + return this; + } + public Builder curve(final String curve) { + this.data.curve = curve; + return this; + } + public Builder dst(final String dst) { + this.data.dst = dst; + return this; + } + public Builder expand(final String expand) { + this.data.expand = expand; + return this; + } + public Builder field(final String m, final String p) { + this.data.field = new Field(m, p); + return this; + } + public Builder hash(final String hash) { + this.data.hash = hash; + return this; + } + public Builder k(final String k) { + this.data.k = k; + return this; + } + public Builder addMap(final String key, final String value) { + this.data.map.put(key, value); + return this; + } + public Builder randomOracle(final boolean randomOracle) { + this.data.randomOracle = randomOracle; + return this; + } + public Builder addVector(final Vector vector) { + this.data.vectors.add(vector); + return this; + } + public TestVectorData build() { + return this.data; + } + } + + public static class Field { + public Field(final String m, final String p) { + this.m = m; + this.p = p; + } + + private String m; + private String p; + + public String getM() { + return m; + } + + public String getP() { + return p; + } + } + + public static class Vector { + private Vector() { + this.P = new HashMap<>(); + this.Q0 = new HashMap<>(); + this.Q1 = new HashMap<>(); + this.u = new ArrayList<>(); + } + + private Map P; + private Map Q0; + private Map Q1; + private String msg; + private List u; + + public static Builder builder() { + return new Builder(); + } + + public String getMsg() { + return msg; + } + + public Map getP() { + return P; + } + + public Map getQ0() { + return Q0; + } + + public Map getQ1() { + return Q1; + } + + public List getU() { + return u; + } + + public static class Builder{ + private final Vector vector; + + private Builder() { + this.vector = new Vector(); + } + + public Builder msg(final String msg) { + this.vector.msg = msg; + return this; + } + + public Builder addU(final String u) { + this.vector.u.add(u); + return this; + } + public Builder addP(final String key, final String value) { + this.vector.P.put(key, value); + return this; + } + public Builder addQ0(final String key, final String value) { + this.vector.Q0.put(key, value); + return this; + } + + public Builder addQ1(final String key, final String value) { + this.vector.Q1.put(key, value); + return this; + } + + public Vector build() { + return this.vector; + } + } + + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/TestVectors.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/TestVectors.java new file mode 100644 index 0000000000..54d82abee4 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/TestVectors.java @@ -0,0 +1,961 @@ +package org.bouncycastle.crypto.hash2curve.test; + +/** + * Functions to obtain test vector data + */ +public class TestVectors { + + public static final TestVectorData P256_HTC_TEST_VECTOR_DATA; + public static final TestVectorData P256_ETC_TEST_VECTOR_DATA; + public static final TestVectorData P384_HTC_TEST_VECTOR_DATA; + public static final TestVectorData P384_ETC_TEST_VECTOR_DATA; + public static final TestVectorData P521_HTC_TEST_VECTOR_DATA; + public static final TestVectorData P521_ETC_TEST_VECTOR_DATA; + public static final TestVectorData curve25519_HTC_TEST_VECTOR_DATA; + public static final TestVectorData curve25519_ETC_TEST_VECTOR_DATA; + public static final TestVectorData curve448_TEST_VECTOR_DATA; + public static final TestVectorData edwards25519_TEST_VECTOR_DATA; + public static final TestVectorData edwards448_TEST_VECTOR_DATA; + + static { + P256_HTC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x30") + .Z("0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5") + .ciphersuite("P256_XMD:SHA-256_SSWU_RO_") + .curve("NIST P-256") + .dst("QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_") + .expand("XMD") + .field("0x1", + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff") + .hash("sha256") + .k("0x80") + .addMap("name", "SSWU") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4") + .addP("y", "0x8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9ab5c43e8415") + .addQ0("x", "0xab640a12220d3ff283510ff3f4b1953d09fad35795140b1c5d64f313967934d5") + .addQ0("y", "0xdccb558863804a881d4fff3455716c836cef230e5209594ddd33d85c565b19b1") + .addQ1("x", "0x51cce63c50d972a6e51c61334f0f4875c9ac1cd2d3238412f84e31da7d980ef5") + .addQ1("y", "0xb45d1a36d00ad90e5ec7840a60a4de411917fbe7c82c3949a6e699e5a1b66aac") + .addU("0xad5342c66a6dd0ff080df1da0ea1c04b96e0330dd89406465eeba11582515009") + .addU("0x8c0f1d43204bd6f6ea70ae8013070a1518b43873bcd850aafa0a9e220e2eea5a") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775dac4a3388a0f") + .addP("y", "0x5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71ffd424212e") + .addQ0("x", "0x5219ad0ddef3cc49b714145e91b2f7de6ce0a7a7dc7406c7726c7e373c58cb48") + .addQ0("y", "0x7950144e52d30acbec7b624c203b1996c99617d0b61c2442354301b191d93ecf") + .addQ1("x", "0x019b7cb4efcfeaf39f738fe638e31d375ad6837f58a852d032ff60c69ee3875f") + .addQ1("y", "0x589a62d2b22357fed5449bc38065b760095ebe6aeac84b01156ee4252715446e") + .addU("0xafe47f2ea2b10465cc26ac403194dfb68b7f5ee865cda61e9f3e07a537220af1") + .addU("0x379a27833b0bfe6f7bdca08e1e83c760bf9a338ab335542704edcd69ce9e46e0") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c1526811864e544ed80") + .addP("y", "0xcad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d6df9b56ca3") + .addQ0("x", "0xa17bdf2965eb88074bc01157e644ed409dac97cfcf0c61c998ed0fa45e79e4a2") + .addQ0("y", "0x4f1bc80c70d411a3cc1d67aeae6e726f0f311639fee560c7f5a664554e3c9c2e") + .addQ1("x", "0x7da48bb67225c1a17d452c983798113f47e438e4202219dd0715f8419b274d66") + .addQ1("y", "0xb765696b2913e36db3016c47edb99e24b1da30e761a8a3215dc0ec4d8f96e6f9") + .addU("0x0fad9d125a9477d55cf9357105b0eb3a5c4259809bf87180aa01d651f53d312c") + .addU("0xb68597377392cd3419d8fcc7d7660948c8403b19ea78bbca4b133c9d2196c0fb") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x4be61ee205094282ba8a2042bcb48d88dfbb609301c49aa8b078533dc65a0b5d") + .addP("y", "0x98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539d2bfb3c29e") + .addQ0("x", "0xc76aaa823aeadeb3f356909cb08f97eee46ecb157c1f56699b5efebddf0e6398") + .addQ0("y", "0x776a6f45f528a0e8d289a4be12c4fab80762386ec644abf2bffb9b627e4352b1") + .addQ1("x", "0x418ac3d85a5ccc4ea8dec14f750a3a9ec8b85176c95a7022f391826794eb5a75") + .addQ1("y", "0xfd6604f69e9d9d2b74b072d14ea13050db72c932815523305cb9e807cc900aff") + .addU("0x3bbc30446f39a7befad080f4d5f32ed116b9534626993d2cc5033f6f8d805919") + .addU("0x76bb02db019ca9d3c1e02f0c17f8baf617bbdae5c393a81d9ce11e3be1bf1d33") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x457ae2981f70ca85d8e24c308b14db22f3e3862c5ea0f652ca38b5e49cd64bc5") + .addP("y", "0xecb9f0eadc9aeed232dabc53235368c1394c78de05dd96893eefa62b0f4757dc") + .addQ0("x", "0xd88b989ee9d1295df413d4456c5c850b8b2fb0f5402cc5c4c7e815412e926db8") + .addQ0("y", "0xbb4a1edeff506cf16def96afff41b16fc74f6dbd55c2210e5b8f011ba32f4f40") + .addQ1("x", "0xa281e34e628f3a4d2a53fa87ff973537d68ad4fbc28d3be5e8d9f6a2571c5a4b") + .addQ1("y", "0xf6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184") + .addU("0x4ebc95a6e839b1ae3c63b847798e85cb3c12d3817ec6ebc10af6ee51adb29fec") + .addU("0x4e21af88e22ea80156aff790750121035b3eefaa96b425a8716e0d20b4e269ee") + .build() + ) + .build(); + + P256_ETC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x30") + .Z("0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5") + .ciphersuite("P256_XMD:SHA-256_SSWU_NU_") + .curve("NIST P-256") + .dst("QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_NU_") + .expand("XMD") + .field("0x1", + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff") + .hash("sha256") + .k("0x80") + .addMap("name", "SSWU") + .randomOracle(false) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0xf871caad25ea3b59c16cf87c1894902f7e7b2c822c3d3f73596c5ace8ddd14d1") + .addP("y", "0x87b9ae23335bee057b99bac1e68588b18b5691af476234b8971bc4f011ddc99b") + .addQ0("x", "0xf871caad25ea3b59c16cf87c1894902f7e7b2c822c3d3f73596c5ace8ddd14d1") + .addQ0("y", "0x87b9ae23335bee057b99bac1e68588b18b5691af476234b8971bc4f011ddc99b") + .addU("0xb22d487045f80e9edcb0ecc8d4bf77833e2bf1f3a54004d7df1d57f4802d311f") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0xfc3f5d734e8dce41ddac49f47dd2b8a57257522a865c124ed02b92b5237befa4") + .addP("y", "0xfe4d197ecf5a62645b9690599e1d80e82c500b22ac705a0b421fac7b47157866") + .addQ0("x", "0xfc3f5d734e8dce41ddac49f47dd2b8a57257522a865c124ed02b92b5237befa4") + .addQ0("y", "0xfe4d197ecf5a62645b9690599e1d80e82c500b22ac705a0b421fac7b47157866") + .addU("0xc7f96eadac763e176629b09ed0c11992225b3a5ae99479760601cbd69c221e58") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0xf164c6674a02207e414c257ce759d35eddc7f55be6d7f415e2cc177e5d8faa84") + .addP("y", "0x3aa274881d30db70485368c0467e97da0e73c18c1d00f34775d012b6fcee7f97") + .addQ0("x", "0xf164c6674a02207e414c257ce759d35eddc7f55be6d7f415e2cc177e5d8faa84") + .addQ0("y", "0x3aa274881d30db70485368c0467e97da0e73c18c1d00f34775d012b6fcee7f97") + .addU("0x314e8585fa92068b3ea2c3bab452d4257b38be1c097d58a21890456c2929614d") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x324532006312be4f162614076460315f7a54a6f85544da773dc659aca0311853") + .addP("y", "0x8d8197374bcd52de2acfefc8a54fe2c8d8bebd2a39f16be9b710e4b1af6ef883") + .addQ0("x", "0x324532006312be4f162614076460315f7a54a6f85544da773dc659aca0311853") + .addQ0("y", "0x8d8197374bcd52de2acfefc8a54fe2c8d8bebd2a39f16be9b710e4b1af6ef883") + .addU("0x752d8eaa38cd785a799a31d63d99c2ae4261823b4a367b133b2c6627f48858ab") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x5c4bad52f81f39c8e8de1260e9a06d72b8b00a0829a8ea004a610b0691bea5d9") + .addP("y", "0xc801e7c0782af1f74f24fc385a8555da0582032a3ce038de637ccdcb16f7ef7b") + .addQ0("x", "0x5c4bad52f81f39c8e8de1260e9a06d72b8b00a0829a8ea004a610b0691bea5d9") + .addQ0("y", "0xc801e7c0782af1f74f24fc385a8555da0582032a3ce038de637ccdcb16f7ef7b") + .addU("0x0e1527840b9df2dfbef966678ff167140f2b27c4dccd884c25014dce0e41dfa3") + .build() + ) + .build(); + + P384_HTC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x48") + .Z("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3") + .ciphersuite("P384_XMD:SHA-384_SSWU_RO_") + .curve("NIST P-384") + .dst("QUUX-V01-CS02-with-P384_XMD:SHA-384_SSWU_RO_") + .expand("XMD") + .field("0x1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff") + .hash("sha384") + .k("0xc0") + .addMap("name", "SSWU") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0xeb9fe1b4f4e14e7140803c1d99d0a93cd823d2b024040f9c067a8eca1f5a2eeac9ad604973527a356f3fa3aeff0e4d83") + .addP("y", "0x0c21708cff382b7f4643c07b105c2eaec2cead93a917d825601e63c8f21f6abd9abc22c93c2bed6f235954b25048bb1a") + .addQ0("x", "0xe4717e29eef38d862bee4902a7d21b44efb58c464e3e1f0d03894d94de310f8ffc6de86786dd3e15a1541b18d4eb2846") + .addQ0("y", "0x6b95a6e639822312298a47526bb77d9cd7bcf76244c991c8cd70075e2ee6e8b9a135c4a37e3c0768c7ca871c0ceb53d4") + .addQ1("x", "0x509527cfc0750eedc53147e6d5f78596c8a3b7360e0608e2fab0563a1670d58d8ae107c9f04bcf90e89489ace5650efd") + .addQ1("y", "0x33337b13cb35e173fdea4cb9e8cce915d836ff57803dbbeb7998aa49d17df2ff09b67031773039d09fbd9305a1566bc4") + .addU("0x25c8d7dc1acd4ee617766693f7f8829396065d1b447eedb155871feffd9c6653279ac7e5c46edb7010a0e4ff64c9f3b4") + .addU("0x59428be4ed69131df59a0c6a8e188d2d4ece3f1b2a3a02602962b47efa4d7905945b1e2cc80b36aa35c99451073521ac") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0xe02fc1a5f44a7519419dd314e29863f30df55a514da2d655775a81d413003c4d4e7fd59af0826dfaad4200ac6f60abe1") + .addP("y", "0x01f638d04d98677d65bef99aef1a12a70a4cbb9270ec55248c04530d8bc1f8f90f8a6a859a7c1f1ddccedf8f96d675f6") + .addQ0("x", "0xfc853b69437aee9a19d5acf96a4ee4c5e04cf7b53406dfaa2afbdd7ad2351b7f554e4bbc6f5db4177d4d44f933a8f6ee") + .addQ0("y", "0x7e042547e01834c9043b10f3a8221c4a879cb156f04f72bfccab0c047a304e30f2aa8b2e260d34c4592c0c33dd0c6482") + .addQ1("x", "0x57912293709b3556b43a2dfb137a315d256d573b82ded120ef8c782d607c05d930d958e50cb6dc1cc480b9afc38c45f1") + .addQ1("y", "0xde9387dab0eef0bda219c6f168a92645a84665c4f2137c14270fb424b7532ff84843c3da383ceea24c47fa343c227bb8") + .addU("0x53350214cb6bef0b51abb791b1c4209a2b4c16a0c67e1ab1401017fad774cd3b3f9a8bcdf7f6229dd8dd5a075cb149a0") + .addU("0xc0473083898f63e03f26f14877a2407bd60c75ad491e7d26cbc6cc5ce815654075ec6b6898c7a41d74ceaf720a10c02e") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0xbdecc1c1d870624965f19505be50459d363c71a699a496ab672f9a5d6b78676400926fbceee6fcd1780fe86e62b2aa89") + .addP("y", "0x57cf1f99b5ee00f3c201139b3bfe4dd30a653193778d89a0accc5e0f47e46e4e4b85a0595da29c9494c1814acafe183c") + .addQ0("x", "0x0ceece45b73f89844671df962ad2932122e878ad2259e650626924e4e7f132589341dec1480ebcbbbe3509d11fb570b7") + .addQ0("y", "0xfafd71a3115298f6be4ae5c6dfc96c400cfb55760f185b7b03f3fa45f3f91eb65d27628b3c705cafd0466fafa54883ce") + .addQ1("x", "0xdea1be8d3f9be4cbf4fab9d71d549dde76875b5d9b876832313a083ec81e528cbc2a0a1d0596b3bcb0ba77866b129776") + .addQ1("y", "0xeb15fe71662214fb03b65541f40d3eb0f4cf5c3b559f647da138c9f9b7484c48a08760e02c16f1992762cb7298fa52cf") + .addU("0xaab7fb87238cf6b2ab56cdcca7e028959bb2ea599d34f68484139dde85ec6548a6e48771d17956421bdb7790598ea52e") + .addU("0x26e8d833552d7844d167833ca5a87c35bcfaa5a0d86023479fb28e5cd6075c18b168bf1f5d2a0ea146d057971336d8d1") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x03c3a9f401b78c6c36a52f07eeee0ec1289f178adf78448f43a3850e0456f5dd7f7633dd31676d990eda32882ab486c0") + .addP("y", "0xcc183d0d7bdfd0a3af05f50e16a3f2de4abbc523215bf57c848d5ea662482b8c1f43dc453a93b94a8026db58f3f5d878") + .addQ0("x", "0x051a22105e0817a35d66196338c8d85bd52690d79bba373ead8a86dd9899411513bb9f75273f6483395a7847fb21edb4") + .addQ0("y", "0xf168295c1bbcff5f8b01248e9dbc885335d6d6a04aea960f7384f746ba6502ce477e624151cc1d1392b00df0f5400c06") + .addQ1("x", "0x6ad7bc8ed8b841efd8ad0765c8a23d0b968ec9aa360a558ff33500f164faa02bee6c704f5f91507c4c5aad2b0dc5b943") + .addQ1("y", "0x47313cc0a873ade774048338fc34ca5313f96bbf6ae22ac6ef475d85f03d24792dc6afba8d0b4a70170c1b4f0f716629") + .addU("0x04c00051b0de6e726d228c85bf243bf5f4789efb512b22b498cde3821db9da667199b74bd5a09a79583c6d353a3bb41c") + .addU("0x97580f218255f899f9204db64cd15e6a312cb4d8182375d1e5157c8f80f41d6a1a4b77fb1ded9dce56c32058b8d5202b") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x7b18d210b1f090ac701f65f606f6ca18fb8d081e3bc6cbd937c5604325f1cdea4c15c10a54ef303aabf2ea58bd9947a4") + .addP("y", "0xea857285a33abb516732915c353c75c576bf82ccc96adb63c094dde580021eddeafd91f8c0bfee6f636528f3d0c47fd2") + .addQ0("x", "0x42e6666f505e854187186bad3011598d9278b9d6e3e4d2503c3d236381a56748dec5d139c223129b324df53fa147c4df") + .addQ0("y", "0x8ee51dbda46413bf621838cc935d18d617881c6f33f3838a79c767a1e5618e34b22f79142df708d2432f75c7366c8512") + .addQ1("x", "0x4ff01ceeba60484fa1bc0d825fe1e5e383d8f79f1e5bb78e5fb26b7a7ef758153e31e78b9d60ce75c5e32e43869d4e12") + .addQ1("y", "0x0f84b978fac8ceda7304b47e229d6037d32062e597dc7a9b95bcd9af441f3c56c619a901d21635f9ec6ab4710b9fcd0e") + .addU("0x480cb3ac2c389db7f9dac9c396d2647ae946db844598971c26d1afd53912a1491199c0a5902811e4b809c26fcd37a014") + .addU("0xd28435eb34680e148bf3908536e42231cba9e1f73ae2c6902a222a89db5c49c97db2f8fa4d4cd6e424b17ac60bdb9bb6") + .build() + ) + .build(); + + P384_ETC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x48") + .Z("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3") + .ciphersuite("P384_XMD:SHA-384_SSWU_NU_") + .curve("NIST P-384") + .dst("QUUX-V01-CS02-with-P384_XMD:SHA-384_SSWU_NU_") + .expand("XMD") + .field("0x1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff") + .hash("sha384") + .k("0xc0") + .addMap("name", "SSWU") + .randomOracle(false) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0xde5a893c83061b2d7ce6a0d8b049f0326f2ada4b966dc7e72927256b033ef61058029a3bfb13c1c7ececd6641881ae20") + .addP("y", "0x63f46da6139785674da315c1947e06e9a0867f5608cf24724eb3793a1f5b3809ee28eb21a0c64be3be169afc6cdb38ca") + .addQ0("x", "0xde5a893c83061b2d7ce6a0d8b049f0326f2ada4b966dc7e72927256b033ef61058029a3bfb13c1c7ececd6641881ae20") + .addQ0("y", "0x63f46da6139785674da315c1947e06e9a0867f5608cf24724eb3793a1f5b3809ee28eb21a0c64be3be169afc6cdb38ca") + .addU("0xbc7dc1b2cdc5d588a66de3276b0f24310d4aca4977efda7d6272e1be25187b001493d267dc53b56183c9e28282368e60") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x1f08108b87e703c86c872ab3eb198a19f2b708237ac4be53d7929fb4bd5194583f40d052f32df66afe5249c9915d139b") + .addP("y", "0x1369dc8d5bf038032336b989994874a2270adadb67a7fcc32f0f8824bc5118613f0ac8de04a1041d90ff8a5ad555f96c") + .addQ0("x", "0x1f08108b87e703c86c872ab3eb198a19f2b708237ac4be53d7929fb4bd5194583f40d052f32df66afe5249c9915d139b") + .addQ0("y", "0x1369dc8d5bf038032336b989994874a2270adadb67a7fcc32f0f8824bc5118613f0ac8de04a1041d90ff8a5ad555f96c") + .addU("0x9de6cf41e6e41c03e4a7784ac5c885b4d1e49d6de390b3cdd5a1ac5dd8c40afb3dfd7bb2686923bab644134483fc1926") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x4dac31ec8a82ee3c02ba2d7c9fa431f1e59ffe65bf977b948c59e1d813c2d7963c7be81aa6db39e78ff315a10115c0d0") + .addP("y", "0x845333cdb5702ad5c525e603f302904d6fc84879f0ef2ee2014a6b13edd39131bfd66f7bd7cdc2d9ccf778f0c8892c3f") + .addQ0("x", "0x4dac31ec8a82ee3c02ba2d7c9fa431f1e59ffe65bf977b948c59e1d813c2d7963c7be81aa6db39e78ff315a10115c0d0") + .addQ0("y", "0x845333cdb5702ad5c525e603f302904d6fc84879f0ef2ee2014a6b13edd39131bfd66f7bd7cdc2d9ccf778f0c8892c3f") + .addU("0x84e2d430a5e2543573e58e368af41821ca3ccc97baba7e9aab51a84543d5a0298638a22ceee6090d9d642921112af5b7") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x13c1f8c52a492183f7c28e379b0475486718a7e3ac1dfef39283b9ce5fb02b73f70c6c1f3dfe0c286b03e2af1af12d1d") + .addP("y", "0x57e101887e73e40eab8963324ed16c177d55eb89f804ec9df06801579820420b5546b579008df2145fd770f584a1a54c") + .addQ0("x", "0x13c1f8c52a492183f7c28e379b0475486718a7e3ac1dfef39283b9ce5fb02b73f70c6c1f3dfe0c286b03e2af1af12d1d") + .addQ0("y", "0x57e101887e73e40eab8963324ed16c177d55eb89f804ec9df06801579820420b5546b579008df2145fd770f584a1a54c") + .addU("0x504e4d5a529333b9205acaa283107bd1bffde753898f7744161f7dd19ba57fbb6a64214a2e00ddd2613d76cd508ddb30") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0xaf129727a4207a8cb9e9dce656d88f79fce25edbcea350499d65e9bf1204537bdde73c7cefb752a6ed5ebcd44e183302") + .addP("y", "0xce68a3d5e161b2e6a968e4ddaa9e51504ad1516ec170c7eef3ca6b5327943eca95d90b23b009ba45f58b72906f2a99e2") + .addQ0("x", "0xaf129727a4207a8cb9e9dce656d88f79fce25edbcea350499d65e9bf1204537bdde73c7cefb752a6ed5ebcd44e183302") + .addQ0("y", "0xce68a3d5e161b2e6a968e4ddaa9e51504ad1516ec170c7eef3ca6b5327943eca95d90b23b009ba45f58b72906f2a99e2") + .addU("0x7b01ce9b8c5a60d9fbc202d6dde92822e46915d8c17e03fcb92ece1ed6074d01e149fc9236def40d673de903c1d4c166") + .build() + ) + .build(); + + P521_HTC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x62") + .Z("0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb") + .ciphersuite("P521_XMD:SHA-512_SSWU_RO_") + .curve("NIST P-521") + .dst("QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_RO_") + .expand("XMD") + .field("0x1", + "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + .hash("sha512") + .k("0x100") + .addMap("name", "SSWU") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x00fd767cebb2452030358d0e9cf907f525f50920c8f607889a6a35680727f64f4d66b161fafeb2654bea0d35086bec0a10b30b14adef3556ed9f7f1bc23cecc9c088") + .addP("y", "0x0169ba78d8d851e930680322596e39c78f4fe31b97e57629ef6460ddd68f8763fd7bd767a4e94a80d3d21a3c2ee98347e024fc73ee1c27166dc3fe5eeef782be411d") + .addQ0("x", "0x00b70ae99b6339fffac19cb9bfde2098b84f75e50ac1e80d6acb954e4534af5f0e9c4a5b8a9c10317b8e6421574bae2b133b4f2b8c6ce4b3063da1d91d34fa2b3a3c") + .addQ0("y", "0x007f368d98a4ddbf381fb354de40e44b19e43bb11a1278759f4ea7b485e1b6db33e750507c071250e3e443c1aaed61f2c28541bb54b1b456843eda1eb15ec2a9b36e") + .addQ1("x", "0x01143d0e9cddcdacd6a9aafe1bcf8d218c0afc45d4451239e821f5d2a56df92be942660b532b2aa59a9c635ae6b30e803c45a6ac871432452e685d661cd41cf67214") + .addQ1("y", "0x00ff75515df265e996d702a5380defffab1a6d2bc232234c7bcffa433cd8aa791fbc8dcf667f08818bffa739ae25773b32073213cae9a0f2a917a0b1301a242dda0c") + .addU("0x01e5f09974e5724f25286763f00ce76238c7a6e03dc396600350ee2c4135fb17dc555be99a4a4bae0fd303d4f66d984ed7b6a3ba386093752a855d26d559d69e7e9e") + .addU("0x00ae593b42ca2ef93ac488e9e09a5fe5a2f6fb330d18913734ff602f2a761fcaaf5f596e790bcc572c9140ec03f6cccc38f767f1c1975a0b4d70b392d95a0c7278aa") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x002f89a1677b28054b50d15e1f81ed6669b5a2158211118ebdef8a6efc77f8ccaa528f698214e4340155abc1fa08f8f613ef14a043717503d57e267d57155cf784a4") + .addP("y", "0x010e0be5dc8e753da8ce51091908b72396d3deed14ae166f66d8ebf0a4e7059ead169ea4bead0232e9b700dd380b316e9361cfdba55a08c73545563a80966ecbb86d") + .addQ0("x", "0x01b254e1c99c835836f0aceebba7d77750c48366ecb07fb658e4f5b76e229ae6ca5d271bb0006ffcc42324e15a6d3daae587f9049de2dbb0494378ffb60279406f56") + .addQ0("y", "0x01845f4af72fc2b1a5a2fe966f6a97298614288b456cfc385a425b686048b25c952fbb5674057e1eb055d04568c0679a8e2dda3158dc16ac598dbb1d006f5ad915b0") + .addQ1("x", "0x007f08e813c620e527c961b717ffc74aac7afccb9158cebc347d5715d5c2214f952c97e194f11d114d80d3481ed766ac0a3dba3eb73f6ff9ccb9304ad10bbd7b4a36") + .addQ1("y", "0x0022468f92041f9970a7cc025d71d5b647f822784d29ca7b3bc3b0829d6bb8581e745f8d0cc9dc6279d0450e779ac2275c4c3608064ad6779108a7828ebd9954caeb") + .addU("0x003d00c37e95f19f358adeeaa47288ec39998039c3256e13c2a4c00a7cb61a34c8969472960150a27276f2390eb5e53e47ab193351c2d2d9f164a85c6a5696d94fe8") + .addU("0x01f3cbd3df3893a45a2f1fecdac4d525eb16f345b03e2820d69bc580f5cbe9cb89196fdf720ef933c4c0361fcfe29940fd0db0a5da6bafb0bee8876b589c41365f15") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x006e200e276a4a81760099677814d7f8794a4a5f3658442de63c18d2244dcc957c645e94cb0754f95fcf103b2aeaf94411847c24187b89fb7462ad3679066337cbc4") + .addP("y", "0x001dd8dfa9775b60b1614f6f169089d8140d4b3e4012949b52f98db2deff3e1d97bf73a1fa4d437d1dcdf39b6360cc518d8ebcc0f899018206fded7617b654f6b168") + .addQ0("x", "0x0021482e8622aac14da60e656043f79a6a110cbae5012268a62dd6a152c41594549f373910ebed170ade892dd5a19f5d687fae7095a461d583f8c4295f7aaf8cd7da") + .addQ0("y", "0x0177e2d8c6356b7de06e0b5712d8387d529b848748e54a8bc0ef5f1475aa569f8f492fa85c3ad1c5edc51faf7911f11359bfa2a12d2ef0bd73df9cb5abd1b101c8b1") + .addQ1("x", "0x00abeafb16fdbb5eb95095678d5a65c1f293291dfd20a3751dbe05d0a9bfe2d2eef19449fe59ec32cdd4a4adc3411177c0f2dffd0159438706159a1bbd0567d9b3d0") + .addQ1("y", "0x007cc657f847db9db651d91c801741060d63dab4056d0a1d3524e2eb0e819954d8f677aa353bd056244a88f00017e00c3ce8beeedb4382d83d74418bd48930c6c182") + .addU("0x00183ee1a9bbdc37181b09ec336bcaa34095f91ef14b66b1485c166720523dfb81d5c470d44afcb52a87b704dbc5c9bc9d0ef524dec29884a4795f55c1359945baf3") + .addU("0x00504064fd137f06c81a7cf0f84aa7e92b6b3d56c2368f0a08f44776aa8930480da1582d01d7f52df31dca35ee0a7876500ece3d8fe0293cd285f790c9881c998d5e") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x01b264a630bd6555be537b000b99a06761a9325c53322b65bdc41bf196711f9708d58d34b3b90faf12640c27b91c70a507998e55940648caa8e71098bf2bc8d24664") + .addP("y", "0x01ea9f445bee198b3ee4c812dcf7b0f91e0881f0251aab272a12201fd89b1a95733fd2a699c162b639e9acdcc54fdc2f6536129b6beb0432be01aa8da02df5e59aaa") + .addQ0("x", "0x0005eac7b0b81e38727efcab1e375f6779aea949c3e409b53a1d37aa2acbac87a7e6ad24aafbf3c52f82f7f0e21b872e88c55e17b7fa21ce08a94ea2121c42c2eb73") + .addQ0("y", "0x00a173b6a53a7420dbd61d4a21a7c0a52de7a5c6ce05f31403bef747d16cc8604a039a73bdd6e114340e55dacd6bea8e217ffbadfb8c292afa3e1b2afc839a6ce7bb") + .addQ1("x", "0x01881e3c193a69e4d88d8180a6879b74782a0bc7e529233e9f84bf7f17d2f319c36920ffba26f9e57a1e045cc7822c834c239593b6e142a694aa00c757b0db79e5e8") + .addQ1("y", "0x01558b16d396d866e476e001f2dd0758927655450b84e12f154032c7c2a6db837942cd9f44b814f79b4d729996ced61eec61d85c675139cbffe3fbf071d2c21cfecb") + .addU("0x0159871e222689aad7694dc4c3480a49807b1eedd9c8cb4ae1b219d5ba51655ea5b38e2e4f56b36bf3e3da44a7b139849d28f598c816fe1bc7ed15893b22f63363c3") + .addU("0x004ef0cffd475152f3858c0a8ccbdf7902d8261da92744e98df9b7fadb0a5502f29c5086e76e2cf498f47321434a40b1504911552ce44ad7356a04e08729ad9411f5") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x00c12bc3e28db07b6b4d2a2b1167ab9e26fc2fa85c7b0498a17b0347edf52392856d7e28b8fa7a2dd004611159505835b687ecf1a764857e27e9745848c436ef3925") + .addP("y", "0x01cd287df9a50c22a9231beb452346720bb163344a41c5f5a24e8335b6ccc595fd436aea89737b1281aecb411eb835f0b939073fdd1dd4d5a2492e91ef4a3c55bcbd") + .addQ0("x", "0x00041f6eb92af8777260718e4c22328a7d74203350c6c8f5794d99d5789766698f459b83d5068276716f01429934e40af3d1111a22780b1e07e72238d2207e5386be") + .addQ0("y", "0x001c712f0182813942b87cab8e72337db017126f52ed797dd234584ac9ae7e80dfe7abea11db02cf1855312eae1447dbaecc9d7e8c880a5e76a39f6258074e1bc2e0") + .addQ1("x", "0x0125c0b69bcf55eab49280b14f707883405028e05c927cd7625d4e04115bd0e0e6323b12f5d43d0d6d2eff16dbcf244542f84ec058911260dc3bb6512ab5db285fbd") + .addQ1("y", "0x008bddfb803b3f4c761458eb5f8a0aee3e1f7f68e9d7424405fa69172919899317fb6ac1d6903a432d967d14e0f80af63e7035aaae0c123e56862ce969456f99f102") + .addU("0x0033d06d17bc3b9a3efc081a05d65805a14a3050a0dd4dfb4884618eb5c73980a59c5a246b18f58ad022dd3630faa22889fbb8ba1593466515e6ab4aeb7381c26334") + .addU("0x0092290ab99c3fea1a5b8fb2ca49f859994a04faee3301cefab312d34227f6a2d0c3322cf76861c6a3683bdaa2dd2a6daa5d6906c663e065338b2344d20e313f1114") + .build() + ) + .build(); + + P521_ETC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x62") + .Z("0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb") + .ciphersuite("P521_XMD:SHA-512_SSWU_NU_") + .curve("NIST P-521") + .dst("QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_NU_") + .expand("XMD") + .field("0x1", + "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + .hash("sha512") + .k("0x100") + .addMap("name", "SSWU") + .randomOracle(false) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x01ec604b4e1e3e4c7449b7a41e366e876655538acf51fd40d08b97be066f7d020634e906b1b6942f9174b417027c953d75fb6ec64b8cee2a3672d4f1987d13974705") + .addP("y", "0x00944fc439b4aad2463e5c9cfa0b0707af3c9a42e37c5a57bb4ecd12fef9fb21508568aedcdd8d2490472df4bbafd79081c81e99f4da3286eddf19be47e9c4cf0e91") + .addQ0("x", "0x01ec604b4e1e3e4c7449b7a41e366e876655538acf51fd40d08b97be066f7d020634e906b1b6942f9174b417027c953d75fb6ec64b8cee2a3672d4f1987d13974705") + .addQ0("y", "0x00944fc439b4aad2463e5c9cfa0b0707af3c9a42e37c5a57bb4ecd12fef9fb21508568aedcdd8d2490472df4bbafd79081c81e99f4da3286eddf19be47e9c4cf0e91") + .addU("0x01e4947fe62a4e47792cee2798912f672fff820b2556282d9843b4b465940d7683a986f93ccb0e9a191fbc09a6e770a564490d2a4ae51b287ca39f69c3d910ba6a4f") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x00c720ab56aa5a7a4c07a7732a0a4e1b909e32d063ae1b58db5f0eb5e09f08a9884bff55a2bef4668f715788e692c18c1915cd034a6b998311fcf46924ce66a2be9a") + .addP("y", "0x003570e87f91a4f3c7a56be2cb2a078ffc153862a53d5e03e5dad5bccc6c529b8bab0b7dbb157499e1949e4edab21cf5d10b782bc1e945e13d7421ad8121dbc72b1d") + .addQ0("x", "0x00c720ab56aa5a7a4c07a7732a0a4e1b909e32d063ae1b58db5f0eb5e09f08a9884bff55a2bef4668f715788e692c18c1915cd034a6b998311fcf46924ce66a2be9a") + .addQ0("y", "0x003570e87f91a4f3c7a56be2cb2a078ffc153862a53d5e03e5dad5bccc6c529b8bab0b7dbb157499e1949e4edab21cf5d10b782bc1e945e13d7421ad8121dbc72b1d") + .addU("0x0019b85ef78596efc84783d42799e80d787591fe7432dee1d9fa2b7651891321be732ddf653fa8fefa34d86fb728db569d36b5b6ed3983945854b2fc2dc6a75aa25b") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x00bcaf32a968ff7971b3bbd9ce8edfbee1309e2019d7ff373c38387a782b005dce6ceffccfeda5c6511c8f7f312f343f3a891029c5858f45ee0bf370aba25fc990cc") + .addP("y", "0x00923517e767532d82cb8a0b59705eec2b7779ce05f9181c7d5d5e25694ef8ebd4696343f0bc27006834d2517215ecf79482a84111f50c1bae25044fe1dd77744bbd") + .addQ0("x", "0x00bcaf32a968ff7971b3bbd9ce8edfbee1309e2019d7ff373c38387a782b005dce6ceffccfeda5c6511c8f7f312f343f3a891029c5858f45ee0bf370aba25fc990cc") + .addQ0("y", "0x00923517e767532d82cb8a0b59705eec2b7779ce05f9181c7d5d5e25694ef8ebd4696343f0bc27006834d2517215ecf79482a84111f50c1bae25044fe1dd77744bbd") + .addU("0x01dba0d7fa26a562ee8a9014ebc2cca4d66fd9de036176aca8fc11ef254cd1bc208847ab7701dbca7af328b3f601b11a1737a899575a5c14f4dca5aaca45e9935e07") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x001ac69014869b6c4ad7aa8c443c255439d36b0e48a0f57b03d6fe9c40a66b4e2eaed2a93390679a5cc44b3a91862b34b673f0e92c83187da02bf3db967d867ce748") + .addP("y", "0x00d5603d530e4d62b30fccfa1d90c2206654d74291c1db1c25b86a051ee3fffc294e5d56f2e776853406bd09206c63d40f37ad8829524cf89ad70b5d6e0b4a3b7341") + .addQ0("x", "0x001ac69014869b6c4ad7aa8c443c255439d36b0e48a0f57b03d6fe9c40a66b4e2eaed2a93390679a5cc44b3a91862b34b673f0e92c83187da02bf3db967d867ce748") + .addQ0("y", "0x00d5603d530e4d62b30fccfa1d90c2206654d74291c1db1c25b86a051ee3fffc294e5d56f2e776853406bd09206c63d40f37ad8829524cf89ad70b5d6e0b4a3b7341") + .addU("0x00844da980675e1244cb209dcf3ea0aabec23bd54b2cda69fff86eb3acc318bf3d01bae96e9cd6f4c5ceb5539df9a7ad7fcc5e9d54696081ba9782f3a0f6d14987e3") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x01801de044c517a80443d2bd4f503a9e6866750d2f94a22970f62d721f96e4310e4a828206d9cdeaa8f2d476705cc3bbc490a6165c687668f15ec178a17e3d27349b") + .addP("y", "0x0068889ea2e1442245fe42bfda9e58266828c0263119f35a61631a3358330f3bb84443fcb54fcd53a1d097fccbe310489b74ee143fc2938959a83a1f7dd4a6fd395b") + .addQ0("x", "0x01801de044c517a80443d2bd4f503a9e6866750d2f94a22970f62d721f96e4310e4a828206d9cdeaa8f2d476705cc3bbc490a6165c687668f15ec178a17e3d27349b") + .addQ0("y", "0x0068889ea2e1442245fe42bfda9e58266828c0263119f35a61631a3358330f3bb84443fcb54fcd53a1d097fccbe310489b74ee143fc2938959a83a1f7dd4a6fd395b") + .addU("0x01aab1fb7e5cd44ba4d9f32353a383cb1bb9eb763ed40b32bdd5f666988970205998c0e44af6e2b5f6f8e48e969b3f649cae3c6ab463e1b274d968d91c02f00cce91") + .build() + ) + .build(); + + curve25519_HTC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x30") + .Z("0x2") + .ciphersuite("curve25519_XMD:SHA-512_ELL2_RO_") + .curve("curve25519") + .dst("QUUX-V01-CS02-with-curve25519_XMD:SHA-512_ELL2_RO_") + .expand("XMD") + .field("0x1", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed") + .hash("sha512") + .k("0x80") + .addMap("name", "ELL2") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x2de3780abb67e861289f5749d16d3e217ffa722192d16bbd9d1bfb9d112b98c0") + .addP("y", "0x3b5dc2a498941a1033d176567d457845637554a2fe7a3507d21abd1c1bd6e878") + .addQ0("x", "0x36b4df0c864c64707cbf6cf36e9ee2c09a6cb93b28313c169be29561bb904f98") + .addQ0("y", "0x6cd59d664fb58c66c892883cd0eb792e52055284dac3907dd756b45d15c3983d") + .addQ1("x", "0x3fa114783a505c0b2b2fbeef0102853c0b494e7757f2a089d0daae7ed9a0db2b") + .addQ1("y", "0x76c0fe7fec932aaafb8eefb42d9cbb32eb931158f469ff3050af15cfdbbeff94") + .addU("0x005fe8a7b8fef0a16c105e6cadf5a6740b3365e18692a9c05bfbb4d97f645a6a") + .addU("0x1347edbec6a2b5d8c02e058819819bee177077c9d10a4ce165aab0fd0252261a") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x2b4419f1f2d48f5872de692b0aca72cc7b0a60915dd70bde432e826b6abc526d") + .addP("y", "0x1b8235f255a268f0a6fa8763e97eb3d22d149343d495da1160eff9703f2d07dd") + .addQ0("x", "0x16b3d86e056b7970fa00165f6f48d90b619ad618791661b7b5e1ec78be10eac1") + .addQ0("y", "0x4ab256422d84c5120b278cbdfc4e1facc5baadffeccecf8ee9bf3946106d50ca") + .addQ1("x", "0x7ec29ddbf34539c40adfa98fcb39ec36368f47f30e8f888cc7e86f4d46e0c264") + .addQ1("y", "0x10d1abc1cae2d34c06e247f2141ba897657fb39f1080d54f09ce0af128067c74") + .addU("0x49bed021c7a3748f09fa8cdfcac044089f7829d3531066ac9e74e0994e05bc7d") + .addU("0x5c36525b663e63389d886105cee7ed712325d5a97e60e140aba7e2ce5ae851b6") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x68ca1ea5a6acf4e9956daa101709b1eee6c1bb0df1de3b90d4602382a104c036") + .addP("y", "0x2a375b656207123d10766e68b938b1812a4a6625ff83cb8d5e86f58a4be08353") + .addQ0("x", "0x71de3dadfe268872326c35ac512164850860567aea0e7325e6b91a98f86533ad") + .addQ0("y", "0x26a08b6e9a18084c56f2147bf515414b9b63f1522e1b6c5649f7d4b0324296ec") + .addQ1("x", "0x5704069021f61e41779e2ba6b932268316d6d2a6f064f997a22fef16d1eaeaca") + .addQ1("y", "0x50483c7540f64fb4497619c050f2c7fe55454ec0f0e79870bb44302e34232210") + .addU("0x6412b7485ba26d3d1b6c290a8e1435b2959f03721874939b21782df17323d160") + .addU("0x24c7b46c1c6d9a21d32f5707be1380ab82db1054fde82865d5c9e3d968f287b2") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x096e9c8bae6c06b554c1ee69383bb0e82267e064236b3a30608d4ed20b73ac5a") + .addP("y", "0x1eb5a62612cafb32b16c3329794645b5b948d9f8ffe501d4e26b073fef6de355") + .addQ0("x", "0x7a94d45a198fb5daa381f45f2619ab279744efdd8bd8ed587fc5b65d6cea1df0") + .addQ0("y", "0x67d44f85d376e64bb7d713585230cdbfafc8e2676f7568e0b6ee59361116a6e1") + .addQ1("x", "0x30506fb7a32136694abd61b6113770270debe593027a968a01f271e146e60c18") + .addQ1("y", "0x7eeee0e706b40c6b5174e551426a67f975ad5a977ee2f01e8e20a6d612458c3b") + .addU("0x5e123990f11bbb5586613ffabdb58d47f64bb5f2fa115f8ea8df0188e0c9e1b5") + .addU("0x5e8553eb00438a0bb1e7faa59dec6d8087f9c8011e5fb8ed9df31cb6c0d4ac19") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg( + "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x1bc61845a138e912f047b5e70ba9606ba2a447a4dade024c8ef3dd42b7bbc5fe") + .addP("y", "0x623d05e47b70e25f7f1d51dda6d7c23c9a18ce015fe3548df596ea9e38c69bf1") + .addQ0("x", "0x02d606e2699b918ee36f2818f2bc5013e437e673c9f9b9cdc15fd0c5ee913970") + .addQ0("y", "0x29e9dc92297231ef211245db9e31767996c5625dfbf92e1c8107ef887365de1e") + .addQ1("x", "0x38920e9b988d1ab7449c0fa9a6058192c0c797bb3d42ac345724341a1aa98745") + .addQ1("y", "0x24dcc1be7c4d591d307e89049fd2ed30aae8911245a9d8554bf6032e5aa40d3d") + .addU("0x20f481e85da7a3bf60ac0fb11ed1d0558fc6f941b3ac5469aa8b56ec883d6d7d") + .addU("0x017d57fd257e9a78913999a23b52ca988157a81b09c5442501d07fed20869465") + .build() + ) + + .build(); + + curve25519_ETC_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x30") + .Z("0x2") + .ciphersuite("curve25519_XMD:SHA-512_ELL2_NU_") + .curve("curve25519") + .dst("QUUX-V01-CS02-with-curve25519_XMD:SHA-512_ELL2_NU_") + .expand("XMD") + .field("0x1", + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed") + .hash("sha512") + .k("0x80") + .addMap("name", "ELL2") + .randomOracle(false) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x1bb913f0c9daefa0b3375378ffa534bda5526c97391952a7789eb976edfe4d08") + .addP("y", "0x4548368f4f983243e747b62a600840ae7c1dab5c723991f85d3a9768479f3ec4") + .addQ0("x", "0x51125222da5e763d97f3c10fcc92ea6860b9ccbbd2eb1285728f566721c1e65b") + .addQ0("y", "0x343d2204f812d3dfc5304a5808c6c0d81a903a5d228b342442aa3c9ba5520a3d") + .addU("0x608d892b641f0328523802a6603427c26e55e6f27e71a91a478148d45b5093cd") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x7c22950b7d900fa866334262fcaea47a441a578df43b894b4625c9b450f9a026") + .addP("y", "0x5547bc00e4c09685dcbc6cb6765288b386d8bdcb595fa5a6e3969e08097f0541") + .addQ0("x", "0x7d56d1e08cb0ccb92baf069c18c49bb5a0dcd927eff8dcf75ca921ef7f3e6eeb") + .addQ0("y", "0x404d9a7dc25c9c05c44ab9a94590e7c3fe2dcec74533a0b24b188a5d5dacf429") + .addU("0x46f5b22494bfeaa7f232cc8d054be68561af50230234d7d1d63d1d9abeca8da5") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x31ad08a8b0deeb2a4d8b0206ca25f567ab4e042746f792f4b7973f3ae2096c52") + .addP("y", "0x405070c28e78b4fa269427c82827261991b9718bd6c6e95d627d701a53c30db1") + .addQ0("x", "0x3fbe66b9c9883d79e8407150e7c2a1c8680bee496c62fabe4619a72b3cabe90f") + .addQ0("y", "0x08ec476147c9a0a3ff312d303dbbd076abb7551e5fce82b48ab14b433f8d0a7b") + .addU("0x235fe40c443766ce7e18111c33862d66c3b33267efa50d50f9e8e5d252a40aaa") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x027877759d155b1997d0d84683a313eb78bdb493271d935b622900459d52ceaa") + .addP("y", "0x54d691731a53baa30707f4a87121d5169fb5d587d70fb0292b5830dedbec4c18") + .addQ0("x", "0x227e0bb89de700385d19ec40e857db6e6a3e634b1c32962f370d26f84ff19683") + .addQ0("y", "0x5f86ff3851d262727326a32c1bf7655a03665830fa7f1b8b1e5a09d85bc66e4a") + .addU("0x001e92a544463bda9bd04ddbe3d6eed248f82de32f522669efc5ddce95f46f5b") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x5fd892c0958d1a75f54c3182a18d286efab784e774d1e017ba2fb252998b5dc1") + .addP("y", "0x750af3c66101737423a4519ac792fb93337bd74ee751f19da4cf1e94f4d6d0b8") + .addQ0("x", "0x3bcd651ee54d5f7b6013898aab251ee8ecc0688166fce6e9548d38472f6bd196") + .addQ0("y", "0x1bb36ad9197299f111b4ef21271c41f4b7ecf5543db8bb5931307ebdb2eaa465") + .addU("0x1a68a1af9f663592291af987203393f707305c7bac9c8d63d6a729bdc553dc19") + .build() + ) + .build(); + + curve448_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x54") + .Z("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe") + .ciphersuite("curve448_XOF:SHAKE256_ELL2_RO_") + .curve("curve448") + .dst("QUUX-V01-CS02-with-curve448_XOF:SHAKE256_ELL2_RO_") + .expand("XOF") + .field("0x1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + .hash("shake_256") + .k("0xe0") + .addMap("name", "ELL2") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x5ea5ff623d27c75e73717514134e73e419f831a875ca9e82915fdfc7069d0a9f8b532cfb32b1d8dd04ddeedbe3fa1d0d681c01e825d6a9ea") + .addP("y", "0xafadd8de789f8f8e3516efbbe313a7eba364c939ecba00dabf4ced5c563b18e70a284c17d8f46b564c4e6ce11784a3825d941116622128c1") + .addQ0("x", "0x3ba318806f89c19cc019f51e33eb6b8c038dab892e858ce7c7f2c2ac58618d06146a5fef31e49af49588d4d3db1bcf02bd4e4a733e37065d") + .addQ0("y", "0xb30b4cfc2fd14d9d4b70456c0f5c6f6070be551788893d570e7955675a20f6c286d01d6e90d2fb500d2efb8f4e18db7f8268bb9b7fbc5975") + .addQ1("x", "0xf03a48cf003f63be61ca055fec87c750434da07a15f8aa6210389ff85943b5166484339c8bea1af9fc571313d35ed2fbb779408b760c4cbd") + .addQ1("y", "0x23943a33b2954dc54b76a8222faf5b7e18405a41f5ecc61bf1b8df1f9cbfad057307ed0c7b721f19c0390b8ee3a2dec223671f9ff905fda7") + .addU("0xc704c7b3d3b36614cf3eedd0324fe6fe7d1402c50efd16cff89ff63f50938506280d3843478c08e24f7842f4e3ef45f6e3c4897f9d976148") + .addU("0xc25427dc97fff7a5ad0a78654e2c6c27b1c1127b5b53c7950cd1fd6edd2703646b25f341e73deedfebf022d1d3cecd02b93b4d585ead3ed7") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x9b2f7ce34878d7cebf34c582db14958308ea09366d1ec71f646411d3de0ae564d082b06f40cd30dfc08d9fb7cb21df390cf207806ad9d0e4") + .addP("y", "0x138a0eef0a4993ea696152ed7db61f7ddb4e8100573591e7466d61c0c568ecaec939e36a84d276f34c402526d8989a96e99760c4869ed633") + .addQ0("x", "0x26714783887ec444fbade9ae350dc13e8d5a64150679232560726a73d36e28bd56766d7d0b0899d79c8d1c889ae333f601c57532ff3c4f09") + .addQ0("y", "0x080e486f8f5740dbbe82305160cab9fac247b0b22a54d961de675037c3036fa68464c8756478c322ae0aeb9ba386fe626cebb0bcca46840c") + .addQ1("x", "0x0d9741d10421691a8ebc7778b5f623260fdf8b28ae28d776efcb8e0d5fbb65139a2f828617835f527cb2ca24a8f5fc8e84378343c43d096d") + .addQ1("y", "0x54f4c499bf3d5b154511913f9615bd914969b65cfb74508d7ae5a169e9595b7cbcab9a1485e07b2ce426e4fbed052f03842c4313b7dbe39a") + .addU("0x2dd95593dfee26fe0d218d3d9a0a23d9e1a262fd1d0b602483d08415213e75e2db3c69b0a5bc89e71bcefc8c723d2b6a0cf263f02ad2aa70") + .addU("0x272e4c79a1290cc6d2bc4f4f9d31bf7fbe956ca303c04518f117d77c0e9d850796fc3e1e2bcb9c75e8eaaded5e150333cae9931868047c9d") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0xf54ecd14b85a50eeeee0618452df3a75be7bfba11da5118774ae4ea55ac204e153f77285d780c4acee6c96abe3577a0c0b00be6e790cf194") + .addP("y", "0x935247a64bf78c107069943c7e3ecc52acb27ce4a3230407c8357341685ea2152e8c3da93f8cd77da1bddb5bb759c6e7ae7d516dced42850") + .addQ0("x", "0x946d91bd50c90ef70743e0dd194bddd68bb630f4e67e5b93e15a9b94e62cb85134467993501759525c1f4fdbf06f10ddaf817847d735e062") + .addQ0("y", "0x185cf511262ec1e9b3c3cbdc015ab93df4e71cbe87766917d81c9f3419d480407c1462385122c84982d4dae60c3ae4acce0089e37ad65934") + .addQ1("x", "0x01778f4797b717cd6f83c193b2dfb92a1606a36ede941b0f6ab0ac71ad0eac756d17604bf054398887da907e41065d3595f178ae802f2087") + .addQ1("y", "0xb4ca727d0bda895e0eee7eb3cbc28710fa2e90a73b568cae26bd7c2e73b70a9fa0affe1096f0810198890ed65d8935886b6e60dc4c569dc6") + .addU("0x6aab71a38391639f27e49eae8b1cb6b7172a1f478190ece293957e7cdb2391e7cc1c4261970d9c1bbf9c3915438f74fbd7eb5cd4d4d17ace") + .addU("0xc80b8380ca47a3bcbf76caa75cef0e09f3d270d5ee8f676cde11aedf41aaca6741bd81a86232bd336ccb42efad39f06542bc06a67b65909e") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x5bd67c4f88adf6beb10f7e0d0054659776a55c97b809ec8b3101729e104fd0f684e103792f267fd87cc4afc25a073956ef4f268fb02824d5") + .addP("y", "0xda1f5cb16a352719e4cb064cf47ba72aeba7752d03e8ca2c56229f419b4ef378785a5af1a53dd7ab4d467c1f92f7b139b3752faf29c96432") + .addQ0("x", "0xc2d275826d6ad55e41a22318f6b6240f1f862a2e231120ff41eadbec319756032e8cef2a7ac6c10214fa0608c17fcaf61ec2694a8a2b358b") + .addQ0("y", "0x93d2e092762b135509840e609d413200df800d99da91d8b82840666cac30e7a3520adbaa4b089bfdc86132e42729f651d022f4782502f12c") + .addQ1("x", "0x3c0880ece7244036e9a45944a85599f9809d772f770cc237ac41b21aa71615e4f3bb08f64fca618896e4f6cf5bd92e16b89d2cf6e1956bfb") + .addQ1("y", "0x45cce4beb96505cac5976b3d2673641e9bcd18d3462bbb453d293e5282740a6389cfeae610adc7bd425c728541ceec83fcc999164af43fb5") + .addU("0xcb5c27e51f9c18ee8ffdb6be230f4eb4f2c2481963b2293484f08da2241c1ff59f80978e6defe9d70e34abba2fcbe12dc3a1eb2c5d3d2e4a") + .addU("0xc895e8afecec5466e126fa70fc4aa784b8009063afb10e3ee06a9b22318256aa8693b0c85b955cf2d6540b8ed71e729af1b8d5ca3b116cd7") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0xea441c10b3636ecedd5c0dfcae96384cc40de8390a0ab648765b4508da12c586d55dc981275776507ebca0e4d1bcaa302bb69dcfa31b3451") + .addP("y", "0xfee0192d49bcc0c28d954763c2cbe739b9265c4bebe3883803c64971220cfda60b9ac99ad986cd908c0534b260b5cfca46f6c2b0f3f21bda") + .addQ0("x", "0x4321ab02a9849128691e9b80a5c5576793a218de14885fddccb91f17ceb1646ea00a28b69ad211e1f14f17739612dbde3782319bdf009689") + .addQ0("y", "0x1b8a7b539519eec0ea9f7a46a43822e16cba39a439733d6847ac44a806b8adb3e1a75ea48a1228b8937ba85c6cb6ee01046e10cad8953b1e") + .addQ1("x", "0x126d744da6a14fddec0f78a9cee4571c1320ac7645b600187812e4d7021f98fc4703732c54daec787206e1f34d9dbbf4b292c68160b8bfbd") + .addQ1("y", "0x136eebe6020f2389d448923899a1a38a4c8ad74254e0686e91c4f93c1f8f8e1bd619ffb7c1281467882a9c957d22d50f65c5b72b2aee11af") + .addU("0x8cba93a007bb2c801b1769e026b1fa1640b14a34cf3029db3c7fd6392745d6fec0f7870b5071d6da4402cedbbde28ae4e50ab30e1049a238") + .addU("0x4223746145069e4b8a981acc3404259d1a2c3ecfed5d864798a89d45f81a2c59e2d40eb1d5f0fe11478cbb2bb30246dd388cb932ad7bb330") + .build() + ) + .build(); + + edwards25519_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x30") + .Z("0x2") + .ciphersuite("edwards25519_XMD:SHA-512_ELL2_RO_") + .curve("edwards25519") + .dst("QUUX-V01-CS02-with-edwards25519_XMD:SHA-512_ELL2_RO_") + .expand("XMD") + .field("0x1", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed") + .hash("sha512") + .k("0x80") + .addMap("name", "ELL2") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x3c3da6925a3c3c268448dcabb47ccde5439559d9599646a8260e47b1e4822fc6") + .addP("y", "0x09a6c8561a0b22bef63124c588ce4c62ea83a3c899763af26d795302e115dc21") + .addQ0("x", "0x6549118f65bb617b9e8b438decedc73c496eaed496806d3b2eb9ee60b88e09a7") + .addQ0("y", "0x7315bcc8cf47ed68048d22bad602c6680b3382a08c7c5d3f439a973fb4cf9feb") + .addQ1("x", "0x31dcfc5c58aa1bee6e760bf78cbe71c2bead8cebb2e397ece0f37a3da19c9ed2") + .addQ1("y", "0x7876d81474828d8a5928b50c82420b2bd0898d819e9550c5c82c39fc9bafa196") + .addU("0x03fef4813c8cb5f98c6eef88fae174e6e7d5380de2b007799ac7ee712d203f3a") + .addU("0x780bdddd137290c8f589dc687795aafae35f6b674668d92bf92ae793e6a60c75") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x608040b42285cc0d72cbb3985c6b04c935370c7361f4b7fbdb1ae7f8c1a8ecad") + .addP("y", "0x1a8395b88338f22e435bbd301183e7f20a5f9de643f11882fb237f88268a5531") + .addQ0("x", "0x5c1525bd5d4b4e034512949d187c39d48e8cd84242aa4758956e4adc7d445573") + .addQ0("y", "0x2bf426cf7122d1a90abc7f2d108befc2ef415ce8c2d09695a7407240faa01f29") + .addQ1("x", "0x37b03bba828860c6b459ddad476c83e0f9285787a269df2156219b7e5c86210c") + .addQ1("y", "0x285ebf5412f84d0ad7bb4e136729a9ffd2195d5b8e73c0dc85110ce06958f432") + .addU("0x5081955c4141e4e7d02ec0e36becffaa1934df4d7a270f70679c78f9bd57c227") + .addU("0x005bdc17a9b378b6272573a31b04361f21c371b256252ae5463119aa0b925b76") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x6d7fabf47a2dc03fe7d47f7dddd21082c5fb8f86743cd020f3fb147d57161472") + .addP("y", "0x53060a3d140e7fbcda641ed3cf42c88a75411e648a1add71217f70ea8ec561a6") + .addQ0("x", "0x3ac463dd7fddb773b069c5b2b01c0f6b340638f54ee3bd92d452fcec3015b52d") + .addQ0("y", "0x7b03ba1e8db9ec0b390d5c90168a6a0b7107156c994c674b61fe696cbeb46baf") + .addQ1("x", "0x0757e7e904f5e86d2d2f4acf7e01c63827fde2d363985aa7432106f1b3a444ec") + .addQ1("y", "0x50026c96930a24961e9d86aa91ea1465398ff8e42015e2ec1fa397d416f6a1c0") + .addU("0x285ebaa3be701b79871bcb6e225ecc9b0b32dff2d60424b4c50642636a78d5b3") + .addU("0x2e253e6a0ef658fedb8e4bd6a62d1544fd6547922acb3598ec6b369760b81b31") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0x5fb0b92acedd16f3bcb0ef83f5c7b7a9466b5f1e0d8d217421878ea3686f8524") + .addP("y", "0x2eca15e355fcfa39d2982f67ddb0eea138e2994f5956ed37b7f72eea5e89d2f7") + .addQ0("x", "0x703e69787ea7524541933edf41f94010a201cc841c1cce60205ec38513458872") + .addQ0("y", "0x32bb192c4f89106466f0874f5fd56a0d6b6f101cb714777983336c159a9bec75") + .addQ1("x", "0x0c9077c5c31720ed9413abe59bf49ce768506128d810cb882435aa90f713ef6b") + .addQ1("y", "0x7d5aec5210db638c53f050597964b74d6dda4be5b54fa73041bf909ccb3826cb") + .addU("0x4fedd25431c41f2a606952e2945ef5e3ac905a42cf64b8b4d4a83c533bf321af") + .addU("0x02f20716a5801b843987097a8276b6d869295b2e11253751ca72c109d37485a9") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x0efcfde5898a839b00997fbe40d2ebe950bc81181afbd5cd6b9618aa336c1e8c") + .addP("y", "0x6dc2fc04f266c5c27f236a80b14f92ccd051ef1ff027f26a07f8c0f327d8f995") + .addQ0("x", "0x21091b2e3f9258c7dfa075e7ae513325a94a3d8a28e1b1cb3b5b6f5d65675592") + .addQ0("y", "0x41a33d324c89f570e0682cdf7bdb78852295daf8084c669f2cc9692896ab5026") + .addQ1("x", "0x4c07ec48c373e39a23bd7954f9e9b66eeab9e5ee1279b867b3d5315aa815454f") + .addQ1("y", "0x67ccac7c3cb8d1381242d8d6585c57eabaddbb5dca5243a68a8aeb5477d94b3a") + .addU("0x6e34e04a5106e9bd59f64aba49601bf09d23b27f7b594e56d5de06df4a4ea33b") + .addU("0x1c1c2cb59fc053f44b86c5d5eb8c1954b64976d0302d3729ff66e84068f5fd96") + .build() + ) + .build(); + + edwards448_TEST_VECTOR_DATA = TestVectorData.builder() + .L("0x54") + .Z("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe") + .ciphersuite("edwards448_XOF:SHAKE256_ELL2_RO_") + .curve("edwards448") + .dst("QUUX-V01-CS02-with-edwards448_XOF:SHAKE256_ELL2_RO_") + .expand("XOF") + .field("0x1", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + .hash("shake_256") + .k("0xe0") + .addMap("name", "ELL2") + .randomOracle(true) + + // ---- Vector 1 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("") + .addP("x", "0x73036d4a88949c032f01507005c133884e2f0d81f9a950826245dda9e844fc78186c39daaa7147ead3e462cff60e9c6340b58134480b4d17") + .addP("y", "0x94c1d61b43728e5d784ef4fcb1f38e1075f3aef5e99866911de5a234f1aafdc26b554344742e6ba0420b71b298671bbeb2b7736618634610") + .addQ0("x", "0xc08177330869db17fb81a5e6e53b36d29086d806269760f2e4cabaa4015f5dbadb7ca2ba594d96a89d0ca4f0944489e1ef393d53db85096f") + .addQ0("y", "0x02e894598c050eeb7195f5791f1a5f65da3776b7534be37640bcbf95d4b915bd22333c50387583507169708fbd7bea0d7aa385dcc614be9c") + .addQ1("x", "0x770877fd3b6c5503398157b68a9d3609f585f40e1ebebdd69bb0e4d3d9aa811995ce75333fdadfa50db886a35959cc59cffd5c9710daca25") + .addQ1("y", "0xb27fef77aa6231fbbc27538fa90eaca8abd03eb1e62fdae4ec5e828117c3b8b3ff8c34d0a6e6d79fff16d339b94ae8ede33331d5b464c792") + .addU("0x0847c5ebf957d3370b1f98fde499fb3e659996d9fc9b5707176ade785ba72cd84b8a5597c12b1024be5f510fa5ba99642c4cec7f3f69d3e7") + .addU("0xf8cbd8a7ae8c8deed071f3ac4b93e7cfcb8f1eac1645d699fd6d3881cb295a5d3006d9449ed7cad412a77a1fe61e84a9e41d59ef384d6f9a") + .build() + ) + + // ---- Vector 2 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abc") + .addP("x", "0x4e0158acacffa545adb818a6ed8e0b870e6abc24dfc1dc45cf9a052e98469275d9ff0c168d6a5ac7ec05b742412ee090581f12aa398f9f8c") + .addP("y", "0x894d3fa437b2d2e28cdc3bfaade035430f350ec5239b6b406b5501da6f6d6210ff26719cad83b63e97ab26a12df6dec851d6bf38e294af9a") + .addQ0("x", "0x7544612a97f4419c94ab0f621a1ee8ccf46c6657b8e0778ec9718bf4b41bc774487ad87d9b1e617aa49d3a4dd35a3cf57cd390ebf0429952") + .addQ0("y", "0xd3ab703e60267d796b485bb58a28f934bd0133a6d1bbdfeda5277fa293310be262d7f653a5adffa608c37ed45c0e6008e54a16e1a342e4df") + .addQ1("x", "0x6262f18d064bc131ade1b8bbcf1cbdf984f4f88153fcc9f94c888af35d5e41aae84c12f169a55d8abf06e6de6c5b23079e587a58cf73303e") + .addQ1("y", "0x6d57589e901abe7d947c93ab02c307ad9093ed9a83eb0b6e829fb7318d590381ca25f3cc628a36a924a9ddfcf3cbedf94edf3b338ea77403") + .addU("0x04d975cd938ab49be3e81703d6a57cca84ed80d2ff6d4756d3f22947fb5b70ab0231f0087cbfb4b7cae73b41b0c9396b356a4831d9a14322") + .addU("0x2547ca887ac3db7b5fad3a098aa476e90078afe1358af6c63d677d6edfd2100bc004e0f5db94dd2560fc5b308e223241d00488c9ca6b0ef2") + .build() + ) + + // ---- Vector 3 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("abcdef0123456789") + .addP("x", "0x2c25b4503fadc94b27391933b557abdecc601c13ed51c5de68389484f93dbd6c22e5f962d9babf7a39f39f994312f8ca23344847e1fbf176") + .addP("y", "0xd5e6f5350f430e53a110f5ac7fcc82a96cb865aeca982029522d32601e41c042a9dfbdfbefa2b0bdcdc3bc58cca8a7cd546803083d3a8548") + .addQ0("x", "0x1457b60c12e00e47ceb3ce64b57e7c3c61636475443d704a8e2b2ab0a5ac7e4b3909435416784e16e19929c653b1bdcd9478a8e5331ca9ae") + .addQ0("y", "0x935d9f75f7a0babbc39c0a1c3b412518ed8a24bc2c4886722fb4b7d4a747af98e4e2528c75221e2dffd3424abb436e10539a74caaafa3ea3") + .addQ1("x", "0xb44d9e34211b4028f24117e856585ed81448f3c8b934987a1c5939c86048737a08d85934fec6b3c2ef9f09cbd365cf22744f2e4ce69762a4") + .addQ1("y", "0xdc996c1736f4319868f897d9a27c45b02dd3bc6b7ca356a039606e5406e131a0bbe8238208b327b00853e8af84b58b13443e705425563323") + .addU("0x10659ce25588db4e4be6f7c791a79eb21a7f24aaaca76a6ca3b83b80aaf95aa328fe7d569a1ac99f9cd216edf3915d72632f1a8b990e250c") + .addU("0x9243e5b6c480683fd533e81f4a778349a309ce00bd163a29eb9fa8dbc8f549242bef33e030db21cffacd408d2c4264b93e476c6a8590e7aa") + .build() + ) + + // ---- Vector 4 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") + .addP("x", "0xa1861a9464ae31249a0e60bf38791f3663049a3f5378998499a83292e159a2fecff838eb9bc6939e5c6ae76eb074ad4aae39b55b72ca0b9a") + .addP("y", "0x580a2798c5b904f8adfec5bd29fb49b4633cd9f8c2935eb4a0f12e5dfa0285680880296bb729c6405337525fb5ed3dff930c137314f60401") + .addQ0("x", "0x9d355251e245e4b13ed4ea3e5a3c55bf9b7211f1704771f2e1d8f1a65610c468b1cf70c6c2ce30dcaad54ad9e5439471ec554b862ec8875a") + .addQ0("y", "0x6689ba36a242af69ac2aadb955d15e982d9b04f5d77f7609ebf7429587feb7e5ce27490b9c72114509f89565122074e46a614d7fd7c800bd") + .addQ1("x", "0xc4b3d3ad4d2d62739a62989532992c1081e9474a201085b4616da5706cab824693b9fb428a201bcd1639a4588cc43b9eb841dbca74219b1f") + .addQ1("y", "0x265286f5dee8f3d894b5649da8565b58e96b4cfd44b462a2883ea64dbcda21a00706ea3fea53fc2d769084b0b74589e91d0384d7118909fb") + .addU("0xc80390020e578f009ead417029eff6cd0926110922db63ab98395e3bdfdd5d8a65b1a2b8d495dc8c5e59b7f3518731f7dfc0f93ace5dee4b") + .addU("0x1c4dc6653a445bbef2add81d8e90a6c8591a788deb91d0d3f1519a2e4a460313041b77c1b0817f2e80b388e5c3e49f37d787dc1f85e4324a") + .build() + ) + + // ---- Vector 5 ---- + .addVector( + TestVectorData.Vector.builder() + .msg("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .addP("x", "0x987c5ac19dd4b47835466a50b2d9feba7c8491b8885a04edf577e15a9f2c98b203ec2cd3e5390b3d20bba0fa6fc3eecefb5029a317234401") + .addP("y", "0x5e273fcfff6b007bb6771e90509275a71ff1480c459ded26fc7b10664db0a68aaa98bc7ecb07e49cf05b80ae5ac653fbdd14276bbd35ccbc") + .addQ0("x", "0xd1a5eba4a332514b69760948af09ceaeddbbb9fd4cb1f19b78349c2ee4cf9ee86dbcf9064659a4a0566fe9c34d90aec86f0801edc131ad9b") + .addQ0("y", "0x5d0a75a3014c3269c33b1b5da80706a4f097893461df286353484d8031cd607c98edc2a846c77a841f057c7251eb45077853c7b205957e52") + .addQ1("x", "0x69583b00dc6b2aced6ffa44630cc8c8cd0dd0649f57588dd0fb1daad2ce132e281d01e3f25ccd3f405be759975c6484268bfe8f5e5f23c30") + .addQ1("y", "0x8418484035f60bdccf48cb488634c2dfb40272123435f7e654fb6f254c6c42e7e38f1fa79a637a168a28de6c275232b704f9ded0ff76dd94") + .addU("0x163c79ab0210a4b5e4f44fb19437ea965bf5431ab233ef16606f0b03c5f16a3feb7d46a5a675ce8f606e9c2bf74ee5336c54a1e54919f13f") + .addU("0xf99666bde4995c4088333d6c2734687e815f80a99c6da02c47df4b51f6c9d9ed466b4fecf7d9884990a8e0d0be6907fa437e0b1a27f49265") + .build() + ) + .build(); + } + +} + + diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/impl/GenericSqrtRatioCalculatorTest.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/impl/GenericSqrtRatioCalculatorTest.java new file mode 100644 index 0000000000..8f86c1b378 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/impl/GenericSqrtRatioCalculatorTest.java @@ -0,0 +1,49 @@ +package org.bouncycastle.crypto.hash2curve.test.impl; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.hash2curve.impl.SqrtRatio; +import org.bouncycastle.crypto.hash2curve.impl.GenericSqrtRatioCalculator; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; + +import java.math.BigInteger; + +/** + * Test class for the GenericSqrtRatioCalculator + */ +public class GenericSqrtRatioCalculatorTest extends TestCase { + + public void testCalculate1() { + ECCurve curve = new SecP256R1Curve(); + BigInteger z = BigInteger.valueOf(-10); + GenericSqrtRatioCalculator calc = new GenericSqrtRatioCalculator(curve, z); + final SqrtRatio sqrtRatio = calc.sqrtRatio(BigInteger.ONE, BigInteger.valueOf(2)); + final BigInteger ratio = sqrtRatio.getRatio(); + assertEquals("39700825768398291280648376089930606243808550255319087055409208967646307233425", ratio.toString(10)); + final boolean qr = sqrtRatio.isQR(); + assertTrue(qr); + } + + public void testCalculate2() { + ECCurve curve = new SecP256R1Curve(); + BigInteger z = BigInteger.valueOf(-10); + GenericSqrtRatioCalculator calc = new GenericSqrtRatioCalculator(curve, z); + final SqrtRatio sqrtRatio = calc.sqrtRatio(BigInteger.valueOf(10), BigInteger.valueOf(2)); + final BigInteger ratio = sqrtRatio.getRatio(); + assertEquals("3785950496672887136307850542143953904054772247473037052005622114270127172924", ratio.toString(10)); + final boolean qr = sqrtRatio.isQR(); + assertTrue(qr); + } + + public void testCalculate3() { + ECCurve curve = new SecP256R1Curve(); + BigInteger z = BigInteger.valueOf(-10); + GenericSqrtRatioCalculator calc = new GenericSqrtRatioCalculator(curve, z); + final SqrtRatio sqrtRatio = calc.sqrtRatio(BigInteger.valueOf(1431), BigInteger.valueOf(2)); + final boolean qr = sqrtRatio.isQR(); + assertFalse(qr); + final BigInteger ratio = sqrtRatio.getRatio(); + assertEquals("20381299611311062807197803046173075660787338796491438136509906084127806899192", ratio.toString(10)); + } + +} diff --git a/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/impl/SimplifiedShallueVanDeWoestijneMapToCurveTest.java b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/impl/SimplifiedShallueVanDeWoestijneMapToCurveTest.java new file mode 100644 index 0000000000..963ab061f1 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/hash2curve/test/impl/SimplifiedShallueVanDeWoestijneMapToCurveTest.java @@ -0,0 +1,50 @@ +package org.bouncycastle.crypto.hash2curve.test.impl; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.hash2curve.MapToCurve; +import org.bouncycastle.crypto.hash2curve.impl.SimplifiedShallueVanDeWoestijneMapToCurve; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; +import org.bouncycastle.util.encoders.Hex; + +import java.math.BigInteger; + +public class SimplifiedShallueVanDeWoestijneMapToCurveTest extends TestCase { + + + + /* + This test class is testing the "process" method in "ShallueVanDeWoestijneMapToCurve" class which implements + the Shallue van de Woestijne Map to curve according to section 6.6.1 of RFC 9380. + */ + + public void testMapToCurve() throws Exception { + ECCurve p256Curve = new SecP256R1Curve(); + + SimplifiedShallueVanDeWoestijneMapToCurve mapToCurve = + new SimplifiedShallueVanDeWoestijneMapToCurve(p256Curve, BigInteger.valueOf(-10)); + + specificMappingTestcase(new BigInteger(1, + Hex.decode("ad5342c66a6dd0ff080df1da0ea1c04b96e0330dd89406465eeba11582515009")), + mapToCurve, + "ab640a12220d3ff283510ff3f4b1953d09fad35795140b1c5d64f313967934d5", + "dccb558863804a881d4fff3455716c836cef230e5209594ddd33d85c565b19b1" + ); + specificMappingTestcase(new BigInteger(1, + Hex.decode("8c0f1d43204bd6f6ea70ae8013070a1518b43873bcd850aafa0a9e220e2eea5a")), + mapToCurve, + "51cce63c50d972a6e51c61334f0f4875c9ac1cd2d3238412f84e31da7d980ef5", + "b45d1a36d00ad90e5ec7840a60a4de411917fbe7c82c3949a6e699e5a1b66aac" + ); + } + + void specificMappingTestcase(BigInteger u, MapToCurve mapToCurve, String expectedX, String expectedY) throws Exception { + ECPoint qu = mapToCurve.process(u); + String x = qu.getXCoord().toBigInteger().toString(16); + String y = qu.getYCoord().toBigInteger().toString(16); + assertEquals(expectedX, x); + assertEquals(expectedY, y); + } + +} diff --git a/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P256_XMD-SHA-256_SSWU_RO_.json b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P256_XMD-SHA-256_SSWU_RO_.json new file mode 100644 index 0000000000..cf5736ad36 --- /dev/null +++ b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P256_XMD-SHA-256_SSWU_RO_.json @@ -0,0 +1,115 @@ +{ + "L": "0x30", + "Z": "0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5", + "ciphersuite": "P256_XMD:SHA-256_SSWU_RO_", + "curve": "NIST P-256", + "dst": "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_", + "expand": "XMD", + "field": { + "m": "0x1", + "p": "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff" + }, + "hash": "sha256", + "k": "0x80", + "map": { + "name": "SSWU" + }, + "randomOracle": true, + "vectors": [ + { + "P": { + "x": "0x2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4", + "y": "0x8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9ab5c43e8415" + }, + "Q0": { + "x": "0xab640a12220d3ff283510ff3f4b1953d09fad35795140b1c5d64f313967934d5", + "y": "0xdccb558863804a881d4fff3455716c836cef230e5209594ddd33d85c565b19b1" + }, + "Q1": { + "x": "0x51cce63c50d972a6e51c61334f0f4875c9ac1cd2d3238412f84e31da7d980ef5", + "y": "0xb45d1a36d00ad90e5ec7840a60a4de411917fbe7c82c3949a6e699e5a1b66aac" + }, + "msg": "", + "u": [ + "0xad5342c66a6dd0ff080df1da0ea1c04b96e0330dd89406465eeba11582515009", + "0x8c0f1d43204bd6f6ea70ae8013070a1518b43873bcd850aafa0a9e220e2eea5a" + ] + }, + { + "P": { + "x": "0x0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775dac4a3388a0f", + "y": "0x5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71ffd424212e" + }, + "Q0": { + "x": "0x5219ad0ddef3cc49b714145e91b2f7de6ce0a7a7dc7406c7726c7e373c58cb48", + "y": "0x7950144e52d30acbec7b624c203b1996c99617d0b61c2442354301b191d93ecf" + }, + "Q1": { + "x": "0x019b7cb4efcfeaf39f738fe638e31d375ad6837f58a852d032ff60c69ee3875f", + "y": "0x589a62d2b22357fed5449bc38065b760095ebe6aeac84b01156ee4252715446e" + }, + "msg": "abc", + "u": [ + "0xafe47f2ea2b10465cc26ac403194dfb68b7f5ee865cda61e9f3e07a537220af1", + "0x379a27833b0bfe6f7bdca08e1e83c760bf9a338ab335542704edcd69ce9e46e0" + ] + }, + { + "P": { + "x": "0x65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c1526811864e544ed80", + "y": "0xcad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d6df9b56ca3" + }, + "Q0": { + "x": "0xa17bdf2965eb88074bc01157e644ed409dac97cfcf0c61c998ed0fa45e79e4a2", + "y": "0x4f1bc80c70d411a3cc1d67aeae6e726f0f311639fee560c7f5a664554e3c9c2e" + }, + "Q1": { + "x": "0x7da48bb67225c1a17d452c983798113f47e438e4202219dd0715f8419b274d66", + "y": "0xb765696b2913e36db3016c47edb99e24b1da30e761a8a3215dc0ec4d8f96e6f9" + }, + "msg": "abcdef0123456789", + "u": [ + "0x0fad9d125a9477d55cf9357105b0eb3a5c4259809bf87180aa01d651f53d312c", + "0xb68597377392cd3419d8fcc7d7660948c8403b19ea78bbca4b133c9d2196c0fb" + ] + }, + { + "P": { + "x": "0x4be61ee205094282ba8a2042bcb48d88dfbb609301c49aa8b078533dc65a0b5d", + "y": "0x98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539d2bfb3c29e" + }, + "Q0": { + "x": "0xc76aaa823aeadeb3f356909cb08f97eee46ecb157c1f56699b5efebddf0e6398", + "y": "0x776a6f45f528a0e8d289a4be12c4fab80762386ec644abf2bffb9b627e4352b1" + }, + "Q1": { + "x": "0x418ac3d85a5ccc4ea8dec14f750a3a9ec8b85176c95a7022f391826794eb5a75", + "y": "0xfd6604f69e9d9d2b74b072d14ea13050db72c932815523305cb9e807cc900aff" + }, + "msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "u": [ + "0x3bbc30446f39a7befad080f4d5f32ed116b9534626993d2cc5033f6f8d805919", + "0x76bb02db019ca9d3c1e02f0c17f8baf617bbdae5c393a81d9ce11e3be1bf1d33" + ] + }, + { + "P": { + "x": "0x457ae2981f70ca85d8e24c308b14db22f3e3862c5ea0f652ca38b5e49cd64bc5", + "y": "0xecb9f0eadc9aeed232dabc53235368c1394c78de05dd96893eefa62b0f4757dc" + }, + "Q0": { + "x": "0xd88b989ee9d1295df413d4456c5c850b8b2fb0f5402cc5c4c7e815412e926db8", + "y": "0xbb4a1edeff506cf16def96afff41b16fc74f6dbd55c2210e5b8f011ba32f4f40" + }, + "Q1": { + "x": "0xa281e34e628f3a4d2a53fa87ff973537d68ad4fbc28d3be5e8d9f6a2571c5a4b", + "y": "0xf6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184" + }, + "msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "u": [ + "0x4ebc95a6e839b1ae3c63b847798e85cb3c12d3817ec6ebc10af6ee51adb29fec", + "0x4e21af88e22ea80156aff790750121035b3eefaa96b425a8716e0d20b4e269ee" + ] + } + ] +} diff --git a/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P384_XMD-SHA-384_SSWU_RO_.json b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P384_XMD-SHA-384_SSWU_RO_.json new file mode 100644 index 0000000000..bdd9cfaa11 --- /dev/null +++ b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P384_XMD-SHA-384_SSWU_RO_.json @@ -0,0 +1,115 @@ +{ + "L": "0x48", + "Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3", + "ciphersuite": "P384_XMD:SHA-384_SSWU_RO_", + "curve": "NIST P-384", + "dst": "QUUX-V01-CS02-with-P384_XMD:SHA-384_SSWU_RO_", + "expand": "XMD", + "field": { + "m": "0x1", + "p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff" + }, + "hash": "sha384", + "k": "0xc0", + "map": { + "name": "SSWU" + }, + "randomOracle": true, + "vectors": [ + { + "P": { + "x": "0xeb9fe1b4f4e14e7140803c1d99d0a93cd823d2b024040f9c067a8eca1f5a2eeac9ad604973527a356f3fa3aeff0e4d83", + "y": "0x0c21708cff382b7f4643c07b105c2eaec2cead93a917d825601e63c8f21f6abd9abc22c93c2bed6f235954b25048bb1a" + }, + "Q0": { + "x": "0xe4717e29eef38d862bee4902a7d21b44efb58c464e3e1f0d03894d94de310f8ffc6de86786dd3e15a1541b18d4eb2846", + "y": "0x6b95a6e639822312298a47526bb77d9cd7bcf76244c991c8cd70075e2ee6e8b9a135c4a37e3c0768c7ca871c0ceb53d4" + }, + "Q1": { + "x": "0x509527cfc0750eedc53147e6d5f78596c8a3b7360e0608e2fab0563a1670d58d8ae107c9f04bcf90e89489ace5650efd", + "y": "0x33337b13cb35e173fdea4cb9e8cce915d836ff57803dbbeb7998aa49d17df2ff09b67031773039d09fbd9305a1566bc4" + }, + "msg": "", + "u": [ + "0x25c8d7dc1acd4ee617766693f7f8829396065d1b447eedb155871feffd9c6653279ac7e5c46edb7010a0e4ff64c9f3b4", + "0x59428be4ed69131df59a0c6a8e188d2d4ece3f1b2a3a02602962b47efa4d7905945b1e2cc80b36aa35c99451073521ac" + ] + }, + { + "P": { + "x": "0xe02fc1a5f44a7519419dd314e29863f30df55a514da2d655775a81d413003c4d4e7fd59af0826dfaad4200ac6f60abe1", + "y": "0x01f638d04d98677d65bef99aef1a12a70a4cbb9270ec55248c04530d8bc1f8f90f8a6a859a7c1f1ddccedf8f96d675f6" + }, + "Q0": { + "x": "0xfc853b69437aee9a19d5acf96a4ee4c5e04cf7b53406dfaa2afbdd7ad2351b7f554e4bbc6f5db4177d4d44f933a8f6ee", + "y": "0x7e042547e01834c9043b10f3a8221c4a879cb156f04f72bfccab0c047a304e30f2aa8b2e260d34c4592c0c33dd0c6482" + }, + "Q1": { + "x": "0x57912293709b3556b43a2dfb137a315d256d573b82ded120ef8c782d607c05d930d958e50cb6dc1cc480b9afc38c45f1", + "y": "0xde9387dab0eef0bda219c6f168a92645a84665c4f2137c14270fb424b7532ff84843c3da383ceea24c47fa343c227bb8" + }, + "msg": "abc", + "u": [ + "0x53350214cb6bef0b51abb791b1c4209a2b4c16a0c67e1ab1401017fad774cd3b3f9a8bcdf7f6229dd8dd5a075cb149a0", + "0xc0473083898f63e03f26f14877a2407bd60c75ad491e7d26cbc6cc5ce815654075ec6b6898c7a41d74ceaf720a10c02e" + ] + }, + { + "P": { + "x": "0xbdecc1c1d870624965f19505be50459d363c71a699a496ab672f9a5d6b78676400926fbceee6fcd1780fe86e62b2aa89", + "y": "0x57cf1f99b5ee00f3c201139b3bfe4dd30a653193778d89a0accc5e0f47e46e4e4b85a0595da29c9494c1814acafe183c" + }, + "Q0": { + "x": "0x0ceece45b73f89844671df962ad2932122e878ad2259e650626924e4e7f132589341dec1480ebcbbbe3509d11fb570b7", + "y": "0xfafd71a3115298f6be4ae5c6dfc96c400cfb55760f185b7b03f3fa45f3f91eb65d27628b3c705cafd0466fafa54883ce" + }, + "Q1": { + "x": "0xdea1be8d3f9be4cbf4fab9d71d549dde76875b5d9b876832313a083ec81e528cbc2a0a1d0596b3bcb0ba77866b129776", + "y": "0xeb15fe71662214fb03b65541f40d3eb0f4cf5c3b559f647da138c9f9b7484c48a08760e02c16f1992762cb7298fa52cf" + }, + "msg": "abcdef0123456789", + "u": [ + "0xaab7fb87238cf6b2ab56cdcca7e028959bb2ea599d34f68484139dde85ec6548a6e48771d17956421bdb7790598ea52e", + "0x26e8d833552d7844d167833ca5a87c35bcfaa5a0d86023479fb28e5cd6075c18b168bf1f5d2a0ea146d057971336d8d1" + ] + }, + { + "P": { + "x": "0x03c3a9f401b78c6c36a52f07eeee0ec1289f178adf78448f43a3850e0456f5dd7f7633dd31676d990eda32882ab486c0", + "y": "0xcc183d0d7bdfd0a3af05f50e16a3f2de4abbc523215bf57c848d5ea662482b8c1f43dc453a93b94a8026db58f3f5d878" + }, + "Q0": { + "x": "0x051a22105e0817a35d66196338c8d85bd52690d79bba373ead8a86dd9899411513bb9f75273f6483395a7847fb21edb4", + "y": "0xf168295c1bbcff5f8b01248e9dbc885335d6d6a04aea960f7384f746ba6502ce477e624151cc1d1392b00df0f5400c06" + }, + "Q1": { + "x": "0x6ad7bc8ed8b841efd8ad0765c8a23d0b968ec9aa360a558ff33500f164faa02bee6c704f5f91507c4c5aad2b0dc5b943", + "y": "0x47313cc0a873ade774048338fc34ca5313f96bbf6ae22ac6ef475d85f03d24792dc6afba8d0b4a70170c1b4f0f716629" + }, + "msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "u": [ + "0x04c00051b0de6e726d228c85bf243bf5f4789efb512b22b498cde3821db9da667199b74bd5a09a79583c6d353a3bb41c", + "0x97580f218255f899f9204db64cd15e6a312cb4d8182375d1e5157c8f80f41d6a1a4b77fb1ded9dce56c32058b8d5202b" + ] + }, + { + "P": { + "x": "0x7b18d210b1f090ac701f65f606f6ca18fb8d081e3bc6cbd937c5604325f1cdea4c15c10a54ef303aabf2ea58bd9947a4", + "y": "0xea857285a33abb516732915c353c75c576bf82ccc96adb63c094dde580021eddeafd91f8c0bfee6f636528f3d0c47fd2" + }, + "Q0": { + "x": "0x42e6666f505e854187186bad3011598d9278b9d6e3e4d2503c3d236381a56748dec5d139c223129b324df53fa147c4df", + "y": "0x8ee51dbda46413bf621838cc935d18d617881c6f33f3838a79c767a1e5618e34b22f79142df708d2432f75c7366c8512" + }, + "Q1": { + "x": "0x4ff01ceeba60484fa1bc0d825fe1e5e383d8f79f1e5bb78e5fb26b7a7ef758153e31e78b9d60ce75c5e32e43869d4e12", + "y": "0x0f84b978fac8ceda7304b47e229d6037d32062e597dc7a9b95bcd9af441f3c56c619a901d21635f9ec6ab4710b9fcd0e" + }, + "msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "u": [ + "0x480cb3ac2c389db7f9dac9c396d2647ae946db844598971c26d1afd53912a1491199c0a5902811e4b809c26fcd37a014", + "0xd28435eb34680e148bf3908536e42231cba9e1f73ae2c6902a222a89db5c49c97db2f8fa4d4cd6e424b17ac60bdb9bb6" + ] + } + ] +} diff --git a/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P521_XMD-SHA-512_SSWU_RO_.json b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P521_XMD-SHA-512_SSWU_RO_.json new file mode 100644 index 0000000000..0736b8bc23 --- /dev/null +++ b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/P521_XMD-SHA-512_SSWU_RO_.json @@ -0,0 +1,115 @@ +{ + "L": "0x62", + "Z": "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", + "ciphersuite": "P521_XMD:SHA-512_SSWU_RO_", + "curve": "NIST P-521", + "dst": "QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_RO_", + "expand": "XMD", + "field": { + "m": "0x1", + "p": "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + }, + "hash": "sha512", + "k": "0x100", + "map": { + "name": "SSWU" + }, + "randomOracle": true, + "vectors": [ + { + "P": { + "x": "0x00fd767cebb2452030358d0e9cf907f525f50920c8f607889a6a35680727f64f4d66b161fafeb2654bea0d35086bec0a10b30b14adef3556ed9f7f1bc23cecc9c088", + "y": "0x0169ba78d8d851e930680322596e39c78f4fe31b97e57629ef6460ddd68f8763fd7bd767a4e94a80d3d21a3c2ee98347e024fc73ee1c27166dc3fe5eeef782be411d" + }, + "Q0": { + "x": "0x00b70ae99b6339fffac19cb9bfde2098b84f75e50ac1e80d6acb954e4534af5f0e9c4a5b8a9c10317b8e6421574bae2b133b4f2b8c6ce4b3063da1d91d34fa2b3a3c", + "y": "0x007f368d98a4ddbf381fb354de40e44b19e43bb11a1278759f4ea7b485e1b6db33e750507c071250e3e443c1aaed61f2c28541bb54b1b456843eda1eb15ec2a9b36e" + }, + "Q1": { + "x": "0x01143d0e9cddcdacd6a9aafe1bcf8d218c0afc45d4451239e821f5d2a56df92be942660b532b2aa59a9c635ae6b30e803c45a6ac871432452e685d661cd41cf67214", + "y": "0x00ff75515df265e996d702a5380defffab1a6d2bc232234c7bcffa433cd8aa791fbc8dcf667f08818bffa739ae25773b32073213cae9a0f2a917a0b1301a242dda0c" + }, + "msg": "", + "u": [ + "0x01e5f09974e5724f25286763f00ce76238c7a6e03dc396600350ee2c4135fb17dc555be99a4a4bae0fd303d4f66d984ed7b6a3ba386093752a855d26d559d69e7e9e", + "0x00ae593b42ca2ef93ac488e9e09a5fe5a2f6fb330d18913734ff602f2a761fcaaf5f596e790bcc572c9140ec03f6cccc38f767f1c1975a0b4d70b392d95a0c7278aa" + ] + }, + { + "P": { + "x": "0x002f89a1677b28054b50d15e1f81ed6669b5a2158211118ebdef8a6efc77f8ccaa528f698214e4340155abc1fa08f8f613ef14a043717503d57e267d57155cf784a4", + "y": "0x010e0be5dc8e753da8ce51091908b72396d3deed14ae166f66d8ebf0a4e7059ead169ea4bead0232e9b700dd380b316e9361cfdba55a08c73545563a80966ecbb86d" + }, + "Q0": { + "x": "0x01b254e1c99c835836f0aceebba7d77750c48366ecb07fb658e4f5b76e229ae6ca5d271bb0006ffcc42324e15a6d3daae587f9049de2dbb0494378ffb60279406f56", + "y": "0x01845f4af72fc2b1a5a2fe966f6a97298614288b456cfc385a425b686048b25c952fbb5674057e1eb055d04568c0679a8e2dda3158dc16ac598dbb1d006f5ad915b0" + }, + "Q1": { + "x": "0x007f08e813c620e527c961b717ffc74aac7afccb9158cebc347d5715d5c2214f952c97e194f11d114d80d3481ed766ac0a3dba3eb73f6ff9ccb9304ad10bbd7b4a36", + "y": "0x0022468f92041f9970a7cc025d71d5b647f822784d29ca7b3bc3b0829d6bb8581e745f8d0cc9dc6279d0450e779ac2275c4c3608064ad6779108a7828ebd9954caeb" + }, + "msg": "abc", + "u": [ + "0x003d00c37e95f19f358adeeaa47288ec39998039c3256e13c2a4c00a7cb61a34c8969472960150a27276f2390eb5e53e47ab193351c2d2d9f164a85c6a5696d94fe8", + "0x01f3cbd3df3893a45a2f1fecdac4d525eb16f345b03e2820d69bc580f5cbe9cb89196fdf720ef933c4c0361fcfe29940fd0db0a5da6bafb0bee8876b589c41365f15" + ] + }, + { + "P": { + "x": "0x006e200e276a4a81760099677814d7f8794a4a5f3658442de63c18d2244dcc957c645e94cb0754f95fcf103b2aeaf94411847c24187b89fb7462ad3679066337cbc4", + "y": "0x001dd8dfa9775b60b1614f6f169089d8140d4b3e4012949b52f98db2deff3e1d97bf73a1fa4d437d1dcdf39b6360cc518d8ebcc0f899018206fded7617b654f6b168" + }, + "Q0": { + "x": "0x0021482e8622aac14da60e656043f79a6a110cbae5012268a62dd6a152c41594549f373910ebed170ade892dd5a19f5d687fae7095a461d583f8c4295f7aaf8cd7da", + "y": "0x0177e2d8c6356b7de06e0b5712d8387d529b848748e54a8bc0ef5f1475aa569f8f492fa85c3ad1c5edc51faf7911f11359bfa2a12d2ef0bd73df9cb5abd1b101c8b1" + }, + "Q1": { + "x": "0x00abeafb16fdbb5eb95095678d5a65c1f293291dfd20a3751dbe05d0a9bfe2d2eef19449fe59ec32cdd4a4adc3411177c0f2dffd0159438706159a1bbd0567d9b3d0", + "y": "0x007cc657f847db9db651d91c801741060d63dab4056d0a1d3524e2eb0e819954d8f677aa353bd056244a88f00017e00c3ce8beeedb4382d83d74418bd48930c6c182" + }, + "msg": "abcdef0123456789", + "u": [ + "0x00183ee1a9bbdc37181b09ec336bcaa34095f91ef14b66b1485c166720523dfb81d5c470d44afcb52a87b704dbc5c9bc9d0ef524dec29884a4795f55c1359945baf3", + "0x00504064fd137f06c81a7cf0f84aa7e92b6b3d56c2368f0a08f44776aa8930480da1582d01d7f52df31dca35ee0a7876500ece3d8fe0293cd285f790c9881c998d5e" + ] + }, + { + "P": { + "x": "0x01b264a630bd6555be537b000b99a06761a9325c53322b65bdc41bf196711f9708d58d34b3b90faf12640c27b91c70a507998e55940648caa8e71098bf2bc8d24664", + "y": "0x01ea9f445bee198b3ee4c812dcf7b0f91e0881f0251aab272a12201fd89b1a95733fd2a699c162b639e9acdcc54fdc2f6536129b6beb0432be01aa8da02df5e59aaa" + }, + "Q0": { + "x": "0x0005eac7b0b81e38727efcab1e375f6779aea949c3e409b53a1d37aa2acbac87a7e6ad24aafbf3c52f82f7f0e21b872e88c55e17b7fa21ce08a94ea2121c42c2eb73", + "y": "0x00a173b6a53a7420dbd61d4a21a7c0a52de7a5c6ce05f31403bef747d16cc8604a039a73bdd6e114340e55dacd6bea8e217ffbadfb8c292afa3e1b2afc839a6ce7bb" + }, + "Q1": { + "x": "0x01881e3c193a69e4d88d8180a6879b74782a0bc7e529233e9f84bf7f17d2f319c36920ffba26f9e57a1e045cc7822c834c239593b6e142a694aa00c757b0db79e5e8", + "y": "0x01558b16d396d866e476e001f2dd0758927655450b84e12f154032c7c2a6db837942cd9f44b814f79b4d729996ced61eec61d85c675139cbffe3fbf071d2c21cfecb" + }, + "msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "u": [ + "0x0159871e222689aad7694dc4c3480a49807b1eedd9c8cb4ae1b219d5ba51655ea5b38e2e4f56b36bf3e3da44a7b139849d28f598c816fe1bc7ed15893b22f63363c3", + "0x004ef0cffd475152f3858c0a8ccbdf7902d8261da92744e98df9b7fadb0a5502f29c5086e76e2cf498f47321434a40b1504911552ce44ad7356a04e08729ad9411f5" + ] + }, + { + "P": { + "x": "0x00c12bc3e28db07b6b4d2a2b1167ab9e26fc2fa85c7b0498a17b0347edf52392856d7e28b8fa7a2dd004611159505835b687ecf1a764857e27e9745848c436ef3925", + "y": "0x01cd287df9a50c22a9231beb452346720bb163344a41c5f5a24e8335b6ccc595fd436aea89737b1281aecb411eb835f0b939073fdd1dd4d5a2492e91ef4a3c55bcbd" + }, + "Q0": { + "x": "0x00041f6eb92af8777260718e4c22328a7d74203350c6c8f5794d99d5789766698f459b83d5068276716f01429934e40af3d1111a22780b1e07e72238d2207e5386be", + "y": "0x001c712f0182813942b87cab8e72337db017126f52ed797dd234584ac9ae7e80dfe7abea11db02cf1855312eae1447dbaecc9d7e8c880a5e76a39f6258074e1bc2e0" + }, + "Q1": { + "x": "0x0125c0b69bcf55eab49280b14f707883405028e05c927cd7625d4e04115bd0e0e6323b12f5d43d0d6d2eff16dbcf244542f84ec058911260dc3bb6512ab5db285fbd", + "y": "0x008bddfb803b3f4c761458eb5f8a0aee3e1f7f68e9d7424405fa69172919899317fb6ac1d6903a432d967d14e0f80af63e7035aaae0c123e56862ce969456f99f102" + }, + "msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "u": [ + "0x0033d06d17bc3b9a3efc081a05d65805a14a3050a0dd4dfb4884618eb5c73980a59c5a246b18f58ad022dd3630faa22889fbb8ba1593466515e6ab4aeb7381c26334", + "0x0092290ab99c3fea1a5b8fb2ca49f859994a04faee3301cefab312d34227f6a2d0c3322cf76861c6a3683bdaa2dd2a6daa5d6906c663e065338b2344d20e313f1114" + ] + } + ] +} diff --git a/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/curve25519_XMD-SHA-512_ELL2_RO_.json b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/curve25519_XMD-SHA-512_ELL2_RO_.json new file mode 100644 index 0000000000..10c953936c --- /dev/null +++ b/core/src/test/resources/org/bouncycastle/crypto/hash2curve/test/curve25519_XMD-SHA-512_ELL2_RO_.json @@ -0,0 +1,115 @@ +{ + "L": "0x30", + "Z": "0x2", + "ciphersuite": "curve25519_XMD:SHA-512_ELL2_RO_", + "curve": "curve25519", + "dst": "QUUX-V01-CS02-with-curve25519_XMD:SHA-512_ELL2_RO_", + "expand": "XMD", + "field": { + "m": "0x1", + "p": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" + }, + "hash": "sha512", + "k": "0x80", + "map": { + "name": "ELL2" + }, + "randomOracle": true, + "vectors": [ + { + "P": { + "x": "0x2de3780abb67e861289f5749d16d3e217ffa722192d16bbd9d1bfb9d112b98c0", + "y": "0x3b5dc2a498941a1033d176567d457845637554a2fe7a3507d21abd1c1bd6e878" + }, + "Q0": { + "x": "0x36b4df0c864c64707cbf6cf36e9ee2c09a6cb93b28313c169be29561bb904f98", + "y": "0x6cd59d664fb58c66c892883cd0eb792e52055284dac3907dd756b45d15c3983d" + }, + "Q1": { + "x": "0x3fa114783a505c0b2b2fbeef0102853c0b494e7757f2a089d0daae7ed9a0db2b", + "y": "0x76c0fe7fec932aaafb8eefb42d9cbb32eb931158f469ff3050af15cfdbbeff94" + }, + "msg": "", + "u": [ + "0x005fe8a7b8fef0a16c105e6cadf5a6740b3365e18692a9c05bfbb4d97f645a6a", + "0x1347edbec6a2b5d8c02e058819819bee177077c9d10a4ce165aab0fd0252261a" + ] + }, + { + "P": { + "x": "0x2b4419f1f2d48f5872de692b0aca72cc7b0a60915dd70bde432e826b6abc526d", + "y": "0x1b8235f255a268f0a6fa8763e97eb3d22d149343d495da1160eff9703f2d07dd" + }, + "Q0": { + "x": "0x16b3d86e056b7970fa00165f6f48d90b619ad618791661b7b5e1ec78be10eac1", + "y": "0x4ab256422d84c5120b278cbdfc4e1facc5baadffeccecf8ee9bf3946106d50ca" + }, + "Q1": { + "x": "0x7ec29ddbf34539c40adfa98fcb39ec36368f47f30e8f888cc7e86f4d46e0c264", + "y": "0x10d1abc1cae2d34c06e247f2141ba897657fb39f1080d54f09ce0af128067c74" + }, + "msg": "abc", + "u": [ + "0x49bed021c7a3748f09fa8cdfcac044089f7829d3531066ac9e74e0994e05bc7d", + "0x5c36525b663e63389d886105cee7ed712325d5a97e60e140aba7e2ce5ae851b6" + ] + }, + { + "P": { + "x": "0x68ca1ea5a6acf4e9956daa101709b1eee6c1bb0df1de3b90d4602382a104c036", + "y": "0x2a375b656207123d10766e68b938b1812a4a6625ff83cb8d5e86f58a4be08353" + }, + "Q0": { + "x": "0x71de3dadfe268872326c35ac512164850860567aea0e7325e6b91a98f86533ad", + "y": "0x26a08b6e9a18084c56f2147bf515414b9b63f1522e1b6c5649f7d4b0324296ec" + }, + "Q1": { + "x": "0x5704069021f61e41779e2ba6b932268316d6d2a6f064f997a22fef16d1eaeaca", + "y": "0x50483c7540f64fb4497619c050f2c7fe55454ec0f0e79870bb44302e34232210" + }, + "msg": "abcdef0123456789", + "u": [ + "0x6412b7485ba26d3d1b6c290a8e1435b2959f03721874939b21782df17323d160", + "0x24c7b46c1c6d9a21d32f5707be1380ab82db1054fde82865d5c9e3d968f287b2" + ] + }, + { + "P": { + "x": "0x096e9c8bae6c06b554c1ee69383bb0e82267e064236b3a30608d4ed20b73ac5a", + "y": "0x1eb5a62612cafb32b16c3329794645b5b948d9f8ffe501d4e26b073fef6de355" + }, + "Q0": { + "x": "0x7a94d45a198fb5daa381f45f2619ab279744efdd8bd8ed587fc5b65d6cea1df0", + "y": "0x67d44f85d376e64bb7d713585230cdbfafc8e2676f7568e0b6ee59361116a6e1" + }, + "Q1": { + "x": "0x30506fb7a32136694abd61b6113770270debe593027a968a01f271e146e60c18", + "y": "0x7eeee0e706b40c6b5174e551426a67f975ad5a977ee2f01e8e20a6d612458c3b" + }, + "msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "u": [ + "0x5e123990f11bbb5586613ffabdb58d47f64bb5f2fa115f8ea8df0188e0c9e1b5", + "0x5e8553eb00438a0bb1e7faa59dec6d8087f9c8011e5fb8ed9df31cb6c0d4ac19" + ] + }, + { + "P": { + "x": "0x1bc61845a138e912f047b5e70ba9606ba2a447a4dade024c8ef3dd42b7bbc5fe", + "y": "0x623d05e47b70e25f7f1d51dda6d7c23c9a18ce015fe3548df596ea9e38c69bf1" + }, + "Q0": { + "x": "0x02d606e2699b918ee36f2818f2bc5013e437e673c9f9b9cdc15fd0c5ee913970", + "y": "0x29e9dc92297231ef211245db9e31767996c5625dfbf92e1c8107ef887365de1e" + }, + "Q1": { + "x": "0x38920e9b988d1ab7449c0fa9a6058192c0c797bb3d42ac345724341a1aa98745", + "y": "0x24dcc1be7c4d591d307e89049fd2ed30aae8911245a9d8554bf6032e5aa40d3d" + }, + "msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "u": [ + "0x20f481e85da7a3bf60ac0fb11ed1d0558fc6f941b3ac5469aa8b56ec883d6d7d", + "0x017d57fd257e9a78913999a23b52ca988157a81b09c5442501d07fed20869465" + ] + } + ] +}