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

io.eosif.lib.ecc.Ecdsa Maven / Gradle / Ivy

package io.eosif.lib.ecc;

import io.eosif.lib.utils.ByteUtils;
import io.eosif.lib.utils.EException;
import io.eosif.lib.utils.Hex;
import io.eosif.lib.utils.Sha;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;


/**
 * Ecdsa
 * 
 * @author espritblock http://eblock.io
 *
 */
public class Ecdsa {

	Secp256k curve = null;

	public Ecdsa(Secp256k curve) {
		this.curve = curve;
	}

	/**
	 * sign
	 * 
	 * @param dataHash
	 * @param d
	 * @param nonce
	 * @return
	 */
	public SignBigInt sign(String dataHash, BigInteger d, int nonce) {
		BigInteger n = curve.n();
		SignBigInt big = new SignBigInt();
		deterministicGenerateK(curve, dataHash, d, nonce, big);
		BigInteger N_OVER_TWO = n.shiftRight(1);
		if (big.getS().compareTo(N_OVER_TWO) > 0) {
			big.setS(n.subtract(big.getS()));
		}
		big.setDer(toDER(big));
		return big;
	}

	/**
	 * toDER
	 * 
	 * @param big
	 * @return
	 */
	private byte[] toDER(SignBigInt big) {
		byte[] rBa = big.getR().toByteArray();
		byte[] sBa = big.getS().toByteArray();
		ArrayList sequence = new ArrayList();
		sequence.add(new Byte(((byte) 0x02)));
		sequence.add(new Byte(((byte) rBa.length)));
		for (int i = 0; i < rBa.length; i++) {
			sequence.add(rBa[i]);
		}
		sequence.add(new Byte(((byte) 0x02)));
		sequence.add(new Byte(((byte) sBa.length)));
		for (int i = 0; i < sBa.length; i++) {
			sequence.add(sBa[i]);
		}
		int len = sequence.size();
		sequence.add(0, (byte) 0x30);
		sequence.add(1, (byte) len);
		byte[] bf = new byte[sequence.size()];
		for (int i = 0; i < bf.length; i++) {
			bf[i] = sequence.get(i).byteValue();
		}
		return bf;
	}

	private BigInteger deterministicGenerateK(Secp256k curve, String dataHash, BigInteger d, int nonce,
			SignBigInt big) {
		byte[] hash = Hex.hexStringToBytes(dataHash);
		if (nonce > 0) {
			hash = Sha.SHA256(ByteUtils.concat(hash, new byte[nonce]));
		}
		byte[] x = null;
		if (d.toByteArray()[0] == 0) {
			x = ByteUtils.copy(d.toByteArray(), 1, d.toByteArray().length - 1);
		} else {
			x = d.toByteArray();
		}
		// int padding = d.toByteArray().length-tmp.length;
		// byte[] zeros = null;
		// if(padding>0) {
		// zeros = new byte[padding];
		// for(int i =0;i= 0 || !check) {
			k = Sha.HmacSHA256(ByteUtils.concat(v, new byte[] { 0 }), k);
			v = Sha.HmacSHA256(v, k);
			v = Sha.HmacSHA256(v, k);
			T = new BigInteger(v);
		}

		big.setK(T);
		return T;
	}

	/**
	 * checkSig
	 * 
	 * @param k
	 * @param d
	 * @param e
	 * @param big
	 * @return
	 */
	public Boolean checkSig(BigInteger k, BigInteger d, BigInteger e, SignBigInt big) {
		Point Q = curve.G().multiply(k);
		if (Q.isInfinity())
			return false;
		BigInteger r = Q.getX().toBigInteger().mod(curve.n());
		big.setR(r);
		if (r.signum() == 0)
			return false;
		BigInteger s = k.modInverse(curve.n()).multiply(e.add(d.multiply(r))).mod(curve.n());
		big.setS(s);
		if (s.signum() == 0)
			return false;
		return true;
	}

	/**
	 * 
	 * @author espritblock http://eblock.io
	 *
	 */
	public static class SignBigInt {
		private BigInteger k;
		private BigInteger r;
		private BigInteger s;
		private byte[] der;

		public BigInteger getK() {
			return k;
		}

		public void setK(BigInteger k) {
			this.k = k;
		}

		public BigInteger getR() {
			return r;
		}

		public void setR(BigInteger r) {
			this.r = r;
		}

		public BigInteger getS() {
			return s;
		}

		public void setS(BigInteger s) {
			this.s = s;
		}

		public byte[] getDer() {
			return der;
		}

		public void setDer(byte[] der) {
			this.der = der;
		}
	}

	public int calcPubKeyRecoveryParam(BigInteger e, SignBigInt sign, Point Q) {
		for (int i = 0; i < 4; i++) {
			Point Qprime = recoverPubKey(e, sign, i);
			if (Qprime.equals(Q)) {
				return i;
			}
		}
		throw new EException("sign_error", "Unable to find valid recovery factor");
	}

	public Point recoverPubKey(BigInteger e, SignBigInt big, int i) {

		BigInteger n = curve.n();
		Point G = curve.G();

		BigInteger r = big.getR();
		BigInteger s = big.getS();

		if (!(r.signum() > 0 && r.compareTo(n) < 0)) {
			throw new EException("recover_pubkey_error", "Invalid r value");
		}
		if (!(s.signum() > 0 && s.compareTo(n) < 0)) {
			throw new EException("recover_pubkey_error", "Invalid r value");
		}

		// A set LSB signifies that the y-coordinate is odd
		int isYOdd = i & 1;

		// The more significant bit specifies whether we should use the
		// first or second candidate key.
		int isSecondKey = i >> 1;

		// 1.1 Let x = r + jn
		BigInteger x = isSecondKey == 1 ? r.add(n) : r;

		Point R = curve.getCurve().pointFromX(isYOdd, x);

		// // 1.4 Check that nR is at infinity
		Point nR = R.multiply(n);

		if (!nR.isInfinity()) {
			throw new EException("sign_error", "nR is not a valid curve point");
		}

		BigInteger eNeg = e.negate().mod(n);

		BigInteger rInv = r.modInverse(n);

		Point Q = R.multiplyTwo(s, G, eNeg).multiply(rInv);

		if (Q.isInfinity()) {
			throw new EException("sign_error", "Point is at infinity");
		}

		return Q;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy