@ -1,2 +1,3 @@ |
|||
node_modules |
|||
blindsecp256k1-browser.js |
|||
dist |
@ -1,109 +0,0 @@ |
|||
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 |
|||
} |
@ -0,0 +1,103 @@ |
|||
import { randomBytes } from 'crypto' |
|||
import * as BigInteger from 'bigi' |
|||
import { getCurveByName, Point } from 'ecurve' |
|||
import { keccak256 } from "@ethersproject/keccak256" |
|||
|
|||
const ecparams = getCurveByName('secp256k1') |
|||
const G = ecparams.G |
|||
const n = ecparams.n as BigInteger |
|||
|
|||
export { ecparams } |
|||
|
|||
export type UserSecretData = { a: BigInteger, b: BigInteger, f: Point } |
|||
export type UnblindedSignature = { s: BigInteger, f: Point } |
|||
|
|||
export function newBigFromString(s: string) { |
|||
let a = new BigInteger(null, null, null) |
|||
a.fromString(s, null) |
|||
return a |
|||
} |
|||
|
|||
function random(bytes: number) { |
|||
let k: BigInteger |
|||
do { |
|||
k = BigInteger.fromByteArrayUnsigned(randomBytes(bytes)) as unknown as BigInteger |
|||
} while (k.toString() == "0" && k.gcd(n).toString() != "1") |
|||
return k |
|||
} |
|||
|
|||
export function newKeyPair() { |
|||
const sk = random(32) |
|||
return { sk: sk, pk: G.multiply(sk) } |
|||
} |
|||
|
|||
export 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}} |
|||
*/ |
|||
export function blind(m: BigInteger, signerR: Point): { mBlinded: BigInteger, userSecretData: UserSecretData } { |
|||
const u: UserSecretData = { a: BigInteger.ZERO as BigInteger, b: BigInteger.ZERO as BigInteger, 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 as unknown as number) |
|||
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 } |
|||
} |
|||
|
|||
export function blindSign(sk: BigInteger, mBlinded: BigInteger, k: BigInteger): BigInteger { |
|||
let sBlind = sk.multiply(mBlinded) |
|||
sBlind = sBlind.add(k) |
|||
return sBlind.mod(n) |
|||
} |
|||
|
|||
/** |
|||
* Unblinds the blinded signature. |
|||
* @param blinded signature |
|||
* @param userSecretData |
|||
* @returns unblinded signature |
|||
*/ |
|||
export function unblind(sBlind: BigInteger, userSecretData: UserSecretData): UnblindedSignature { |
|||
const s = userSecretData.a.multiply(sBlind).add(userSecretData.b) |
|||
return { s: s.mod(n), f: userSecretData.f } |
|||
} |
|||
|
|||
export function verify(m: BigInteger, s: UnblindedSignature, q: Point) { |
|||
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 |
|||
} |
@ -1,39 +0,0 @@ |
|||
const assert = require('assert'); |
|||
const BigInteger = require('bigi'); |
|||
var {Point} = require('ecurve') |
|||
const {keccak256} = require("@ethersproject/keccak256"); |
|||
|
|||
const {newBigFromString, ecparams, newKeyPair, newRequestParameters, blind, blindSign, unblind, verify} = require("../src/index.js"); |
|||
|
|||
describe("keccak256", function () { |
|||
it("keccak256", async () => { |
|||
const m = BigInteger.fromBuffer(Buffer.from("test", 'utf8')); |
|||
const mHex = m.toString(16); |
|||
const hHex = keccak256('0x' + mHex); |
|||
assert.equal('0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', hHex); |
|||
const h = BigInteger.fromHex(hHex.slice(2)); |
|||
assert.equal('70622639689279718371527342103894932928233838121221666359043189029713682937432', h.toString()); |
|||
}); |
|||
}); |
|||
|
|||
describe("test blind", function () { |
|||
it("blind", async () => { |
|||
const {sk, pk} = newKeyPair(); |
|||
|
|||
const {k, signerR} = newRequestParameters(); |
|||
|
|||
const msg = BigInteger.fromBuffer( |
|||
Buffer.from("test", 'utf8') |
|||
); |
|||
assert.equal('1952805748', msg.toString()); |
|||
|
|||
const {mBlinded, userSecretData} = blind(msg, signerR); |
|||
|
|||
const sBlind = blindSign(sk, mBlinded, k); |
|||
|
|||
const sig = unblind(sBlind, userSecretData); |
|||
|
|||
const verified = verify(msg, sig, pk); |
|||
assert.equal(true, verified); |
|||
}); |
|||
}); |
@ -0,0 +1,39 @@ |
|||
import * as assert from 'assert' |
|||
import * as BigInteger from 'bigi' |
|||
// import { Point } from 'ecurve'
|
|||
import { keccak256 } from "@ethersproject/keccak256" |
|||
|
|||
import { newBigFromString, ecparams, newKeyPair, newRequestParameters, blind, blindSign, unblind, verify } from "../src/index" |
|||
|
|||
describe("keccak256", function () { |
|||
it("keccak256", async () => { |
|||
const m = BigInteger.fromBuffer(Buffer.from("test", 'utf8')) |
|||
const mHex = m.toString(16) |
|||
const hHex = keccak256('0x' + mHex) |
|||
assert.strictEqual('0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', hHex) |
|||
const h = BigInteger.fromHex(hHex.slice(2)) |
|||
assert.strictEqual('70622639689279718371527342103894932928233838121221666359043189029713682937432', h.toString()) |
|||
}) |
|||
}) |
|||
|
|||
describe("test blind", function () { |
|||
it("should blind", async () => { |
|||
const { sk, pk } = newKeyPair() |
|||
|
|||
const { k, signerR } = newRequestParameters() |
|||
|
|||
const msg = BigInteger.fromBuffer( |
|||
Buffer.from("test", 'utf8') |
|||
) |
|||
assert.strictEqual('1952805748', msg.toString()) |
|||
|
|||
const { mBlinded, userSecretData } = blind(msg, signerR) |
|||
|
|||
const sBlind = blindSign(sk, mBlinded, k) |
|||
|
|||
const sig = unblind(sBlind, userSecretData) |
|||
|
|||
const verified = verify(msg, sig, pk) |
|||
assert(verified) |
|||
}) |
|||
}) |
@ -0,0 +1,19 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"module": "commonjs", |
|||
"moduleResolution": "node", |
|||
"resolveJsonModule": true, |
|||
"pretty": true, |
|||
"declaration": true, |
|||
"sourceMap": true, |
|||
"target": "es2017", |
|||
"outDir": "dist", |
|||
"baseUrl": "src" |
|||
}, |
|||
"include": [ |
|||
"src/**/*.ts" |
|||
], |
|||
"exclude": [ |
|||
"node_modules" |
|||
] |
|||
} |
@ -0,0 +1,24 @@ |
|||
{ |
|||
"defaultSeverity": "error", |
|||
"extends": [ |
|||
"tslint:recommended" |
|||
], |
|||
"jsRules": {}, |
|||
"rules": { |
|||
"indent": [ |
|||
true, |
|||
"spaces", |
|||
4 |
|||
], |
|||
"semicolon": [ |
|||
false, |
|||
"always" |
|||
] |
|||
}, |
|||
"rulesDirectory": [], |
|||
"linterOptions": { |
|||
"exclude": [ |
|||
"node_modules/**" |
|||
] |
|||
} |
|||
} |