arnaucube
arnaucube/blindsecp256k1-jsPublic Self-hosted repository
blindsecp256k1-js/src/index.js
src/index.jsRaw
  1var crypto = require('crypto');
  2var BigInteger = require('bigi')
  3var ecurve = require('ecurve')
  4const {keccak256} = require("@ethersproject/keccak256");
  5
  6const ecparams = ecurve.getCurveByName('secp256k1');
  7const G = ecparams.G;
  8const n = ecparams.n;
  9
 10function newBigFromString(s) {
 11    var a = new BigInteger()
 12    a.fromString(s)
 13    return a;
 14}
 15
 16function random(bytes){
 17    do {
 18	var k = BigInteger.fromByteArrayUnsigned(crypto.randomBytes(bytes));
 19    } while (k.toString() == "0" && k.gcd(n).toString() != "1")
 20    return k;
 21}
 22
 23function newKeyPair() {
 24    const sk = random(32);
 25    return {sk: sk, pk: G.multiply(sk)};
 26}
 27
 28function newRequestParameters() {
 29    const k = random(32);
 30    return {k: k, signerR: G.multiply(k)};
 31}
 32
 33/**
 34 * Blinds the message for the signer R.
 35 * @param {BigInteger} m
 36 * @param {Point} signerR
 37 * @returns {struct} {mBlinded: BigInteger, userSecretData: {a: BigInteger, b: BigInteger, f: Point}}
 38 */
 39function blind(m, signerR) {
 40    let u = {a: BigInteger.ZERO, b: BigInteger.ZERO, f: G};
 41    u.a = random(32);
 42    u.b = random(32);
 43
 44    const aR = signerR.multiply(u.a);
 45    const bG = G.multiply(u.b);
 46    u.f = aR.add(bG);
 47
 48    const rx = u.f.affineX.mod(n);
 49
 50    const ainv = u.a.modInverse(n);
 51    const ainvrx = ainv.multiply(rx);
 52
 53    const mHex = m.toString(16);
 54    const hHex = keccak256('0x' + mHex);
 55    const h = BigInteger.fromHex(hHex.slice(2));
 56    const mBlinded = ainvrx.multiply(h);
 57
 58    return {mBlinded: mBlinded.mod(n), userSecretData: u};
 59}
 60
 61function blindSign(sk, mBlinded, k) {
 62    let sBlind = sk.multiply(mBlinded);
 63    sBlind = sBlind.add(k);
 64    return sBlind.mod(n);
 65}
 66
 67/**
 68 * Unblinds the blinded signature.
 69 * @param {BigInteger} sBlind - blinded signature
 70 * @param {a: BigInteger, b: BigInteger, f: Point} - userSecretData
 71 * @returns {s: BigInteger, f: Point} - unblinded signature
 72 */
 73function unblind(sBlind, userSecretData) {
 74    const s = userSecretData.a.multiply(sBlind).add(userSecretData.b);
 75    return {s: s.mod(n), f: userSecretData.f};
 76}
 77
 78function verify(m, s, q) {
 79    const sG = G.multiply(s.s);
 80
 81    const mHex = m.toString(16);
 82    const hHex = keccak256('0x' + mHex);
 83    const h = BigInteger.fromHex(hHex.slice(2));
 84
 85    const rx = s.f.affineX.mod(n);
 86    const right = s.f.add(
 87	q.multiply(
 88	    rx.multiply(h)
 89	)
 90    );
 91
 92    if ((sG.affineX.toString() == right.affineX.toString())
 93	&& (sG.affineY.toString() == right.affineY.toString())) {
 94	return true;
 95    }
 96    return false;
 97}
 98
 99
100module.exports = {
101    newBigFromString: newBigFromString,
102    ecparams: ecparams,
103    newKeyPair: newKeyPair,
104    newRequestParameters: newRequestParameters,
105    blind: blind,
106    blindSign: blindSign,
107    unblind: unblind,
108    verify: verify
109}