Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance by using bcoin-org/bcrypto #29

Closed
faustbrian opened this issue Apr 12, 2022 · 5 comments
Closed

Improve performance by using bcoin-org/bcrypto #29

faustbrian opened this issue Apr 12, 2022 · 5 comments

Comments

@faustbrian
Copy link

faustbrian commented Apr 12, 2022

Hey, have you considered using https://github.com/bcoin-org/bcrypto to replace the functions in https://github.com/guggero/bip-schnorr/blob/master/src/schnorr.js? I would have to check if it is 100% compatible with the way BIP340 is implemented here but if it is you could gain a massive performance boost through it, especially for verification.

Code

const bench = require("micro-bmark");
const { schnorr: bcrypto } = require("bcrypto");
const BIP340 = require("bip-schnorr");

const { run, mark } = bench; // or bench.mark

const hash = Buffer.from("690a91fc0a7a49bbc5afe9516c1831ca8845f281ef2e414f7dfeb71b5e91a902", "hex");
const privateKey = Buffer.from("9aab9a93dace8454efd433a09bbf096d086926d2296a029b2bd545410d98ac0b", "hex");
const publicKey = Buffer.from("8178586544c1e6201123cee2ffb872ee368a45a79319511b7a2a5fb8143f9eb8", "hex");
const signature = Buffer.from(
	"0e0fba175b6bffe5dc2e62253a1e1d729e87a67eb56989c9c5e13eb5e9c682c1aad5ed4c3920ded1206fabe03a84bd33ae0b2119caa84c4ed769341b15ad60a4",
	"hex",
);

run(async () => {
	await mark("bcrypto#sign", () => {
		bcrypto.sign(hash, privateKey);
	});

	await mark("bcrypto#verify", () => {
		bcrypto.verify(hash, signature, publicKey);
	});

	await mark("BIP340#sign", () => {
		BIP340.sign(privateKey.toString("hex"), hash);
	});

	await mark("BIP340#verify", () => {
		BIP340.verify(publicKey, hash, signature);
	});

	bench.logMem();
	bench.getTime();
});

Result

bcrypto#sign x 98 ops/sec @ 10ms/op
bcrypto#verify x 11,605 ops/sec @ 86μs/op
BIP340#sign x 33 ops/sec @ 29ms/op
BIP340#verify x 37 ops/sec @ 26ms/op
@faustbrian
Copy link
Author

@faustbrian
Copy link
Author

faustbrian commented Apr 12, 2022

Looks like the vast majority of tests do pass with bcrypto. Only 18 fail, while 600 pass.

src/schnorr.js

const { schnorr: bcrypto } = require("bcrypto");
const check = require("./check");

function sign(privateKey, message) {
  check.checkSignParams(privateKey, message);

  if (typeof privateKey === "string") {
    privateKey = Buffer.from(privateKey, "hex");
  }

  return bcrypto.sign(message, privateKey);
}

function verify(pubKey, message, signature) {
  check.checkVerifyParams(pubKey, message, signature);

  return bcrypto.verify(message, signature, pubKey);
}

function batchVerify(pubKeys, messages, signatures) {
  check.checkBatchVerifyParams(pubKeys, messages, signatures);

  const batch = [];

  for (let i = 0; i < pubKeys.length; i++) {
    batch.push([messages[i], signatures[i], pubKeys[i]]);
  }

  return bcrypto.verifyBatch(batch);
}

module.exports = {
  sign,
  verify,
  batchVerify,
};

Tests

  600 passing (21s)
  18 failing

  1) edge cases
       sign
         can sign example code in README:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-edge-cases.spec.js:41:40)
      at processImmediate (node:internal/timers:464:21)

  2) random tests
       verify
         can verify 64 random messages with random keys:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-random-tests.spec.js:43:37)
      at processImmediate (node:internal/timers:464:21)

  3) random tests
       batchVerify
         can batch verify 64 random messages and signatures:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-random-tests.spec.js:74:37)
      at processImmediate (node:internal/timers:464:21)

  4) test vectors
       sign
         can sign 0000000000000000000000000000000000000000000000000000000000000003:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:22:34)
      at processImmediate (node:internal/timers:464:21)

  5) test vectors
       sign
         can sign B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:22:34)
      at processImmediate (node:internal/timers:464:21)

  6) test vectors
       sign
         can sign C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:22:34)
      at processImmediate (node:internal/timers:464:21)

  7) test vectors
       sign
         can sign 0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710:
     Error: Assertion failed
      at Object.sign (node_modules/bcrypto/lib/native/schnorr-libsecp256k1.js:312:3)
      at Object.sign (src/schnorr.js:2:81)
      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:22:34)
      at processImmediate (node:internal/timers:464:21)

  8) test vectors
       verify
         can verify public key not on the curve:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  9) test vectors
       verify
         can verify has_even_y(R) is false:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  10) test vectors
       verify
         can verify negated message:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  11) test vectors
       verify
         can verify negated s value:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  12) test vectors
       verify
         can verify sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  13) test vectors
       verify
         can verify sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  14) test vectors
       verify
         can verify sig[0:32] is not an X coordinate on the curve:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  15) test vectors
       verify
         can verify sig[0:32] is equal to field size:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  16) test vectors
       verify
         can verify sig[32:64] is equal to curve order:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  17) test vectors
       verify
         can verify public key is not a valid X coordinate because it exceeds the field size:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:51:18)
      at processImmediate (node:internal/timers:464:21)

  18) test vectors
       batchVerify
         fails on one invalid signature:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

true !== false

      + expected - actual

      -true
      +false

      at Context.<anonymous> (test/schnorr-test-vectors.spec.js:101:14)
      at processImmediate (node:internal/timers:464:21)

@guggero
Copy link
Owner

guggero commented Apr 12, 2022

It looks like the library doesn't support BIP340 x-only public keys. At least that's what I think from the test failures. But I'm happy to review a PR if you're able to get the tests working.

@faustbrian
Copy link
Author

Looking at https://github.com/bcoin-org/bcrypto/blob/master/lib/native/schnorr-libsecp256k1.js and searching for xonly it does seem to support them so will have to dig a bit where it fails.

@faustbrian
Copy link
Author

Looks like it would be more involved than just swapping some methods because bcrypto seems to not be 100% compliant with BIP340. Will fork instead and make changes as needed for my use-case as I don't need the parts that cause tests to fail. Thanks for the solid base!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants