mirror of
https://github.com/arnaucube/blindsecp256k1-js.git
synced 2026-02-07 03:16:43 +01:00
Initial version that works
Includes the needed methods to do the full flow: - newKeyPair - newRequestParameters - blind - blindSign - unblind - verify
This commit is contained in:
109
src/index.js
Normal file
109
src/index.js
Normal file
@@ -0,0 +1,109 @@
|
||||
var crypto = require('crypto');
|
||||
var BigInteger = require('bigi')
|
||||
var ecurve = require('ecurve')
|
||||
const {keccak256} = require("@ethersproject/keccak256");
|
||||
|
||||
const ecparams = ecurve.getCurveByName('secp256k1');
|
||||
const G = ecparams.G;
|
||||
const n = ecparams.n;
|
||||
|
||||
function newBigFromString(s) {
|
||||
var a = new BigInteger()
|
||||
a.fromString(s)
|
||||
return a;
|
||||
}
|
||||
|
||||
function random(bytes){
|
||||
do {
|
||||
var k = BigInteger.fromByteArrayUnsigned(crypto.randomBytes(bytes));
|
||||
} while (k.toString() == "0" && k.gcd(n).toString() != "1")
|
||||
return k;
|
||||
}
|
||||
|
||||
function newKeyPair() {
|
||||
const sk = random(32);
|
||||
return {sk: sk, pk: G.multiply(sk)};
|
||||
}
|
||||
|
||||
function newRequestParameters() {
|
||||
const k = random(32);
|
||||
return {k: k, signerR: G.multiply(k)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Blinds the message for the signer R.
|
||||
* @param {BigInteger} m
|
||||
* @param {Point} signerR
|
||||
* @returns {struct} {mBlinded: BigInteger, userSecretData: {a: BigInteger, b: BigInteger, f: Point}}
|
||||
*/
|
||||
function blind(m, signerR) {
|
||||
let u = {a: BigInteger.ZERO, b: BigInteger.ZERO, f: G};
|
||||
u.a = random(32);
|
||||
u.b = random(32);
|
||||
|
||||
const aR = signerR.multiply(u.a);
|
||||
const bG = G.multiply(u.b);
|
||||
u.f = aR.add(bG);
|
||||
|
||||
const rx = u.f.affineX.mod(n);
|
||||
|
||||
const ainv = u.a.modInverse(n);
|
||||
const ainvrx = ainv.multiply(rx);
|
||||
|
||||
const mHex = m.toString(16);
|
||||
const hHex = keccak256('0x' + mHex);
|
||||
const h = BigInteger.fromHex(hHex.slice(2));
|
||||
const mBlinded = ainvrx.multiply(h);
|
||||
|
||||
return {mBlinded: mBlinded.mod(n), userSecretData: u};
|
||||
}
|
||||
|
||||
function blindSign(sk, mBlinded, k) {
|
||||
let sBlind = sk.multiply(mBlinded);
|
||||
sBlind = sBlind.add(k);
|
||||
return sBlind.mod(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblinds the blinded signature.
|
||||
* @param {BigInteger} sBlind - blinded signature
|
||||
* @param {a: BigInteger, b: BigInteger, f: Point} - userSecretData
|
||||
* @returns {s: BigInteger, f: Point} - unblinded signature
|
||||
*/
|
||||
function unblind(sBlind, userSecretData) {
|
||||
const s = userSecretData.a.multiply(sBlind).add(userSecretData.b);
|
||||
return {s: s.mod(n), f: userSecretData.f};
|
||||
}
|
||||
|
||||
function verify(m, s, q) {
|
||||
const sG = G.multiply(s.s);
|
||||
|
||||
const mHex = m.toString(16);
|
||||
const hHex = keccak256('0x' + mHex);
|
||||
const h = BigInteger.fromHex(hHex.slice(2));
|
||||
|
||||
const rx = s.f.affineX.mod(n);
|
||||
const right = s.f.add(
|
||||
q.multiply(
|
||||
rx.multiply(h)
|
||||
)
|
||||
);
|
||||
|
||||
if ((sG.affineX.toString() == right.affineX.toString())
|
||||
&& (sG.affineY.toString() == right.affineY.toString())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
newBigFromString: newBigFromString,
|
||||
ecparams: ecparams,
|
||||
newKeyPair: newKeyPair,
|
||||
newRequestParameters: newRequestParameters,
|
||||
blind: blind,
|
||||
blindSign: blindSign,
|
||||
unblind: unblind,
|
||||
verify: verify
|
||||
}
|
||||
Reference in New Issue
Block a user