function recoverPubKey(curve, e, signature, i) {
  assert.strictEqual(i & 3, i, 'Recovery param is more than two bits')

  var n = curve.n
  var G = curve.G

  var r = signature.r
  var s = signature.s

  assert(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value')
  assert(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value')

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

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

  // 1.1 Let x = r + jn
  var x = isSecondKey ? r.add(n) : r
  var R = curve.pointFromX(isYOdd, x)

  // 1.4 Check that nR is at infinity
  var nR = R.multiply(n)
  assert(curve.isInfinity(nR), 'nR is not a valid curve point')

  // Compute -e from e
  var eNeg = e.negate().mod(n)

  // 1.6.1 Compute Q = r^-1 (sR -  eG)
  //               Q = r^-1 (sR + -eG)
  var rInv = r.modInverse(n)

  var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv)
  curve.validate(Q)

  return Q
}
function recoverPubKey(curve, e, signature, i) {
  assert.strictEqual(i & 3, i, 'Recovery param is more than two bits')

  var n = curve.n
  var G = curve.G

  var r = signature.r
  var s = signature.s

  assert(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value')
  assert(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value')

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

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

  // 1.1 Let x = r + jn
  var x = isSecondKey ? r.add(n) : r
  var R = curve.pointFromX(isYOdd, x)

  // 1.4 Check that nR is at infinity
  var nR = R.multiply(n)
  assert(curve.isInfinity(nR), 'nR is not a valid curve point')

  // Compute -e from e
  var eNeg = e.negate().mod(n)

  // 1.6.1 Compute Q = r^-1 (sR -  eG)
  //               Q = r^-1 (sR + -eG)
  var rInv = r.modInverse(n)

  var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv)
  curve.validate(Q)

  return Q
}
function recoverPubKey ( curve , e , signature , i ) { assert . strictEqual ( i & 3 , i , 'Recovery param is more than two bits' ) var n = curve . n var G = curve . G var r = signature . r var s = signature . s assert ( r . signum ( ) > 0 && r . compareTo ( n ) < 0 , 'Invalid r value' ) assert ( s . signum ( ) > 0 && s . compareTo ( n ) < 0 , 'Invalid s value' ) // A set LSB signifies that the y-coordinate is odd var isYOdd = i & 1 // The more significant bit specifies whether we should use the // first or second candidate key. var isSecondKey = i >> 1 // 1.1 Let x = r + jn var x = isSecondKey ? r . add ( n ) : r var R = curve . pointFromX ( isYOdd , x ) // 1.4 Check that nR is at infinity var nR = R . multiply ( n ) assert ( curve . isInfinity ( nR ) , 'nR is not a valid curve point' ) // Compute -e from e var eNeg = e . negate ( ) . mod ( n ) // 1.6.1 Compute Q = r^-1 (sR -  eG) //               Q = r^-1 (sR + -eG) var rInv = r . modInverse ( n ) var Q = R . multiplyTwo ( s , G , eNeg ) . multiply ( rInv ) curve . validate ( Q ) return Q }
Recover a public key from a signature.

See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
Key Recovery Operation".

http://www.secg.org/download/aid-780/sec1-v2.pdf
Recover a public key from a signature .