Code Monkey home page Code Monkey logo

Comments (6)

junderw avatar junderw commented on June 12, 2024

This library does not need recid, so there are no methods that return or calculate it.

The two bits of the recid are:

LSB = "is Y value for signature r point odd?"
MSB = "is X value for signature r point >= n (order)?"

MSB is almost always 0, so 99.9...% of recid will be integer of 0 or 1

from tiny-secp256k1.

junderw avatar junderw commented on June 12, 2024

To make it a little easier to understand, here's how it would be calculated in the current pure JS code.

ie. for the JS:

tiny-secp256k1/js.js

Lines 188 to 205 in 5a311f1

let r, s
const checkSig = function (k) {
const kI = fromBuffer(k)
const Q = G.mul(kI)
if (Q.isInfinity()) return false
r = Q.x.umod(n)
if (r.isZero() === 0) return false
s = kI
.invm(n)
.mul(e.add(d.mul(r)))
.umod(n)
if (s.isZero() === 0) return false
return true
}

diff --git a/js.js b/js.js
index 5e0fd45..6382476 100644
--- a/js.js
+++ b/js.js
@@ -185,7 +185,7 @@ function __sign (hash, x, addData) {
   const d = fromBuffer(x)
   const e = fromBuffer(hash)
 
-  let r, s
+  let r, s, recid
   const checkSig = function (k) {
     const kI = fromBuffer(k)
     const Q = G.mul(kI)
@@ -201,6 +201,10 @@ function __sign (hash, x, addData) {
       .umod(n)
     if (s.isZero() === 0) return false
 
+    const isOddY = Q.y.isOdd()
+    const isHighX = Q.x.cmp(n) >= 0
+    recid = (isHighX << 1) | (isOddY << 0)
+
     return true
   }
 
@@ -214,7 +218,10 @@ function __sign (hash, x, addData) {
   const buffer = Buffer.allocUnsafe(64)
   toBuffer(r).copy(buffer, 0)
   toBuffer(s).copy(buffer, 32)
-  return buffer
+  return {
+    signature: buffer,
+    recovery: recid,
+  }
 }
 
 function verify (hash, q, signature, strict) {

from tiny-secp256k1.

junderw avatar junderw commented on June 12, 2024

Also, in the verify function you recreate the R point, so you would be able to calculate the recid if you have the public key and the signature.

from tiny-secp256k1.

junderw avatar junderw commented on June 12, 2024

This is what it looks like to get the recid during the verify function.

diff --git a/js.js b/js.js
index 5e0fd45..58e4dc2 100644
--- a/js.js
+++ b/js.js
@@ -255,6 +255,10 @@ function verify (hash, q, signature, strict) {
   // 1.4.5 (cont.) Enforce R is not at infinity
   if (R.isInfinity()) return false
 
+  const isOddY = R.y.isOdd()
+  const isHighX = R.x.cmp(n) >= 0
+  const recid = (isHighX << 1) | (isOddY << 0)
+
   // 1.4.6 Convert the field element R.x to an integer
   const xR = R.x
 
@@ -262,7 +266,11 @@ function verify (hash, q, signature, strict) {
   const v = xR.umod(n)
 
   // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
-  return v.eq(r)
+  const isValid = v.eq(r)
+  return {
+    verified: isValid,
+    recovery: isValid ? recid : null,
+  }
 }
 
 module.exports = {

from tiny-secp256k1.

CodeForcer avatar CodeForcer commented on June 12, 2024

Thanks for your help @junderw. In particular your last example got me through my blocker on this. I will share my code for extending a BitcoinJs library signer into a BitcoinJs-message signer, in case it helps any other developers working on this particular issue:

export class BitcoinMessageSigner extends BitcoinSigner {
  sign(payload) {
    const signature = super.sign(payload, true)

    const recovery = this.recidFromSig(payload, this.publicKey, signature)

    return {
      signature,
      recovery,
    }
  }

  recidFromSig(payload, publicKey, signature) {
    const BN = require('bn.js')
    const secp256k1 = new ec('secp256k1')

    const n = secp256k1.curve.n
    const G = secp256k1.curve.g

    const Q = secp256k1.curve.decodePoint(publicKey)

    const r = new BN(signature.slice(0, 32))
    const s = new BN(signature.slice(32, 64))

    const e = new BN(payload)

    const sInv = s.invm(n)

    const u1 = e.mul(sInv).umod(n)
    const u2 = r.mul(sInv).umod(n)

    const R = G.mulAdd(u1, Q, u2)

    const isOddY = R.y.isOdd()
    const isHighX = R.x.cmp(n) >= 0
    const recid = (isHighX << 1) | (isOddY << 0)

    return recid
  }
}

I'm still code-cleaning, but the above example is working.

from tiny-secp256k1.

junderw avatar junderw commented on June 12, 2024

Be careful, as that is very slow.

You are using Signer because you have some sort of native implementation you're calling into, correct?

In which case you should get your native implementation to have a private method that returns the signature AND recid (in one go) and your key Signer class will throw away the recid and the message Signer class will keep it.

If not, and the private key is being managed in a Buffer in the JavaScript memory... then it is easier to just pass the privateKey Buffer to the message sign function.

from tiny-secp256k1.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.