diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts index ad748d0e09..8f01385bfd 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts @@ -20,21 +20,22 @@ import { X509Identity, TransientMap, Wallet, + TxEventHandlerFactory, } from "fabric-network"; ///////////////// import { Client, User, - // DiscoveryService, - // Discoverer, - // Committer, - // BuildProposalRequest, + DiscoveryService, + Discoverer, + Committer, + BuildProposalRequest, } from "fabric-common"; import elliptic from "elliptic"; -// import crypto from "crypto"; -// import { ECCPrivateKey, KEYUTIL } from "jsrsasign"; +import crypto from "crypto"; +import { ECCPrivateKey, KEYUTIL } from "jsrsasign"; //const elliptic = require("elliptic"); // const crypto = require("crypto"); @@ -143,6 +144,7 @@ import { } from "./common/get-transaction-receipt-by-tx-id"; import { GetBlockEndpointV1 } from "./get-block/get-block-endpoint-v1"; import { querySystemChainCode } from "./common/query-system-chain-code"; +import { NETWORK_SCOPE_ALLFORTX } from "fabric-network/lib/impl/event/defaulteventhandlerstrategies"; /** * Constant value holding the default $GOPATH in the Fabric CLI container as @@ -1599,14 +1601,13 @@ export class PluginLedgerConnectorFabric ); // todo - types fix - const { prvKeyHex } = KEYUTIL.getKey(privateKeyPEM) as any; // convert the pem encoded key to hex encoded private key + const key = KEYUTIL.getKey(privateKeyPEM) as any; // convert the pem encoded key to hex encoded private key const EC = elliptic.ec; const ecdsaCurve = (elliptic.curves as any)["p256"]; const ecdsa = new EC(ecdsaCurve); - const signKey = ecdsa.keyFromPrivate(prvKeyHex, "hex"); - this.log.warn("signKey", signKey, "prvKeyHex", prvKeyHex); + const signKey = ecdsa.keyFromPrivate(key.prvKeyHex, "hex"); + this.log.warn("signKey", signKey, "key", key); - // TODO: Just cert?? should work... const user = User.createUser( username, pass, @@ -1663,30 +1664,46 @@ export class PluginLedgerConnectorFabric // }); // this.log.warn("ENDORESE RESPONSES:", proposalResponses.responses); + ///////// + // Signign Idx + const userPlain = User.createUser( + "", + "", + "Org1MSP", // todo -arg? + cert, + ); + const idxPlain = client.newIdentityContext(userPlain); + ///////// const endorsement = channel.newEndorsement(contractName); - const build_options = { fcn: "TransferAsset", args: ["asset2", "Bar"] }; - // const proposalBytes = endorsement.build(idx, build_options); - // this.log.warn("proposalBytes", proposalBytes); - - // // Calculate Hash for transaction Proposal Bytes - // const hash = crypto - // .createHash("sha256") - // .update(proposalBytes) - // .digest("hex"); - // this.log.warn("hash", hash); - - // // Creating Signature - // const sig = ecdsa.sign(Buffer.from(hash, "hex"), signKey, { - // canonical: true, - // }); - // const signature = Buffer.from(sig.toDER()); - // this.log.warn("signature:", signature); + const build_options = { fcn: "TransferAsset", args: ["asset2", "BarZ"] }; + const proposalBytes = endorsement.build(idxPlain, build_options); + this.log.warn("proposalBytes", proposalBytes); + + // Calculate Hash for transaction Proposal Bytes + const hash = crypto + .createHash("sha256") + .update(proposalBytes) + .digest("hex"); + this.log.warn("hash", hash); + + // Creating Signature + let sig = ecdsa.sign(Buffer.from(hash, "hex"), signKey, { + canonical: true, + }); + + this.log.warn("HODOR KEY", key); + sig = _preventMalleability(sig, key.ecparams); + + const signature = Buffer.from(sig.toDER()); + this.log.warn("signature:", signature); // Final - Sending Proposal Request - // await endorsement.sign(signature); - endorsement.build(idx, build_options); - await endorsement.sign(idx); + await endorsement.sign(signature); + + // endorsement.build(idx, build_options); + // await endorsement.sign(idx); + const proposalResponses = await endorsement.send({ targets: channel.getEndorsers(), }); @@ -1695,14 +1712,67 @@ export class PluginLedgerConnectorFabric // Commit the Transaction const commitReq = endorsement.newCommit(); this.log.warn("commitReq:", channel.getCommitters()); - commitReq.build(idx); - await commitReq.sign(idx); + + const commitProposalBytes = commitReq.build(idxPlain); + this.log.warn("commitProposalBytes", commitProposalBytes); + + const commitHash = crypto + .createHash("sha256") + .update(commitProposalBytes) + .digest("hex"); + this.log.warn("commitHash", commitHash); + + // Creating Signature + let sigCommit = ecdsa.sign(Buffer.from(commitHash, "hex"), signKey, { + canonical: true, + }); + sigCommit = _preventMalleability(sigCommit, key.ecparams); + + const signatureCommit = Buffer.from(sigCommit.toDER()); + this.log.warn("signatureCommit:", signatureCommit); + + // Final - Sending Proposal Request + await commitReq.sign(signatureCommit); + + // commitReq.build(idx); + // await commitReq.sign(idx); + const res = await commitReq.send({ targets: channel.getCommitters(), }); this.log.warn("Commit Result: ", res); + } +} - // TODO - events +// map for easy lookup of the "N/2" and "N" value per elliptic curve +const ordersForCurve = { + secp256r1: { + halfOrder: (elliptic.curves as any).p256.n.shrn(1), + order: (elliptic.curves as any).p256.n, + }, + secp384r1: { + halfOrder: (elliptic.curves as any).p384.n.shrn(1), + order: (elliptic.curves as any).p384.n, + }, +} as any; + +function _preventMalleability(sig: any, curveParams: any) { + const halfOrder = ordersForCurve[curveParams.name].halfOrder; + if (!halfOrder) { + throw new Error( + 'Can not find the half order needed to calculate "s" value for immalleable signatures. Unsupported curve name: ' + + curveParams.name, + ); + } + // in order to guarantee 's' falls in the lower range of the order, as explained in the above link, + // first see if 's' is larger than half of the order, if so, it needs to be specially treated + if (sig.s.cmp(halfOrder) === 1) { + // module 'bn.js', file lib/bn.js, method cmp() + // convert from BigInteger used by jsrsasign Key objects and bn.js used by elliptic Signature objects + const bigNum = ordersForCurve[curveParams.name].order; + sig.s = bigNum.sub(sig.s); } + + return sig; } diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/offline-signing.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/offline-signing.test.ts index fed5a61735..43ee6c4ca8 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/offline-signing.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/offline-signing.test.ts @@ -60,7 +60,7 @@ import { // FabricSigningCredential, RunTransactionRequest, FabricApiClient, - // WatchBlocksListenerTypeV1, + WatchBlocksListenerTypeV1, } from "../../../../main/typescript/public-api"; // Logger setup