org.bouncycastle.crypto.signers.ECDSASigner Java Examples

The following examples show how to use org.bouncycastle.crypto.signers.ECDSASigner. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ECKeyPair.java    From WalletCordova with GNU Lesser General Public License v2.1 6 votes vote down vote up
@Override
public byte[] sign (byte[] hash) throws ValidationException
{
	if ( priv == null )
	{
		throw new ValidationException ("Need private key to sign");
	}
	ECDSASigner signer = new ECDSASigner (new HMacDSAKCalculator (new SHA256Digest ()));
	signer.init (true, new ECPrivateKeyParameters (priv, domain));
	BigInteger[] signature = signer.generateSignature (hash);
	ByteArrayOutputStream s = new ByteArrayOutputStream ();
	try
	{
		DERSequenceGenerator seq = new DERSequenceGenerator (s);
		seq.addObject (new ASN1Integer (signature[0]));
		seq.addObject (new ASN1Integer (signature[1]));
		seq.close ();
		return s.toByteArray ();
	}
	catch ( IOException e )
	{
	}
	return null;
}
 
Example #2
Source File: SECP256K1.java    From besu with Apache License 2.0 6 votes vote down vote up
private static boolean verifyDefault(
    final Bytes data, final Signature signature, final PublicKey pub) {
  final ECDSASigner signer = new ECDSASigner();
  final Bytes toDecode = Bytes.wrap(Bytes.of((byte) 4), pub.getEncodedBytes());
  final ECPublicKeyParameters params =
      new ECPublicKeyParameters(CURVE.getCurve().decodePoint(toDecode.toArrayUnsafe()), CURVE);
  signer.init(false, params);
  try {
    return signer.verifySignature(data.toArrayUnsafe(), signature.r, signature.s);
  } catch (final NullPointerException e) {
    // Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures. Those
    // signatures
    // are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
    return false;
  }
}
 
Example #3
Source File: ECKeyPair.java    From bop-bitcoin-client with Apache License 2.0 6 votes vote down vote up
@Override
public byte[] sign (byte[] hash) throws ValidationException
{
	if ( priv == null )
	{
		throw new ValidationException ("Need private key to sign");
	}
	ECDSASigner signer = new ECDSASigner (new HMacDSAKCalculator (new SHA256Digest ()));
	signer.init (true, new ECPrivateKeyParameters (priv, domain));
	BigInteger[] signature = signer.generateSignature (hash);
	ByteArrayOutputStream s = new ByteArrayOutputStream ();
	try
	{
		DERSequenceGenerator seq = new DERSequenceGenerator (s);
		seq.addObject (new ASN1Integer (signature[0]));
		seq.addObject (new ASN1Integer (signature[1]));
		seq.close ();
		return s.toByteArray ();
	}
	catch ( IOException e )
	{
	}
	return null;
}
 
Example #4
Source File: BouncyCastleCrypto.java    From fabric-api-archive with Apache License 2.0 6 votes vote down vote up
@Override
public byte[] sign(byte[] hash, byte[] privateKey) {
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
    signer.init(true, new ECPrivateKeyParameters(new BigInteger(privateKey), domain));
    BigInteger[] signature = signer.generateSignature(hash);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        DERSequenceGenerator seq = new DERSequenceGenerator(baos);
        seq.addObject(new ASN1Integer(signature[0]));
        seq.addObject(new ASN1Integer(toCanonicalS(signature[1])));
        seq.close();
        return baos.toByteArray();
    } catch (IOException e) {
        return new byte[0];
    }
}
 
Example #5
Source File: BouncyCastleCrypto.java    From fabric-api-archive with Apache License 2.0 6 votes vote down vote up
@Override
public boolean verify(byte[] hash, byte[] signature, byte[] publicKey) {
    ASN1InputStream asn1 = new ASN1InputStream(signature);
    try {
        ECDSASigner signer = new ECDSASigner();
        signer.init(false, new ECPublicKeyParameters(curve.getCurve().decodePoint(publicKey), domain));

        DLSequence seq = (DLSequence) asn1.readObject();
        BigInteger r = ((ASN1Integer) seq.getObjectAt(0)).getPositiveValue();
        BigInteger s = ((ASN1Integer) seq.getObjectAt(1)).getPositiveValue();
        return signer.verifySignature(hash, r, s);
    } catch (Exception e) {
        return false;
    } finally {
        try {
            asn1.close();
        } catch (IOException ignored) {
        }
    }
}
 
Example #6
Source File: BouncyCastleCrypto.java    From fabric-api with Apache License 2.0 6 votes vote down vote up
@Override
public byte[] sign(byte[] hash, byte[] privateKey) {
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
    signer.init(true, new ECPrivateKeyParameters(new BigInteger(privateKey), domain));
    BigInteger[] signature = signer.generateSignature(hash);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        DERSequenceGenerator seq = new DERSequenceGenerator(baos);
        seq.addObject(new ASN1Integer(signature[0]));
        seq.addObject(new ASN1Integer(toCanonicalS(signature[1])));
        seq.close();
        return baos.toByteArray();
    } catch (IOException e) {
        return new byte[0];
    }
}
 
Example #7
Source File: BouncyCastleCrypto.java    From fabric-api with Apache License 2.0 6 votes vote down vote up
@Override
public boolean verify(byte[] hash, byte[] signature, byte[] publicKey) {
    ASN1InputStream asn1 = new ASN1InputStream(signature);
    try {
        ECDSASigner signer = new ECDSASigner();
        signer.init(false, new ECPublicKeyParameters(curve.getCurve().decodePoint(publicKey), domain));

        DLSequence seq = (DLSequence) asn1.readObject();
        BigInteger r = ((ASN1Integer) seq.getObjectAt(0)).getPositiveValue();
        BigInteger s = ((ASN1Integer) seq.getObjectAt(1)).getPositiveValue();
        return signer.verifySignature(hash, r, s);
    } catch (Exception e) {
        return false;
    } finally {
        try {
            asn1.close();
        } catch (IOException ignored) {
        }
    }
}
 
Example #8
Source File: NamedCurve.java    From UAF with Apache License 2.0 5 votes vote down vote up
public static boolean verifyUsingSecp256k1(byte[] pub, byte[] dataForSigning,
		BigInteger[] rs) throws Exception {
	ECDSASigner signer = new ECDSASigner();
	X9ECParameters params = SECNamedCurves.getByName("secp256k1");
	ECDomainParameters ecParams = new ECDomainParameters(params.getCurve(),
			params.getG(), params.getN(), params.getH());
	ECPublicKeyParameters pubKeyParams = new ECPublicKeyParameters(ecParams
			.getCurve().decodePoint(pub), ecParams);
	signer.init(false, pubKeyParams);

	return signer.verifySignature(dataForSigning, rs[0].abs(), rs[1].abs());
}
 
Example #9
Source File: ECKeyPair.java    From web3sdk with Apache License 2.0 5 votes vote down vote up
/**
 * Verify a hash with the private key of this key pair.
 *
 * @param hash
 * @param signature
 * @return
 */
public boolean verify(byte[] hash, ECDSASignature signature) {
    ECDSASigner signer = new ECDSASigner();
    // not for signing...
    signer.init(
            false,
            new ECPublicKeyParameters(
                    Sign.publicPointFromPrivate(getPrivateKey()), Sign.CURVE));
    return signer.verifySignature(hash, signature.r, signature.s);
}
 
Example #10
Source File: ECKeyPair.java    From web3j with Apache License 2.0 5 votes vote down vote up
/**
 * Sign a hash with the private key of this key pair.
 *
 * @param transactionHash the hash to sign
 * @return An {@link ECDSASignature} of the hash
 */
public ECDSASignature sign(byte[] transactionHash) {
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));

    ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKey, Sign.CURVE);
    signer.init(true, privKey);
    BigInteger[] components = signer.generateSignature(transactionHash);

    return new ECDSASignature(components[0], components[1]).toCanonicalised();
}
 
Example #11
Source File: NamedCurve.java    From UAF with Apache License 2.0 5 votes vote down vote up
/**
 * UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_RAW 0x01 An ECDSA signature on the
 * NIST secp256r1 curve which MUST have raw R and S buffers, encoded in
 * big-endian order. I.e. [R (32 bytes), S (32 bytes)]
 * 
 * @param priv
 *            - Private key
 * @param input
 *            - Data to sign
 * @return BigInteger[] - [R,S]
 */
public static BigInteger[] signAndFromatToRS(PrivateKey priv, byte[] input) {
	X9ECParameters params = SECNamedCurves.getByName("secp256r1");
	ECDomainParameters ecParams = new ECDomainParameters(params.getCurve(),
			params.getG(), params.getN(), params.getH());
	if (priv == null)
		throw new IllegalStateException(
				"This ECKey does not have the private key necessary for signing.");
	ECDSASigner signer = new ECDSASigner();
	ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
			((ECPrivateKey) priv).getS(), ecParams);
	signer.init(true, privKey);
	BigInteger[] sigs = signer.generateSignature(input);
	return sigs;
}
 
Example #12
Source File: NamedCurve.java    From UAF with Apache License 2.0 5 votes vote down vote up
public static boolean verify(byte[] pub, byte[] dataForSigning,
		BigInteger[] rs) throws Exception {
	ECDSASigner signer = new ECDSASigner();
	X9ECParameters params = SECNamedCurves.getByName("secp256r1");
	ECDomainParameters ecParams = new ECDomainParameters(params.getCurve(),
			params.getG(), params.getN(), params.getH());
	ECPublicKeyParameters pubKeyParams = new ECPublicKeyParameters(ecParams
			.getCurve().decodePoint(pub), ecParams);
	signer.init(false, pubKeyParams);

	return signer.verifySignature(dataForSigning, rs[0].abs(), rs[1].abs());
}
 
Example #13
Source File: ECKeyPair.java    From web3sdk with Apache License 2.0 5 votes vote down vote up
/**
 * Sign a hash with the private key of this key pair.
 *
 * @param hash the hash to sign
 * @return An {@link ECDSASignature} of the hash
 */
public ECDSASignature sign(byte[] hash) {

    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));

    ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKey, Sign.CURVE);
    signer.init(true, privKey);
    BigInteger[] components = signer.generateSignature(hash);

    return new ECDSASignature(components[0], components[1]).toCanonicalised();
}
 
Example #14
Source File: ECCurvePoint.java    From InflatableDonkey with MIT License 5 votes vote down vote up
public boolean verifySignature(byte[] message, BigInteger r, BigInteger s) {
    ECDomainParameters ecDomainParameters = ECAssistant.ecDomainParametersFrom(x9ECParameters);
    ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(Q, ecDomainParameters);

    ECDSASigner signer = new ECDSASigner();
    signer.init(false, ecPublicKeyParameters);

    return signer.verifySignature(message, r, s);
}
 
Example #15
Source File: ECKey.java    From bushido-java-core with GNU General Public License v3.0 5 votes vote down vote up
public byte[] sign(byte[] message) throws Exception
{
    if (priv == null) {
        throw new Exception("Unable to sign");
    }
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
    signer.init(true, new ECPrivateKeyParameters(priv, params));
    BigInteger[] signature = signer.generateSignature(message);
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    DERSequenceGenerator seqGen = new DERSequenceGenerator(outputStream);
    seqGen.addObject(new ASN1Integer(signature[0]));
    seqGen.addObject(new ASN1Integer(signature[1]));
    seqGen.close();
    return outputStream.toByteArray();
}
 
Example #16
Source File: ECKey.java    From bushido-java-core with GNU General Public License v3.0 5 votes vote down vote up
public boolean verify(byte[] message, byte[] signature) throws Exception
{
    ASN1InputStream asn1 = new ASN1InputStream(signature);
    ECDSASigner signer = new ECDSASigner();
    //not for signing...
    signer.init(false, new ECPublicKeyParameters(curve.getCurve().decodePoint(pub), params));
    DLSequence seq = (DLSequence) asn1.readObject();
    BigInteger r = ((ASN1Integer) seq.getObjectAt(0)).getPositiveValue();
    BigInteger s = ((ASN1Integer) seq.getObjectAt(1)).getPositiveValue();
    return signer.verifySignature(message, r, s);
}
 
Example #17
Source File: P12ContentSignerBuilder.java    From xipki with Apache License 2.0 5 votes vote down vote up
protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
    throws OperatorCreationException {
  if (!AlgorithmUtil.isECSigAlg(sigAlgId)) {
    throw new OperatorCreationException("the given algorithm is not a valid EC signature "
        + "algorithm '" + sigAlgId.getAlgorithm().getId() + "'");
  }

  Digest dig = digestProvider.get(digAlgId);
  ECDSASigner dsaSigner = new ECDSASigner();

  return plain ? new DSAPlainDigestSigner(dsaSigner, dig) : new DSADigestSigner(dsaSigner, dig);
}
 
Example #18
Source File: K256KeyPair.java    From jingtum-lib-java with MIT License 5 votes vote down vote up
private static ECDSASignature createECDSASignature(byte[] hash, BigInteger secret) {
	ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
	ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(secret, SECP256K1.params());
	signer.init(true, privKey);
	BigInteger[] sigs = signer.generateSignature(hash);
	BigInteger r = sigs[0], s = sigs[1];
	BigInteger otherS = SECP256K1.order().subtract(s);
	if (s.compareTo(otherS) == 1) {
		s = otherS;
	}
	return new ECDSASignature(r, s);
}
 
Example #19
Source File: K256KeyPair.java    From jingtum-lib-java with MIT License 5 votes vote down vote up
public static boolean verify(byte[] data, byte[] sigBytes, BigInteger pub) {
	ECDSASignature signature = ECDSASignature.decodeFromDER(sigBytes);
	if (signature == null) {
		return false;
	}
	ECDSASigner signer = new ECDSASigner();
	ECPoint pubPoint = SECP256K1.curve().decodePoint(pub.toByteArray());
	ECPublicKeyParameters params = new ECPublicKeyParameters(pubPoint, SECP256K1.params());
	signer.init(false, params);
	return signer.verifySignature(data, signature.r, signature.s);
}
 
Example #20
Source File: Ts3Crypt.java    From ts3j with Apache License 2.0 5 votes vote down vote up
public static byte[] createSignature(BigInteger privateKey, byte[] data) {
    DSADigestSigner signer = new DSADigestSigner(new ECDSASigner(), new SHA256Digest());
    ECPrivateKeyParameters signingKey = new ECPrivateKeyParameters(privateKey, getDomainParameters());

    signer.init(true, signingKey);
    signer.update(data, 0, data.length);

    return signer.generateSignature();
}
 
Example #21
Source File: Ts3Crypt.java    From ts3j with Apache License 2.0 5 votes vote down vote up
public static boolean verifySignature(ECPoint publicKey, byte[] data, byte[] signature) {
    DSADigestSigner signer = new DSADigestSigner(new ECDSASigner(), new SHA256Digest());
    ECPublicKeyParameters signingKey = new ECPublicKeyParameters(publicKey, getDomainParameters());

    signer.init(false, signingKey);
    signer.update(data, 0, data.length);

    return signer.verifySignature(signature);
}
 
Example #22
Source File: ECKey.java    From nuls-v2 with MIT License 5 votes vote down vote up
/**
 * <p>Verifies the given ECDSA signature against the message bytes using the public key bytes.</p>
 *
 * <p>When using native ECDSA verification, data must be 32 bytes, and no element may be
 * larger than 520 bytes.</p>
 *
 * @param data      Hash of the data to verify.
 * @param signature ASN.1 encoded signature.
 * @param pub       The public key bytes to use.
 */
public static boolean verify(byte[] data, ECDSASignature signature, byte[] pub) {
    ECDSASigner signer = new ECDSASigner();
    ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE);
    signer.init(false, params);
    try {
        return signer.verifySignature(data, signature.r, signature.s);
    } catch (NullPointerException e) {
        log.error("Caught NPE inside bouncy castle", e);
        return false;
    }
}
 
Example #23
Source File: ECKey.java    From nuls-v2 with MIT License 5 votes vote down vote up
/**
 * 用私钥对数据进行签名
 *
 * @param input                需签名数据
 * @param privateKeyForSigning 私钥
 * @return byte[] 签名
 */
protected byte[] doSign(byte[] input, BigInteger privateKeyForSigning) {
    HexUtil.checkNotNull(privateKeyForSigning);
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
    ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeyForSigning, CURVE);
    signer.init(true, privKey);
    BigInteger[] components = signer.generateSignature(input);
    return new ECDSASignature(components[0], components[1]).toCanonicalised().encodeToDER();
}
 
Example #24
Source File: SECP256K1.java    From cava with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies the given ECDSA signature against the message bytes using the public key bytes.
 *
 * @param hash The keccak256 hash of the data to verify.
 * @param signature The signature.
 * @param publicKey The public key.
 * @return True if the verification is successful.
 */
public static boolean verifyHashed(byte[] hash, Signature signature, PublicKey publicKey) {
  ECDSASigner signer = new ECDSASigner();
  Bytes toDecode = Bytes.wrap(Bytes.of((byte) 4), publicKey.bytes());
  ECPublicKeyParameters params =
      new ECPublicKeyParameters(Parameters.CURVE.getCurve().decodePoint(toDecode.toArray()), Parameters.CURVE);
  signer.init(false, params);
  try {
    return signer.verifySignature(hash, signature.r, signature.s);
  } catch (NullPointerException e) {
    // Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures. Those signatures
    // are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
    return false;
  }
}
 
Example #25
Source File: ECKeyPair.java    From etherscan-explorer with GNU General Public License v3.0 5 votes vote down vote up
/**
 * Sign a hash with the private key of this key pair.
 * @param transactionHash   the hash to sign
 * @return  An {@link ECDSASignature} of the hash
 */
public ECDSASignature sign(byte[] transactionHash) {
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));

    ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKey, Sign.CURVE);
    signer.init(true, privKey);
    BigInteger[] components = signer.generateSignature(transactionHash);

    return new ECDSASignature(components[0], components[1]).toCanonicalised();
}
 
Example #26
Source File: ECKeyPair.java    From client-sdk-java with Apache License 2.0 5 votes vote down vote up
/**
 * Sign a hash with the private key of this key pair.
 * @param transactionHash   the hash to sign
 * @return  An {@link ECDSASignature} of the hash
 */
public ECDSASignature sign(byte[] transactionHash) {
    ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));

    ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKey, Sign.CURVE);
    signer.init(true, privKey);
    BigInteger[] components = signer.generateSignature(transactionHash);

    return new ECDSASignature(components[0], components[1]).toCanonicalised();
}
 
Example #27
Source File: ECKey.java    From javasdk with GNU Lesser General Public License v3.0 5 votes vote down vote up
/**
 * <p>Verifies the given ECDSA signature against the message bytes using the public key bytes.</p>
 * <p>
 * <p>When using native ECDSA verification, data must be 32 bytes, and no element may be
 * larger than 520 bytes.</p>
 *
 * @param data      Hash of the data to verify.
 * @param signature signature.
 * @param pub       The public key bytes to use.
 * @return -
 */
public static boolean verify(byte[] data, ECDSASignature signature, byte[] pub) {
    ECDSASigner signer = new ECDSASigner();
    ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE);
    signer.init(false, params);
    try {
        return signer.verifySignature(data, signature.r, signature.s);
    } catch (NullPointerException npe) {
        // Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures.
        // Those signatures are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
        logger.error("Caught NPE inside bouncy castle, " + npe);
        return false;
    }
}
 
Example #28
Source File: SECP256K1.java    From besu with Apache License 2.0 5 votes vote down vote up
private static Signature signDefault(final Bytes32 dataHash, final KeyPair keyPair) {
  final ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));

  final ECPrivateKeyParameters privKey =
      new ECPrivateKeyParameters(
          keyPair.getPrivateKey().getEncodedBytes().toUnsignedBigInteger(), CURVE);
  signer.init(true, privKey);

  final BigInteger[] components = signer.generateSignature(dataHash.toArrayUnsafe());

  return normaliseSignature(components[0], components[1], keyPair.getPublicKey(), dataHash);
}
 
Example #29
Source File: SECP256K1.java    From incubator-tuweni with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies the given ECDSA signature against the message bytes using the public key bytes.
 *
 * @param hash The keccak256 hash of the data to verify.
 * @param signature The signature.
 * @param publicKey The public key.
 * @return True if the verification is successful.
 */
public static boolean verifyHashed(byte[] hash, Signature signature, PublicKey publicKey) {
  ECDSASigner signer = new ECDSASigner();
  Bytes toDecode = Bytes.wrap(Bytes.of((byte) 4), publicKey.bytes());
  ECPublicKeyParameters params =
      new ECPublicKeyParameters(Parameters.CURVE.getCurve().decodePoint(toDecode.toArray()), Parameters.CURVE);
  signer.init(false, params);
  try {
    return signer.verifySignature(hash, signature.r, signature.s);
  } catch (NullPointerException e) {
    // Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures. Those signatures
    // are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
    return false;
  }
}
 
Example #30
Source File: SECP256K1.java    From incubator-tuweni with Apache License 2.0 4 votes vote down vote up
/**
 * Generates an ECDSA signature.
 *
 * @param hash The keccak256 hash of the data to sign.
 * @param keyPair The keypair to sign using.
 * @return The signature.
 */
public static Signature signHashed(Bytes32 hash, KeyPair keyPair) {
  ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));

  ECPrivateKeyParameters privKey =
      new ECPrivateKeyParameters(keyPair.secretKey().bytes().toUnsignedBigInteger(), Parameters.CURVE);
  signer.init(true, privKey);

  BigInteger[] components = signer.generateSignature(hash.toArrayUnsafe());
  BigInteger r = components[0];
  BigInteger s = components[1];

  // Automatically adjust the S component to be less than or equal to half the curve
  // order, if necessary. This is required because for every signature (r,s) the signature
  // (r, -s (mod N)) is a valid signature of the same message. However, we dislike the
  // ability to modify the bits of a Bitcoin transaction after it's been signed, as that
  // violates various assumed invariants. Thus in future only one of those forms will be
  // considered legal and the other will be banned.
  if (s.compareTo(Parameters.HALF_CURVE_ORDER) > 0) {
    // The order of the curve is the number of valid points that exist on that curve.
    // If S is in the upper half of the number of valid points, then bring it back to
    // the lower half. Otherwise, imagine that:
    //   N = 10
    //   s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions.
    //   10 - 8 == 2, giving us always the latter solution, which is canonical.
    s = Parameters.CURVE_ORDER.subtract(s);
  }

  // Now we have to work backwards to figure out the recovery id needed to recover the signature.
  // On this curve, there are only two possible values for the recovery id.
  int recId = -1;
  BigInteger publicKeyBI = keyPair.publicKey().bytes().toUnsignedBigInteger();
  for (int i = 0; i < 2; i++) {
    BigInteger k = recoverFromSignature(i, r, s, hash);
    if (k != null && k.equals(publicKeyBI)) {
      recId = i;
      break;
    }
  }
  if (recId == -1) {
    // this should never happen
    throw new RuntimeException("Unexpected error - could not construct a recoverable key.");
  }

  byte v = (byte) recId;
  return new Signature(v, r, s);
}