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}