Coverage Summary for Class: Secp256k1ServiceNative (org.ethereum.crypto.signature)

Class Class, % Method, % Line, %
Secp256k1ServiceNative 0% (0/1) 0% (0/6) 0% (0/32)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2020 RSK Labs Ltd. 4  * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>) 5  * 6  * This program is free software: you can redistribute it and/or modify 7  * it under the terms of the GNU Lesser General Public License as published by 8  * the Free Software Foundation, either version 3 of the License, or 9  * (at your option) any later version. 10  * 11  * This program is distributed in the hope that it will be useful, 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14  * GNU Lesser General Public License for more details. 15  * 16  * You should have received a copy of the GNU Lesser General Public License 17  * along with this program. If not, see <http://www.gnu.org/licenses/>. 18  */ 19  20 package org.ethereum.crypto.signature; 21  22 import org.bitcoin.NativeSecp256k1; 23 import org.bitcoin.NativeSecp256k1Exception; 24 import org.ethereum.crypto.ECKey; 25 import org.slf4j.Logger; 26 import org.slf4j.LoggerFactory; 27  28 import javax.annotation.Nullable; 29  30 import static java.lang.System.arraycopy; 31  32 /** 33  * Implementation of SignatureService with Native library. 34  */ 35 public class Secp256k1ServiceNative extends Secp256k1ServiceBC { 36  37  private static final Logger logger = LoggerFactory.getLogger(Secp256k1ServiceNative.class); 38  private static final byte[] ZERO_PUB = {0}; 39  40  @Nullable 41  @Override 42  public ECKey recoverFromSignature(int recId, ECDSASignature sig, byte[] messageHash, boolean compressed) { 43  check(recId >= 0, "recId must be positive"); 44  check(sig.getR().signum() >= 0, "r must be positive"); 45  check(sig.getS().signum() >= 0, "s must be positive"); 46  check(messageHash != null, "messageHash must not be null"); 47  48  // to be compatible with BC implementation. and to prevent garbage in signature truncation when concatenate. 49  if (!sig.validateComponentsWithoutV()) { 50  return null; 51  } 52  53  byte[] pbKey; 54  try { 55  byte[] sigBytes = concatenate(sig); 56  logger.trace("Recovering key from signature: comporessed[{}] - recId[{}] - sig[{}] - msgHash[{}].", compressed, recId, sigBytes, messageHash); 57  try { 58  pbKey = NativeSecp256k1.ecdsaRecover(sigBytes, messageHash, recId, compressed); 59  } catch (NativeSecp256k1Exception e) { 60  if (NativeSecp256k1.isInfinity(sigBytes, messageHash, recId)) { 61  return ECKey.fromPublicOnly(ZERO_PUB); 62  } 63  throw e; 64  } 65  } catch (Exception e) { 66  logger.error("Couldnt recover key from signature.", e); 67  return null; 68  } 69  return ECKey.fromPublicOnly(pbKey); 70  } 71  72  /** 73  * Returns a (r.length + s.length) bytes array long 74  * <p> 75  * Note: we take 32 bytes from "r" and 32 bytes from "s". 76  * 77  * @param sig {r,s} 78  * @return r + s (64 length byte array) 79  */ 80  byte[] concatenate(ECDSASignature sig) { 81  byte[] rBytes = sig.getR().toByteArray(); 82  byte[] sBytes = sig.getS().toByteArray(); 83  byte[] result = new byte[64]; 84  int rLength = getLength(rBytes); 85  int sLength = getLength(sBytes); 86  arraycopy(rBytes, getStartIndex(rBytes), result, 32 - rLength, rLength); 87  arraycopy(sBytes, getStartIndex(sBytes), result, 64 - sLength, sLength); 88  return result; 89  } 90  91  /** 92  * Get the length of valid data to copy from the array, with a max of 32 bytes. 93  * 94  * @param rs 95  * @return 96  */ 97  private static final int getLength(byte[] rs) { 98  return Math.min(rs.length, 32); 99  } 100  101  /** 102  * If bytes length is greater than 32, we keep the last 32 bytes at the right. 103  * - So starting byte index will be = length - 32. 104  * If not 105  * - Starting byte index = 0. 106  * 107  * @param rs 108  * @return 109  */ 110  private static final int getStartIndex(byte[] rs) { 111  return Math.max(rs.length - 32, 0); 112  } 113 }