Browse Source

Adding support for Typescript

pull/3/head
Jør∂¡ 3 years ago
parent
commit
fc74a782e3
9 changed files with 2792 additions and 1215 deletions
  1. +1
    -0
      .gitignore
  2. +2584
    -1059
      package-lock.json
  3. +22
    -8
      package.json
  4. +0
    -109
      src/index.js
  5. +103
    -0
      src/index.ts
  6. +0
    -39
      test/index.test.js
  7. +39
    -0
      test/index.test.ts
  8. +19
    -0
      tsconfig.json
  9. +24
    -0
      tslint.json

+ 1
- 0
.gitignore

@ -1,2 +1,3 @@
node_modules node_modules
blindsecp256k1-browser.js blindsecp256k1-browser.js
dist

+ 2584
- 1059
package-lock.json
File diff suppressed because it is too large
View File


+ 22
- 8
package.json

@ -2,21 +2,35 @@
"name": "blindsecp256k1", "name": "blindsecp256k1",
"version": "0.0.1", "version": "0.0.1",
"description": "Blind signatures over secp256k1, compatible with https://github.com/arnaucube/go-blindsecp256k1", "description": "Blind signatures over secp256k1, compatible with https://github.com/arnaucube/go-blindsecp256k1",
"main": "src/index.js",
"main": "dist/index",
"types": "dist/index",
"scripts": { "scripts": {
"browserify": "browserify src/index.js --standalone blindsecp256k1 > blindsecp256k1-browser.js",
"test": "mocha"
"prepublishOnly": "npm run build",
"clean": "rimraf dist",
"build": "npm run clean && ./node_modules/.bin/tsc",
"watch": "./node_modules/.bin/tsc -w -p .",
"ts-node": "./node_modules/.bin/ts-node",
"test": "npm run build && ./node_modules/.bin/mocha -r ts-node/register test/**/*.ts"
}, },
"author": "arnaucube", "author": "arnaucube",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"bigi": "^1.1.0",
"@ethersproject/keccak256": "5.0.7",
"bigi": "^1.4.2",
"bignumber.js": "7.0.2", "bignumber.js": "7.0.2",
"ecurve": "1.0.0",
"@ethersproject/keccak256": "5.0.7"
"ecurve": "1.0.0"
}, },
"devDependencies": { "devDependencies": {
"browserify": "^16.5.0",
"mocha": "^5.2.0"
"@types/bigi": "^1.4.2",
"@types/chai": "^4.2.14",
"@types/ecurve": "^1.0.0",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.25",
"chai": "^4.2.0",
"mocha": "^8.2.1",
"rimraf": "^3.0.2",
"ts-node": "^9.1.1",
"tslint": "^6.1.3",
"typescript": "^4.1.3"
} }
} }

+ 0
- 109
src/index.js

@ -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
}

+ 103
- 0
src/index.ts

@ -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
}

+ 0
- 39
test/index.test.js

@ -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);
});
});

+ 39
- 0
test/index.test.ts

@ -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)
})
})

+ 19
- 0
tsconfig.json

@ -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"
]
}

+ 24
- 0
tslint.json

@ -0,0 +1,24 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {
"indent": [
true,
"spaces",
4
],
"semicolon": [
false,
"always"
]
},
"rulesDirectory": [],
"linterOptions": {
"exclude": [
"node_modules/**"
]
}
}

Loading…
Cancel
Save