signer.init(true, privKeyParams); BigInteger[] components = signer.generateSignature(input); return new ECDSASignature(components[0], components[1]).toCanonicalised(); } else { try { ecSig.update(input); byte[] derSignature = ecSig.sign(); return ECDSASignature.decodeFromDER(derSignature) .toCanonicalised(); } catch (SignatureException | InvalidKeyException ex) { throw new RuntimeException("ECKey signing error", ex);
/** * Given a piece of text and a message signature encoded in base64, returns an ECKey * containing the public key that was used to sign it. This can then be compared to the expected public key to * determine if the signature was correct. * * @param messageHash a piece of human readable text that was signed * @param signatureBase64 The Ethereum-format message signature in base64 * * @return - * * @throws SignatureException If the public key could not be recovered or if there was a signature format error. */ public static byte[] signatureToKeyBytes(byte[] messageHash, String signatureBase64) throws SignatureException { byte[] signatureEncoded; try { signatureEncoded = Base64.decode(signatureBase64); } catch (RuntimeException e) { // This is what you get back from Bouncy Castle if base64 doesn't decode :( throw new SignatureException("Could not decode base64", e); } // Parse the signature bytes into r/s and the selector value. if (signatureEncoded.length < 65) { throw new SignatureException( "Signature truncated, expected 65 bytes and got " + signatureEncoded.length); } return signatureToKeyBytes(messageHash, ECDSASignature.fromComponents(Arrays.copyOfRange(signatureEncoded, 1, 33), Arrays.copyOfRange(signatureEncoded, 33, 65), (byte) (signatureEncoded[0] & 0xFF))); }
byte[] s = transaction.get(8) .getRLPData(); this.signature = ECDSASignature.fromComponents(r, s, getRealV(v)); } else { logger.info("RLP encoded tx is not signed!");
public static ECDSASignature decodeFromDER(byte[] bytes) { ASN1InputStream decoder = null; try { decoder = new ASN1InputStream(bytes); DLSequence seq = (DLSequence) decoder.readObject(); if (seq == null) throw new RuntimeException("Reached past end of ASN.1 stream."); ASN1Integer r, s; try { r = (ASN1Integer) seq.getObjectAt(0); s = (ASN1Integer) seq.getObjectAt(1); } catch (ClassCastException e) { throw new IllegalArgumentException(e); } // OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be // Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue()); } catch (IOException e) { throw new RuntimeException(e); } finally { if (decoder != null) { try { decoder.close(); } catch (IOException x) { } } } }
/** * Will 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 Ethereum 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. * * @return - */ public ECDSASignature toCanonicalised() { if (s.compareTo(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. return new ECDSASignature(r, CURVE.getN() .subtract(s)); } else { return this; } }
public String toHex() { return normalize(Hex.toHexString(toByteArray())); }
public boolean validateComponents() { return validateComponents(r, s, v); }
/** * @param r - * @param s - * @param v - * * @return - */ public static ECDSASignature fromComponents(byte[] r, byte[] s, byte v) { ECDSASignature signature = fromComponents(r, s); signature.v = v; return signature; }
/** * t * * @param r * @param s * * @return - */ private static ECDSASignature fromComponents(byte[] r, byte[] s) { return new ECDSASignature(new BigInteger(1, r), new BigInteger(1, s)); }
private byte[] createBalanceMsgHash(Address receiverAddress, BigInteger openBlockNumber, BigInteger owedBalance, ECKey senderECKey, Address channelManagerAddr) { byte[] balanceMsgHash = createBalanceMsgHashRaw(receiverAddress, openBlockNumber, owedBalance, channelManagerAddr); return senderECKey.sign(balanceMsgHash) .toByteArray(); }
private byte[] createClosingMsgHash(Address senderAddress, BigInteger openBlockNumber, BigInteger owedBalance, ECKey receiverECKey, Address channelManagerAddr) { byte[] closingMsgHash = createClosingMsgHashRaw(senderAddress, openBlockNumber, owedBalance, channelManagerAddr); return receiverECKey.sign(closingMsgHash) .toByteArray(); }
public Transaction(byte[] nonce, byte[] gasPrice, byte[] gasLimit, byte[] receiveAddress, byte[] value, byte[] data, byte[] r, byte[] s, byte v, Integer chainId) { this(nonce, gasPrice, gasLimit, receiveAddress, value, data, chainId); this.signature = ECDSASignature.fromComponents(r, s, v); }
/** * Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key. * * @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, byte[] signature, byte[] pub) { return verify(data, ECDSASignature.decodeFromDER(signature), pub); }