Skip to content

Commit

Permalink
[FIX] Add public key as a part of calculating challenge hash in Schno…
Browse files Browse the repository at this point in the history
…rr signatures.

- Modify 'txx/index.ts' schnorrSign() to include total public key as an input for building challenge hash.
- Modify 'txx/index.ts' schnorrHash() for considering public key in challenge.
- Modify 'txx/index.ts' schnorrVerify() for total public key in Schnorr challenge hash value.
- Modify muon_network_simulator.ts and speed-test.ts to consider these changes.
  • Loading branch information
hyajam committed Apr 15, 2023
1 parent 82a3bfc commit b215159
Show file tree
Hide file tree
Showing 17 changed files with 193 additions and 30 deletions.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/muon-threshold-signature.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions .idea/sonarlint/issuestore/index.pb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
"@libp2p/logger": "^2.0.2",
"ajv": "^8.11.0",
"elliptic": "^6.5.4",
"ethereumjs-util": "^7.1.5",
"events-async": "^1.2.1",
"lodash": "^4.17.21",
"node-cache": "^5.1.2",
"redis": "^3.1.2",
"web3": "^1.7.3"
},
"devDependencies": {
"@noble/secp256k1": "^2.0.0",
"@types/lodash": "^4.14.191",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
Expand Down
2 changes: 1 addition & 1 deletion src/mpc/dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export class DistributedKeyGeneration extends MultiPartyComputation {
/** Ri = g^k */
{type: "bytes", value: "0x"+kPublic.encode('hex', true)},
)
const popSign = TssModule.schnorrSign(fx.coefficients[0].getPrivate(), k, kPublic, popMsg)
const popSign = TssModule.schnorrSign(fx.coefficients[0].getPrivate(), k, kPublic, TssModule.keyFromPublic(Fx[0]), popMsg);
const sig = {
nonce: kPublic.encode('hex', true),
signature: TssModule.stringifySignature(popSign)
Expand Down
7 changes: 4 additions & 3 deletions src/muon_network_simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ async function run() {
*/
const sigs = Object.keys(distKey).map(id => {
const key = toBN(distKey[id].share);
const nonce = toBN(distNonce[id].share)
const noncePublicKey = TssModule.keyFromPublic(distNonce[id].publicKey);
const nonce = toBN(distNonce[id].share);
const noncePoint = TssModule.keyFromPublic(distNonce[id].publicKey);
const publicKey = TssModule.keyFromPublic(distKey[id].publicKey);

return {
index: id,
sign: TssModule.schnorrSign(key, nonce, noncePublicKey, messageHex)
sign: TssModule.schnorrSign(key, nonce, noncePoint, publicKey, messageHex)
};
});

Expand Down
3 changes: 2 additions & 1 deletion src/speed-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ async function run() {
const key = toBN(distKey[id].share);
const nonce = toBN(distNonce[id].share)
const noncePublicKey = TssModule.keyFromPublic(distNonce[id].publicKey);
const publicKey = TssModule.keyFromPublic(distKey[id].publicKey);

return {
index: id,
sign: TssModule.schnorrSign(key, nonce, noncePublicKey, messageHex)
sign: TssModule.schnorrSign(key, nonce, noncePublicKey, publicKey, messageHex)
};
});
const signingTime = Date.now();
Expand Down
95 changes: 70 additions & 25 deletions src/tss/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {PublicKey} from "./types";
import {PublicKey} from './types';
import ethJsUtil from 'ethereumjs-util'
import {BN, toBN, keccak256, range, pub2addr} from './utils.js'
import assert from 'assert'
Expand All @@ -23,12 +23,22 @@ const HALF_N = curve.n!.shrn(1).addn(1);
const H = curve.keyFromPublic("04206ae271fa934801b55f5144bec8416be0b85f22d452ad410f3f0fca1083dc7ae41249696c446f8c5b166760377115943662991c35ff02f9585f892970af89ed", 'hex').getPublic()

function pointAdd(point1?: PublicKey, point2?: PublicKey): PublicKey {
if (point1 === null)
return point2!;
if (point2 === null)
return point1!;
// if a point is null then return another one as the result of the addition
if (point1 === null) {
return point2;
}
if (point2 === null) {
return point1;
}
// calculate the addition of the points
const result = point1?.add(point2);

return point1!.add(point2!);
// if any of the input points are not valid elliptic curve points return generator as output
if ((point1.validate() && point2.validate()) === false) {
return curve.g;
} else {
return result;
}
}

function calcPoly(x, polynomial) {
Expand All @@ -54,8 +64,16 @@ function calcPolyPointOld(x, polynomial): PublicKey {

function calcPolyPoint(x: string|number, polynomial: PublicKey[]): PublicKey {
const bnx = toBN(x);
const coeffs = polynomial.map((_,i) => bnx.pow(toBN(i)).umod(curve.n!))
return curve.curve._endoWnafMulAdd(polynomial, coeffs, false);
const validated = polynomial.reduce((accumulator, currentValue) => {
accumulator && currentValue.validate();
}, true);
const coefArray = polynomial.map((_,i) => bnx.pow(toBN(i)).umod(curve.n));
const result = curve.curve._endoWnafMulAdd(polynomial, coefArray, false);
if (validated === false) {
return curve.g;
} else {
return result;
}
}

function random() {
Expand Down Expand Up @@ -141,20 +159,35 @@ function key2pub(privateKey) {
return curve.g.mul(_PK);
}

function schnorrHash(publicKey, msg) {
let address = pub2addr(publicKey)
let addressBuff = Buffer.from(address.replace(/^0x/i, ''), 'hex');
let msgBuff = Buffer.from(msg.replace(/^0x/i, ''), 'hex');
let totalBuff = Buffer.concat([addressBuff, msgBuff])
function schnorrHash(noncePoint, pubKey, msg) {
const nonceAddress = pub2addr(noncePoint);
const nonceAddressBuff = Buffer.from(nonceAddress.replace(/^0x/i, ''), 'hex');

// calculate public ket address to add to the challenge hash
const pubKeyAddress = pub2addr(pubKey);
const pubKeyAddressBuff = Buffer.from(pubKeyAddress.replace(/^0x/i, ''), 'hex');

const msgBuff = Buffer.from(msg.replace(/^0x/i, ''), 'hex');

const totalBuff = Buffer.concat([nonceAddressBuff, pubKeyAddressBuff, msgBuff]);
// @ts-ignore
return keccak256(totalBuff)
return keccak256(totalBuff);
}

function schnorrSign(sharedPrivateKey, sharedK, kPub, msg) {
let _sharedPrivateKey = BN.isBN(sharedPrivateKey) ? sharedPrivateKey : toBN(sharedPrivateKey);
let e = toBN(schnorrHash(kPub, msg))
let s = sharedK.sub(_sharedPrivateKey.mul(e)).umod(curve.n);
return {s, e}
function schnorrSign(sharedPrivateKey, sharedK, noncePoint, publicKey, msg) {
// make _sharedPrivateKey that is the BN from of sharedPrivateKey
let _sharedPrivateKey: BN;
if (BN.isBN(sharedPrivateKey)) {
_sharedPrivateKey = sharedPrivateKey;
} else {
_sharedPrivateKey = toBN(sharedPrivateKey);
}

// calculate 'e' of the signature consider adding public key to challenge value
const e = toBN(schnorrHash(noncePoint, publicKey, msg));
const s = sharedK.sub(_sharedPrivateKey.mul(e)).umod(curve.n);

return {s, e};
}

export function stringifySignature(sign: {s: BN, e: BN}): string {
Expand All @@ -172,13 +205,25 @@ export function splitSignature(signature: string): {s: BN, e: BN} {
}

function schnorrVerify(pubKey: PublicKey, msg, sig:{s: BN, e: BN}|string) {
if(typeof sig === 'string')
if(typeof sig === 'string') {
sig = splitSignature(sig);
if(!sig.s.lt(curve.n!))
throw "signature must be reduced modulo N"
let r_v = pointAdd(curve.g.mul(sig.s), pubKey.mul(sig.e))
let e_v = schnorrHash(r_v, msg)
return toBN(e_v).eq(sig.e);
}

// Prevent denial of service attacks by bounding the 's' and 'e' to values lower than curve.n
const s = sig.s.umod(curve.n);
const e = sig.e.umod(curve.n);

// Calculate verifying values of signature use public key as part of challenge hash
const rv = pointAdd(curve.g.mul(s), pubKey.mul(e));
const ev = schnorrHash(rv, pubKey, msg);
const result = toBN(ev).eq(e);

// Return only if the public key value is a valid point on curve
if (pubKey.validate() === false) {
return false;
} else {
return result;
}
}

function schnorrVerifyWithNonceAddress(hash, signature, nonceAddress, signingPubKey) {
Expand Down

0 comments on commit b215159

Please sign in to comment.