From bffb6a08e0fe19b96d7d69271e6b5276bbb392a5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 May 2024 15:30:58 +1000 Subject: [PATCH 1/8] Fixed resolveAsset --- contracts/utils/resolvers.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/contracts/utils/resolvers.js b/contracts/utils/resolvers.js index e1bc803f06..5791420874 100644 --- a/contracts/utils/resolvers.js +++ b/contracts/utils/resolvers.js @@ -13,16 +13,23 @@ const resolveAsset = async (symbol) => { // "Hardhat can't be initialized while its config is being defined" const hre = require("hardhat"); - if (hre.network.name != "hardhat") { + // Not using helpers here as they import hardhat which won't work for Hardhat tasks + if (process.env.FORK === "true" || hre.network.name != "hardhat") { + const network = + hre.network.name != "hardhat" + ? hre.network.name != "hardhat" + : hre.network.config.chainId == 17000 + ? "holesky" + : "mainnet"; + const assetAddr = - addresses[hre.network.name][symbol + "Proxy"] || - addresses[hre.network.name][symbol]; + addresses[network][symbol + "Proxy"] || addresses[network][symbol]; if (!assetAddr) { throw Error( - `Failed to resolve symbol "${symbol}" to an address on the "${hre.network.name}" network` + `Failed to resolve symbol "${symbol}" to an address on the "${network}" network` ); } - log(`Resolved ${symbol} to ${assetAddr}`); + log(`Resolved ${symbol} to ${assetAddr} on the ${network} network`); const asset = await ethers.getContractAt("IERC20Metadata", assetAddr); return asset; } From 92aa9c62536047cb94c7e4aedc7cd4d02f52f57d Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 May 2024 21:17:29 +1000 Subject: [PATCH 2/8] Fixed validator fork tests Added error func sigs to ISSVNetwork --- .../contracts/interfaces/ISSVNetwork.sol | 70 +++++++++++-------- .../strategies/nativeSsvStaking.fork-test.js | 10 +-- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/contracts/contracts/interfaces/ISSVNetwork.sol b/contracts/contracts/interfaces/ISSVNetwork.sol index 9f37388663..f069138177 100644 --- a/contracts/contracts/interfaces/ISSVNetwork.sol +++ b/contracts/contracts/interfaces/ISSVNetwork.sol @@ -10,36 +10,46 @@ struct Cluster { } interface ISSVNetwork { - error ApprovalNotWithinTimeframe(); - error CallerNotOwner(); - error CallerNotWhitelisted(); - error ClusterAlreadyEnabled(); - error ClusterDoesNotExists(); - error ClusterIsLiquidated(); - error ClusterNotLiquidatable(); - error ExceedValidatorLimit(); - error FeeExceedsIncreaseLimit(); - error FeeIncreaseNotAllowed(); - error FeeTooHigh(); - error FeeTooLow(); - error IncorrectClusterState(); - error IncorrectValidatorState(); - error InsufficientBalance(); - error InvalidOperatorIdsLength(); - error InvalidPublicKeyLength(); - error MaxValueExceeded(); - error NewBlockPeriodIsBelowMinimum(); - error NoFeeDeclared(); - error NotAuthorized(); - error OperatorAlreadyExists(); - error OperatorDoesNotExist(); - error OperatorsListNotUnique(); - error SameFeeChangeNotAllowed(); - error TargetModuleDoesNotExist(); - error TokenTransferFailed(); - error UnsortedOperatorsList(); - error ValidatorAlreadyExists(); - error ValidatorDoesNotExist(); + /**********/ + /* Errors */ + /**********/ + + error CallerNotOwner(); // 0x5cd83192 + error CallerNotWhitelisted(); // 0x8c6e5d71 + error FeeTooLow(); // 0x732f9413 + error FeeExceedsIncreaseLimit(); // 0x958065d9 + error NoFeeDeclared(); // 0x1d226c30 + error ApprovalNotWithinTimeframe(); // 0x97e4b518 + error OperatorDoesNotExist(); // 0x961e3e8c + error InsufficientBalance(); // 0xf4d678b8 + error ValidatorDoesNotExist(); // 0xe51315d2 + error ClusterNotLiquidatable(); // 0x60300a8d + error InvalidPublicKeyLength(); // 0x637297a4 + error InvalidOperatorIdsLength(); // 0x38186224 + error ClusterAlreadyEnabled(); // 0x3babafd2 + error ClusterIsLiquidated(); // 0x95a0cf33 + error ClusterDoesNotExists(); // 0x185e2b16 + error IncorrectClusterState(); // 0x12e04c87 + error UnsortedOperatorsList(); // 0xdd020e25 + error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac + error ExceedValidatorLimit(); // 0x6df5ab76 + error TokenTransferFailed(); // 0x045c4b02 + error SameFeeChangeNotAllowed(); // 0xc81272f8 + error FeeIncreaseNotAllowed(); // 0x410a2b6c + error NotAuthorized(); // 0xea8e4eb5 + error OperatorsListNotUnique(); // 0xa5a1ff5d + error OperatorAlreadyExists(); // 0x289c9494 + error TargetModuleDoesNotExist(); // 0x8f9195fb + error MaxValueExceeded(); // 0x91aa3017 + error FeeTooHigh(); // 0xcd4e6167 + error PublicKeysSharesLengthMismatch(); // 0x9ad467b8 + error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938 + error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999 + error EmptyPublicKeysList(); // df83e679 + + // legacy errors + error ValidatorAlreadyExists(); // 0x8d09a73e + error IncorrectValidatorState(); // 0x2feda3c1 event AdminChanged(address previousAdmin, address newAdmin); event BeaconUpgraded(address indexed beacon); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 3652fa8955..12b502c26d 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -21,14 +21,14 @@ describe("ForkTest: Native SSV Staking Strategy", function () { addresses: addresses.mainnet, testValidator: { publicKey: - "0xad9ade40c386259fe4161ec12d7746ab49a098a4760a279c56dc7e26b56fc4d985e74eeecdd2bc5a1decceb5174204f4", - operatorIds: [193, 196, 199, 202], + "0x93d60259213f491a910ee8f6504d51ba5fc28085981eccd6c20ca646525c626013c75b04f061fbf3de839ac602c64698", + operatorIds: [348, 352, 361, 377], sharesData: - "0x8308e4b6ad536304f978077a0cd3685a98d5847bb1b05e0a4c5994ddf64ce48daa917f666d86f3125aac139a4fc7b07119ea2c7fc0fe5cfb316a5687dbddf621b0229e55230f0857d426697513ee2556d2c730595268358ebe8e16331bd2dd53acfd93e4e96c5fb510f78dc0f11e5097f83b2609a5711b233fa843935125dbbd90e43dc4f7d181221a42fcc02fe58aeb90fefb6a1d46faad099b6fa8e68351ff21f52d90a96bffeb33d1c0517bf39e413a441f1c290f1289021e9bd47146689ba139bccfaf7d6d1a6fba03c177d9ffca11f347b0f16a1cd8b1808a9b46ec0849ff45562a853ea137dfea3a0ed43ceac5805a993edd6b618cf7aa1441b2deeb2a7a573f0a44d9ed6bffb75573a91e9de2c21e198815d9b133ce7060ff339bf23b12af3c15f566b81842f307066205f09b40b4db045af881f5ca571289d1aa52555002544e8941b854b1b565b5e76c845c4b287a46890d6ad3e01185d2fb5485ecb136814a23378d37ff53244c1420af43db268f74bf0532dd235cb2afd49d1dce7158d1f51650bc32b790f29bdfc2bafc9990a55a15d005139c6ede259a6a9426400d67192ec697a8990c326bc63fe8a809515d0cc311059da2e333cb92331c45ac8b8d2e09a8cc4092016ade9f90a4b1a89a89f9da38818a5a77f84ae2aba340719dc6a01810ddfcd9e9cf9ebfab033363d2a58296cd1ab8e33ea4e04738111a3e2d80d34c601b0b49e95412cdd554a844f02a94f7f239e70cb72247c36218de79b5d0d73a7429cccf1999eca2611b1c486e8148451cac60bc60280764948f54100a39d9290c368a2ace60daa3ff1bf9dd7514afd02397c196b9cee8ef94478619a114cbebdf4475053857f2728c7621c5fb6739cbf8a15727c5d15a354e20ac054f31e51288a4f94a4215d00d23d2e5a82f745f2f15d6b147ecf817165913f2f72f492075de8f339efe54f163311f7de056c36a900949f7f026c17a96770edd29ba0301732bb83d218a0fb28d466858118e7240725ee74a45fd3acf8ca7310cb72f6cb3c6f8517b89984ad622ffeb39dad587d2e944d59fe849841fc5f09e9f1935cc59b10c795446eb18a2f87e6ee1a497fe0bb556164cd2d7b5c7cf5fdb758e8fc26711116bf59a08be68d2ddb9a97300d2ac43055877a0cc3be97c8b82ceb5dd59f6222c23d849dc7620ffca0393d685cb609059e0e8a76500c9c92d7878a3939c346897d10c6707d39bd10d0f546f6506b6b087dea16156478e11d9537d169d582ca26a04dceede25a38b5a4bf2e16db9db97bdb320f198632a0b60af8ebdf3e6a0bda19f34c9ddc7e437d3fef3da021cae41dd99d2898d825db9de51561dee2a5587fa75453609fff5aec3e949a34fd438f00ab6dbca03e385059003936db14c66d4fec38d6ba729051866c336c51c802507dc5b16b591a4905636736a05bbd0d39ba965de131abad34797e3521ff01612b1bd17aca6af61abf8bd24182a1e2848fc41819c0ce7065000747023db82de23eef601ed7cdaffd39b005e8bb8156f4986d9825e62cd2f13f8c0e33e5825e8d81730ef1a63dfd19af6afd08f9f102f403783dca89173456d9e60fb72b2c153bf0bb73bed799a15eb94923f7cadd9c9bc529a86051d8202b1af53ccb161179f9c4609084dd977091082fc14c20ff21efd70bb9ca56b0ea80c7fc16e2f1718c7b306944fa6c7572440c7d6035a22cea8858f64bb3b6d147a05743021ca1b79d71bac87888bb5fd343b1817a28dda336f1d640f8adae159020deba8d3e1e97ae0b9a4ba23112e59d93169a7b875fc878f66f13b2568ed326f9da7ba6c2bd08d37f5b0ef6bfe56febe20e366fa9d", + "0x861fce88da51de578b2a3f9fa32b3c56499b1261d33f8adbb24932cc906edfd6383b63ac37bfd8b2e9f7087622c1f14b1651426316c741bd8470315d63393bbdc8a0a097f1ac728315fbf17b79b675e9c40605913fff64800a5c7c2057e30f44abed76d8ce797db6f03219e077a3d1fa3945f37d8eeb4c52aee99b4a5f606be50515d347405db37b37a063cd1cd315818521decd2e44878a1a53e84a4186ea3e896a29e0e34c68091a4575b5834e6bfa6c5987916ae49d77347ee7b2f7428f8489a07e54e9d05690f5f8acc2eeab46f44a0f39e5e0e41fde76d29e2660fb5349e00d264527f92d71cfa27a51d9285873908757f42f8f9e40a9c3ec5d9adc966a4dde82d0b87c48ffaebfe2bda73ff388197829d24eb2b18cc50dbae96473a95d819dc1dc99959811e832396eec4773701dbaf86d6449c8310f7fa9ed289675a0ba1be59881fe7b1e64d4485654bab3f9010e575773262ac65f7fa24663f090d413ca74572dac7df3cf06c1fdc226acfc1380441c2d9c4b31fbdd5ee12d83e2d36b9512f4e9c5f0b3607b51665479a9ce035ee952c9d743b5d7b3fa1acec222b447bf8e98397a6e79569a1487adff39f06bfa0a51b022d1798738b37a0801a1f97498c6c3633404f251c137b21e0eec92bcb7a4eb00cad9c826327f4712643035e4b79d14d3e5b0bcf791e6bbfa447f30d362570c26c29787d7c9360b3566b1e9c6eb3f785c96c6d3642a2332910fe3f0b78d4d18d7d4bbedd0b919c8a2853a0babd353c695960d4ec00727a3a91192b8b3a4d4e7cfd1620cdb4936afd91f5155c20bbe8a3dd96790d5e623f9cea53fa32ebe8f2f2572d5d99686ba735d824aaa74a56fd0fde9c219811cb79760410be3815ca95b75551608ee945b895a5c08b760b90aa4836128048b4fd19e0ed475c720d83a76af7e8c3e571f11b0fc540c788d7daea8bc923db44a6f8d208e0140a18d1c811029419d27b4ed994f0ec21c8f65df2f0c83cf5d0111694c18076e7441b0e0fa8e58da3a6c3b94e819550322765d70fbd4f053f2edcba3050cfe14d0efe7280c4a3990182a46cdf4a7f8cf20e0fc17d4fb5becb35908a04e19f5be2df7db81edf9cae016ac88769cb1a644189d84e35e18ff0d2fea6b02a406129487009311525199ffec581fd587521a239f6514e6e10aeef63e531cbe4c37f08592999ce3c3146e76e2793a974d49e0c7264c214133bd2049eacb8f09b3184130812b71fb0cd02d2f044f1d38ab34d1a9bed9940b5691f396c7e2ad25b6baf6ed14baa0f70ef3fd2d5cafd16c7775f6583971223eab2276b98e1998e87692e8474647bc135fab8d8ff7bbdd3d669856897cf7776b594f7cf49ac02870df621eca1919b39f9d28bddee92f3b5150e806b9fe9db01e6e1474d09239799c1265bdab86e8eda0f69cebf921af3ba852f5b64d2129bfa09155dc411165d66c0d750fa9fc07a6be3fdbce769bb494b84eff41319618c1611fe3f62b39066e81ee5ead615d7a576cc8fe68e8bb6ba1d4088810c701f0c1873df8cd02d5019589c095bb730a5625a3996c0b240aaf4484f2502d4aa377d462894557615a5d486339b4ad108ef6ffef0a26ba0136e3d969b4337954069aaeaa73e64757477f30d723ba38dc644f6e371088d9e2b1ff50ecbddad48198e525963fabda4e196c9ddf0d89abcdc3a3d395a96b22254242ce93804e4d6673265e7c4d56b1195aada97bbe9050e843bd56181a533fa03e01285ade0f715d0f9830b1f0ae7586d8485bf76ace561ea6c8c4c9497674d96182a9e289ddcc722814f14b8ce8a70bbb6dec40f84cde55e0d16d4ec043561d6a1d16790b5bc4f02ab9", signature: - "0xadf71438600db72305e4a277554c06359d25e59480e2c4d5ea9d12d132088893d2df141c60a0857c63edc10b9800ac0e0e3e3dcd7b5fdfbcab8fbf377816811becc8be9420c17a725dff9dac6653230b9c5c04fd2ea19f9313fe943e1a562a18", + "0x8522f6464ddc5550f70ed8cd58ed26961d8755111d5e967ee815730bc2e9ad24e7ca718fcf56f1af785bc25dfac719a615a4c4e029a352840edca0d78c9a46ef35202f42311918f70d8ddde9de25fe091889283b9778ea15403fe87dc5f7527e", depositDataRoot: - "0x0d12c28849771f3f946d8d705a1f73683d97add9edaec5e6b30650cc03bc57d5", + "0xcbcd1da8a9ba0e30b2dd8a955591ac4a759bf5ee6f5295d72f5b89b1b175193b", }, }; }); From 9d9e09caa083d809050a7c57c7db39a3ea4fad0f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 May 2024 21:44:42 +1000 Subject: [PATCH 3/8] Fixed harvester behaviour tests --- contracts/test/behaviour/reward-tokens.fork.js | 5 +++-- contracts/test/vault/oeth-vault.fork-test.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/test/behaviour/reward-tokens.fork.js b/contracts/test/behaviour/reward-tokens.fork.js index 068ff475ae..d0c48eb779 100644 --- a/contracts/test/behaviour/reward-tokens.fork.js +++ b/contracts/test/behaviour/reward-tokens.fork.js @@ -14,6 +14,7 @@ const { BigNumber } = require("ethers"); shouldHaveRewardTokensConfigured(() => ({ harvester: fixture.harvester, vault: fixture.vault, + ignoreTokens: [fixture.weth.address.toLowerCase()], expectedConfigs: { [fixture.cvx.address]: { allowedSlippageBps: 300, @@ -46,7 +47,7 @@ const shouldHaveRewardTokensConfigured = (context) => { describe("Reward Tokens", () => { it("Should have swap config for all reward tokens from strategies", async () => { - let { vault, harvester, expectedConfigs } = context(); + let { vault, harvester, expectedConfigs, ignoreTokens } = context(); const strategies = await vault.getAllStrategies(); expectedConfigs = Object.keys(expectedConfigs).reduce( @@ -57,7 +58,7 @@ const shouldHaveRewardTokensConfigured = (context) => { {} ); - const checkedConfigs = []; + const checkedConfigs = ignoreTokens || []; for (const strategyAddr of strategies) { const strategy = await ethers.getContractAt("IStrategy", strategyAddr); diff --git a/contracts/test/vault/oeth-vault.fork-test.js b/contracts/test/vault/oeth-vault.fork-test.js index 7ade3fd9da..59177c0cbf 100644 --- a/contracts/test/vault/oeth-vault.fork-test.js +++ b/contracts/test/vault/oeth-vault.fork-test.js @@ -219,6 +219,7 @@ describe("ForkTest: OETH Vault", function () { shouldHaveRewardTokensConfigured(() => ({ vault: fixture.oethVault, harvester: fixture.oethHarvester, + ignoreTokens: [fixture.weth.address.toLowerCase()], expectedConfigs: { [fixture.cvx.address]: { allowedSlippageBps: 300, From 99c88339fb9dd0518a26d503a232595da9c80f27 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 08:32:47 +1000 Subject: [PATCH 4/8] WIP decrypting validator key from P2P API --- contracts/tasks/crypto.js | 193 ++++++++++++++++++++++++++++++++++++++ contracts/tasks/tasks.js | 75 +++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 contracts/tasks/crypto.js diff --git a/contracts/tasks/crypto.js b/contracts/tasks/crypto.js new file mode 100644 index 0000000000..5533049c0b --- /dev/null +++ b/contracts/tasks/crypto.js @@ -0,0 +1,193 @@ +const { + createPrivateKey, + createPublicKey, + generateKeyPair, + createCipheriv, + createECDH, + createDecipheriv, + randomBytes, +} = require("node:crypto"); + +const ecdhCurveName = "prime256v1"; +const encryptionAlgorithm = "aes-256-cbc"; + +const genECDHKey = async ({ privateKey }) => { + const ecdh = createECDH(ecdhCurveName); + + if (privateKey) { + console.log(`Private key ${privateKey}`); + const pair = ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); + const publicKeyPem = ecdh.getPublicKey("pem", "spki"); + + // console.log(`Public key:\n${ecdh.getPublicKey("base64")}`); + // console.log( + // `Encoded public key for P2P API:\n${ecdh + // .getPublicKey("base64") + // .toString("base64")}` + // ); + return; + } + + ecdh.generateKeys(); + const privateKeyBase64 = ecdh.getPrivateKey("base64"); + const publicKeyBase64 = ecdh.getPublicKey("base64"); + + console.log(`Private key ${privateKeyBase64}`); + console.log(`Public key:\n${publicKeyBase64}`); + + // Create a PublicKey object from the ECDH instance + const publicKeyObj = createPublicKey({ + key: ecdh.getPublicKey(), + format: "der", + type: "spki", + }); + + // Export the public key in PEM format + const publicKeyPem = publicKeyObj.export({ type: "spki", format: "pem" }); + console.log(`Public key in PEM format ${publicKeyPem.toString("base64")}`); + + // const publicKey = createPublicKey(privateKeyBase64); + // console.log(`Public key in PEM format ${ecdh.getPublicKey("pem", "spki")}`); + // console.log( + // `Encoded public key for P2P API:\n${publicKeyPem.toString("base64")}` + // ); +}; + +const genECDHKey2 = async ({ privateKey }) => { + if (privateKey) { + console.log(`Private key ${privateKey}`); + const ecdh = createECDH(ecdhCurveName); + // const pk = createPrivateKey({ + // key: Buffer.from(privateKey, "base64"), + // format: "der", + // type: "pkcs8", + // }); + + const pk = createPrivateKey({ + key: Buffer.from(privateKey, "base64"), + type: "pkcs8", // 'sec1' or 'pkcs8', depending on the format + format: "der", + }); + + const pair = ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); + // const pair = ecdh.setPrivateKey( + // pk.export({ type: "pkcs8", format: "der" }).toString("base64") + // ); + console.log(`Public key:\n${pair.publicKey.toString("base64")}`); + console.log( + `Encoded public key for P2P API:\n${Buffer.from(pair.publicKey).toString( + "base64" + )}` + ); + return; + } + + return new Promise((resolve, reject) => { + // Generate an elliptic curve key pair using the secp256r1 curve + generateKeyPair( + "ec", + { + namedCurve: ecdhCurveName, // is the same as secp256r1 + publicKeyEncoding: { + type: "spki", // Use Subject Public Key Info format + format: "pem", // Encoding format + }, + privateKeyEncoding: { + type: "pkcs8", // Use Public-Key Cryptography Standards 8 format + format: "der", // Encoding format + }, + }, + (err, publicKey, pk) => { + if (err) return reject(err); + + console.log(`Private key ${pk.toString("base64")}`); + console.log(`Public key:\n${publicKey.toString("base64")}`); + console.log( + `Encoded public key for P2P API:\n${Buffer.from(publicKey).toString( + "base64" + )}` + ); + + const pk2 = createPrivateKey({ + key: Buffer.from(pk.toString("base64"), "base64"), + type: "pkcs8", // 'sec1' or 'pkcs8', depending on the format + format: "der", + }); + console.log( + `Private key 2 ${pk2 + .export({ type: "pkcs8", format: "der" }) + .toString("base64")}` + ); + const ecdh = createECDH(ecdhCurveName); + const base64PrivateKey = + "MHcCAQEEIG6AQo/0h2C4sK1cIlTVTFLEmTSzCk++c5jeUG+KjCp6oAoGCCqGSM49AwEHoUQDQgAEZtnrHukMrlO+2rONXOHfncFtgsZ+lqnr5Y0l6XBbeyEOv7iz6SyeUMWtUlWGsWE9sbzMFs7owEhrcz0sxf58eA=="; + + const pair = ecdh.setPrivateKey( + Buffer.from(base64PrivateKey, "base64") + ); + console.log(`Private key 3 ${pair.toString("base64")}`); + + resolve(); + } + ); + }); +}; + +const encrypt = async ({ privateKey, publicKey, text }) => { + const ecdh = createECDH(ecdhCurveName); + ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); + + console.log(`My private key ${ecdh.getPrivateKey("base64")}`); + console.log(`My public key ${ecdh.getPublicKey("base64", "spki")}`); + + const otherPublicKey = Buffer.from(publicKey, "base64"); + + const secretKey = ecdh.computeSecret(otherPublicKey, "base64", "base64"); + console.log("secretKey:", secretKey.toString("base64")); + + const initializationVector = randomBytes(16); + console.log( + "initialization vector:", + initializationVector.toString("base64") + ); + + const cipher = createCipheriv( + encryptionAlgorithm, + secretKey, + initializationVector + ); + + const encrypted = Buffer.concat([cipher.update(text), cipher.final()]); + + console.log("encrypted content:", encrypted.toString("base64")); +}; + +const decrypt = async ({ privateKey, publicKey, text, iv }) => { + const ecdh = createECDH(ecdhCurveName); + ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); + + console.log(`My private key ${ecdh.getPrivateKey("base64")}`); + console.log(`My public key ${ecdh.getPublicKey("base64", "spki")}`); + + const otherPublicKey = Buffer.from(publicKey, "base64"); + const secretKey = ecdh.computeSecret(otherPublicKey, "base64", "base64"); + console.log("Secret:", secretKey); + + const decipher = createDecipheriv( + encryptionAlgorithm, + secretKey, + Buffer.from(iv, "base64") + ); + + const decryptedContent = Buffer.concat([ + decipher.update(Buffer.from(text, "base64")), + decipher.final(), + ]); + console.log(`Decrypted content: ${decryptedContent.toString()}`); +}; + +module.exports = { + genECDHKey, + encrypt, + decrypt, +}; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 55fd7c0b28..555e90c31e 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -11,6 +11,7 @@ const { resolveContract } = require("../utils/resolvers"); const { KeyValueStoreClient } = require("defender-kvstore-client"); const { operateValidators } = require("./validator"); const { formatUnits } = require("ethers/lib/utils"); +const { genECDHKey, encrypt, decrypt } = require("./crypto.js"); const { storeStorageLayoutForAllContracts, @@ -978,3 +979,77 @@ subtask( task("operateValidators").setAction(async (_, __, runSuper) => { return runSuper(); }); + +// Encryption + +subtask("genECDHKey", "Generate Elliptic-curve Diffie–Hellman (ECDH) key pair") + .addOptionalParam( + "privateKey", + "Private key to encrypt the message with in base64 format", + undefined, + types.string + ) + .setAction(genECDHKey); +task("genECDHKey").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "encrypt", + "Encrypt a message using a Elliptic-curve Diffie–Hellman (ECDH) key pair" +) + .addParam( + "privateKey", + "Private key to encrypt the message with in hex format without the 0x prefix", + undefined, + types.string + ) + .addParam( + "publicKey", + "Public key of the other party in hex format without the 0x prefix", + undefined, + types.string + ) + .addParam( + "text", + "Message that needs to be encrypted", + undefined, + types.string + ) + .setAction(encrypt); +task("encrypt").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "decrypt", + "Decrypt a message using a Elliptic-curve Diffie–Hellman (ECDH) key pair" +) + .addParam( + "privateKey", + "Private key to decrypt the message with in hex format without the 0x prefix", + undefined, + types.string + ) + .addParam( + "publicKey", + "Public key of the other party in hex format without the 0x prefix", + undefined, + types.string + ) + .addParam( + "text", + "Encrypted message that needs to be decrypted in base64 format", + undefined, + types.string + ) + .addParam( + "iv", + "InitializationVector in hex format without the 0x prefix", + undefined, + types.string + ) + .setAction(decrypt); +task("decrypt").setAction(async (_, __, runSuper) => { + return runSuper(); +}); From d35eaa4cf265ab0cdc3a046d79d298209bc5f983 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 22:21:29 +1000 Subject: [PATCH 5/8] Fixed genECDHKey HH task --- contracts/tasks/crypto.js | 125 ++++---------------------------------- 1 file changed, 13 insertions(+), 112 deletions(-) diff --git a/contracts/tasks/crypto.js b/contracts/tasks/crypto.js index 5533049c0b..cc83015255 100644 --- a/contracts/tasks/crypto.js +++ b/contracts/tasks/crypto.js @@ -1,7 +1,4 @@ const { - createPrivateKey, - createPublicKey, - generateKeyPair, createCipheriv, createECDH, createDecipheriv, @@ -15,122 +12,26 @@ const genECDHKey = async ({ privateKey }) => { const ecdh = createECDH(ecdhCurveName); if (privateKey) { - console.log(`Private key ${privateKey}`); - const pair = ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); - const publicKeyPem = ecdh.getPublicKey("pem", "spki"); - - // console.log(`Public key:\n${ecdh.getPublicKey("base64")}`); - // console.log( - // `Encoded public key for P2P API:\n${ecdh - // .getPublicKey("base64") - // .toString("base64")}` - // ); - return; + ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); + } else { + ecdh.generateKeys(); } - ecdh.generateKeys(); const privateKeyBase64 = ecdh.getPrivateKey("base64"); const publicKeyBase64 = ecdh.getPublicKey("base64"); - console.log(`Private key ${privateKeyBase64}`); - console.log(`Public key:\n${publicKeyBase64}`); - - // Create a PublicKey object from the ECDH instance - const publicKeyObj = createPublicKey({ - key: ecdh.getPublicKey(), - format: "der", - type: "spki", - }); - - // Export the public key in PEM format - const publicKeyPem = publicKeyObj.export({ type: "spki", format: "pem" }); - console.log(`Public key in PEM format ${publicKeyPem.toString("base64")}`); - - // const publicKey = createPublicKey(privateKeyBase64); - // console.log(`Public key in PEM format ${ecdh.getPublicKey("pem", "spki")}`); - // console.log( - // `Encoded public key for P2P API:\n${publicKeyPem.toString("base64")}` - // ); -}; + console.log(`Private key: ${privateKeyBase64}`); + console.log(`Public key: ${publicKeyBase64}`); -const genECDHKey2 = async ({ privateKey }) => { - if (privateKey) { - console.log(`Private key ${privateKey}`); - const ecdh = createECDH(ecdhCurveName); - // const pk = createPrivateKey({ - // key: Buffer.from(privateKey, "base64"), - // format: "der", - // type: "pkcs8", - // }); - - const pk = createPrivateKey({ - key: Buffer.from(privateKey, "base64"), - type: "pkcs8", // 'sec1' or 'pkcs8', depending on the format - format: "der", - }); - - const pair = ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); - // const pair = ecdh.setPrivateKey( - // pk.export({ type: "pkcs8", format: "der" }).toString("base64") - // ); - console.log(`Public key:\n${pair.publicKey.toString("base64")}`); - console.log( - `Encoded public key for P2P API:\n${Buffer.from(pair.publicKey).toString( - "base64" - )}` - ); - return; - } + // convert the public key to PEM format + const publicKeyPEM = `-----BEGIN PUBLIC KEY-----\n${publicKeyBase64 + .replace(/.{64}/g, "$&\n") + .replace(/\n$/g, "")}\n-----END PUBLIC KEY-----\n`; + console.log(`Public key in PEM format:\n${publicKeyPEM.toString()}`); - return new Promise((resolve, reject) => { - // Generate an elliptic curve key pair using the secp256r1 curve - generateKeyPair( - "ec", - { - namedCurve: ecdhCurveName, // is the same as secp256r1 - publicKeyEncoding: { - type: "spki", // Use Subject Public Key Info format - format: "pem", // Encoding format - }, - privateKeyEncoding: { - type: "pkcs8", // Use Public-Key Cryptography Standards 8 format - format: "der", // Encoding format - }, - }, - (err, publicKey, pk) => { - if (err) return reject(err); - - console.log(`Private key ${pk.toString("base64")}`); - console.log(`Public key:\n${publicKey.toString("base64")}`); - console.log( - `Encoded public key for P2P API:\n${Buffer.from(publicKey).toString( - "base64" - )}` - ); - - const pk2 = createPrivateKey({ - key: Buffer.from(pk.toString("base64"), "base64"), - type: "pkcs8", // 'sec1' or 'pkcs8', depending on the format - format: "der", - }); - console.log( - `Private key 2 ${pk2 - .export({ type: "pkcs8", format: "der" }) - .toString("base64")}` - ); - const ecdh = createECDH(ecdhCurveName); - const base64PrivateKey = - "MHcCAQEEIG6AQo/0h2C4sK1cIlTVTFLEmTSzCk++c5jeUG+KjCp6oAoGCCqGSM49AwEHoUQDQgAEZtnrHukMrlO+2rONXOHfncFtgsZ+lqnr5Y0l6XBbeyEOv7iz6SyeUMWtUlWGsWE9sbzMFs7owEhrcz0sxf58eA=="; - - const pair = ecdh.setPrivateKey( - Buffer.from(base64PrivateKey, "base64") - ); - console.log(`Private key 3 ${pair.toString("base64")}`); - - resolve(); - } - ); - }); + // base64 encode the PEM format again to get P2P format + const p2pPublicKey = Buffer.from(publicKeyPEM).toString("base64"); + console.log(`Encoded public key for P2P API:\n${p2pPublicKey}`); }; const encrypt = async ({ privateKey, publicKey, text }) => { From 33701c47587be2bf1c41b868bfafe1a3674cf659 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 27 May 2024 20:28:19 +1000 Subject: [PATCH 6/8] Copied decrypt validator key from P2P repo --- contracts/tasks/crypto.js | 110 ++++++++++++++++++++------------------ contracts/tasks/tasks.js | 47 ++-------------- 2 files changed, 63 insertions(+), 94 deletions(-) diff --git a/contracts/tasks/crypto.js b/contracts/tasks/crypto.js index cc83015255..0930977361 100644 --- a/contracts/tasks/crypto.js +++ b/contracts/tasks/crypto.js @@ -1,12 +1,6 @@ -const { - createCipheriv, - createECDH, - createDecipheriv, - randomBytes, -} = require("node:crypto"); +const { createECDH, createCipheriv } = require("node:crypto"); const ecdhCurveName = "prime256v1"; -const encryptionAlgorithm = "aes-256-cbc"; const genECDHKey = async ({ privateKey }) => { const ecdh = createECDH(ecdhCurveName); @@ -34,61 +28,75 @@ const genECDHKey = async ({ privateKey }) => { console.log(`Encoded public key for P2P API:\n${p2pPublicKey}`); }; -const encrypt = async ({ privateKey, publicKey, text }) => { - const ecdh = createECDH(ecdhCurveName); - ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); - - console.log(`My private key ${ecdh.getPrivateKey("base64")}`); - console.log(`My public key ${ecdh.getPublicKey("base64", "spki")}`); - - const otherPublicKey = Buffer.from(publicKey, "base64"); - - const secretKey = ecdh.computeSecret(otherPublicKey, "base64", "base64"); - console.log("secretKey:", secretKey.toString("base64")); +const decryptValidatorKey = async ({ privateKey, encryptedMessage }) => { + const client = createECDH("prime256v1"); + client.setPrivateKey(privateKey, "hex"); - const initializationVector = randomBytes(16); - console.log( - "initialization vector:", - initializationVector.toString("base64") + const decryptedMessage = decrypt( + client.getPrivateKey(), + Buffer.from(encryptedMessage, "base64") ); - const cipher = createCipheriv( - encryptionAlgorithm, - secretKey, - initializationVector - ); - - const encrypted = Buffer.concat([cipher.update(text), cipher.final()]); - - console.log("encrypted content:", encrypted.toString("base64")); + console.log(decryptedMessage.toString("utf8")); }; -const decrypt = async ({ privateKey, publicKey, text, iv }) => { - const ecdh = createECDH(ecdhCurveName); - ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); +const decrypt = (privateKey, msg) => { + const ecdh = createECDH("prime256v1"); + ecdh.setPrivateKey(privateKey); + const epk = msg.slice(0, 65); + const message = msg.slice(65, msg.length - 32); + const sharedSecret = ecdh.computeSecret(epk); + const { encKey, macKey } = deriveKeys(sharedSecret, Buffer.alloc(0), 16); + const tag = messageTag(macKey, message, Buffer.alloc(0)); + if (tag.toString("hex") !== msg.slice(msg.length - 32).toString("hex")) { + throw new Error("tag mismatch"); + } + return symDecrypt(encKey, message); +}; - console.log(`My private key ${ecdh.getPrivateKey("base64")}`); - console.log(`My public key ${ecdh.getPublicKey("base64", "spki")}`); +const deriveKeys = (secret, s1, keyLen) => { + const keys = concatKDF(secret, s1, keyLen * 2); + const encKey = keys.slice(0, keyLen); + const macKey = crypto + .createHash("sha256") + .update(keys.slice(keyLen, keyLen * 2)) + .digest(); + return { encKey, macKey }; +}; - const otherPublicKey = Buffer.from(publicKey, "base64"); - const secretKey = ecdh.computeSecret(otherPublicKey, "base64", "base64"); - console.log("Secret:", secretKey); +const messageTag = (macKey, message, s2) => { + return crypto + .createHmac("sha256", macKey) + .update(message) + .update(s2) + .digest(); +}; - const decipher = createDecipheriv( - encryptionAlgorithm, - secretKey, - Buffer.from(iv, "base64") - ); +const symDecrypt = (key, ct) => { + const c = createCipheriv("aes-128-ctr", key, ct.slice(0, 16)); + const m = Buffer.alloc(ct.length - 16); + c.update(ct.slice(16)).copy(m); + return m; +}; - const decryptedContent = Buffer.concat([ - decipher.update(Buffer.from(text, "base64")), - decipher.final(), - ]); - console.log(`Decrypted content: ${decryptedContent.toString()}`); +const concatKDF = (secret, s1, keyLen) => { + let hashSum = Buffer.from(""); + for (let ctr = 1; hashSum.length < keyLen; ctr++) { + const ctrs = Buffer.from([ctr >> 24, ctr >> 16, ctr >> 8, ctr]); // Buffer.from([ctr >> 24, ctr >> 16, ctr >> 8, ctr]) + const tmp = [ + hashSum, + crypto + .createHash("sha256") + .update(Buffer.concat([ctrs, secret, s1])) + .digest(), + ]; + console.log(tmp); + hashSum = Buffer.concat(tmp); + } + return hashSum.slice(0, keyLen); }; module.exports = { genECDHKey, - encrypt, - decrypt, + decryptValidatorKey, }; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 555e90c31e..0e904ff3b9 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -11,7 +11,7 @@ const { resolveContract } = require("../utils/resolvers"); const { KeyValueStoreClient } = require("defender-kvstore-client"); const { operateValidators } = require("./validator"); const { formatUnits } = require("ethers/lib/utils"); -const { genECDHKey, encrypt, decrypt } = require("./crypto.js"); +const { genECDHKey, decryptValidatorKey } = require("./crypto.js"); const { storeStorageLayoutForAllContracts, @@ -994,33 +994,6 @@ task("genECDHKey").setAction(async (_, __, runSuper) => { return runSuper(); }); -subtask( - "encrypt", - "Encrypt a message using a Elliptic-curve Diffie–Hellman (ECDH) key pair" -) - .addParam( - "privateKey", - "Private key to encrypt the message with in hex format without the 0x prefix", - undefined, - types.string - ) - .addParam( - "publicKey", - "Public key of the other party in hex format without the 0x prefix", - undefined, - types.string - ) - .addParam( - "text", - "Message that needs to be encrypted", - undefined, - types.string - ) - .setAction(encrypt); -task("encrypt").setAction(async (_, __, runSuper) => { - return runSuper(); -}); - subtask( "decrypt", "Decrypt a message using a Elliptic-curve Diffie–Hellman (ECDH) key pair" @@ -1032,24 +1005,12 @@ subtask( types.string ) .addParam( - "publicKey", - "Public key of the other party in hex format without the 0x prefix", - undefined, - types.string - ) - .addParam( - "text", - "Encrypted message that needs to be decrypted in base64 format", - undefined, - types.string - ) - .addParam( - "iv", - "InitializationVector in hex format without the 0x prefix", + "encryptedKey", + "Encrypted validator key returned form P2P API", undefined, types.string ) - .setAction(decrypt); + .setAction(decryptValidatorKey); task("decrypt").setAction(async (_, __, runSuper) => { return runSuper(); }); From a6cab8bea591ec0ac8ecfee65fa0d283520b5276 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 4 Jun 2024 22:29:25 +1000 Subject: [PATCH 7/8] Decryption of validator private key from P2P API is working --- contracts/package.json | 1 + contracts/tasks/crypto.js | 48 +++++++++++++++++++++---------------- contracts/tasks/tasks.js | 2 +- contracts/yarn.lock | 50 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 19dcbdfc18..b929ca410a 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -53,6 +53,7 @@ "@openzeppelin/defender-relay-client": "^1.54.4", "@openzeppelin/defender-sdk": "^1.13.1", "@openzeppelin/hardhat-upgrades": "^1.10.0", + "@rigidity/bls-signatures": "^2.0.5", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.2.3", diff --git a/contracts/tasks/crypto.js b/contracts/tasks/crypto.js index 0930977361..0e4d2735bb 100644 --- a/contracts/tasks/crypto.js +++ b/contracts/tasks/crypto.js @@ -1,4 +1,10 @@ -const { createECDH, createCipheriv } = require("node:crypto"); +const bls = require("@rigidity/bls-signatures"); +const { + createCipheriv, + createECDH, + createHash, + createHmac, +} = require("node:crypto"); const ecdhCurveName = "prime256v1"; @@ -6,19 +12,27 @@ const genECDHKey = async ({ privateKey }) => { const ecdh = createECDH(ecdhCurveName); if (privateKey) { - ecdh.setPrivateKey(Buffer.from(privateKey, "base64")); + ecdh.setPrivateKey(Buffer.from(privateKey, "hex")); } else { ecdh.generateKeys(); } - const privateKeyBase64 = ecdh.getPrivateKey("base64"); + const privateKeyHex = ecdh.getPrivateKey("hex"); const publicKeyBase64 = ecdh.getPublicKey("base64"); - console.log(`Private key: ${privateKeyBase64}`); + console.log(`Private key: ${privateKeyHex}`); console.log(`Public key: ${publicKeyBase64}`); - // convert the public key to PEM format - const publicKeyPEM = `-----BEGIN PUBLIC KEY-----\n${publicKeyBase64 + const subtleKey = await crypto.subtle.importKey( + "raw", + ecdh.getPublicKey(), + { name: "ECDH", namedCurve: "P-256" }, + true, + [] + ); + const fmtKey = await crypto.subtle.exportKey("spki", subtleKey); + const publicKeyPEM = `-----BEGIN PUBLIC KEY-----\n${Buffer.from(fmtKey) + .toString("base64") .replace(/.{64}/g, "$&\n") .replace(/\n$/g, "")}\n-----END PUBLIC KEY-----\n`; console.log(`Public key in PEM format:\n${publicKeyPEM.toString()}`); @@ -28,16 +42,17 @@ const genECDHKey = async ({ privateKey }) => { console.log(`Encoded public key for P2P API:\n${p2pPublicKey}`); }; -const decryptValidatorKey = async ({ privateKey, encryptedMessage }) => { +const decryptValidatorKey = async ({ privateKey, message }) => { const client = createECDH("prime256v1"); client.setPrivateKey(privateKey, "hex"); - const decryptedMessage = decrypt( + const validatorPrivateKey = decrypt( client.getPrivateKey(), - Buffer.from(encryptedMessage, "base64") + Buffer.from(message, "base64") ); - console.log(decryptedMessage.toString("utf8")); + const vsk = bls.PrivateKey.fromBytes(validatorPrivateKey); + console.log(`Validator public key: ${vsk.getG1().toHex()}`); }; const decrypt = (privateKey, msg) => { @@ -57,19 +72,14 @@ const decrypt = (privateKey, msg) => { const deriveKeys = (secret, s1, keyLen) => { const keys = concatKDF(secret, s1, keyLen * 2); const encKey = keys.slice(0, keyLen); - const macKey = crypto - .createHash("sha256") + const macKey = createHash("sha256") .update(keys.slice(keyLen, keyLen * 2)) .digest(); return { encKey, macKey }; }; const messageTag = (macKey, message, s2) => { - return crypto - .createHmac("sha256", macKey) - .update(message) - .update(s2) - .digest(); + return createHmac("sha256", macKey).update(message).update(s2).digest(); }; const symDecrypt = (key, ct) => { @@ -85,12 +95,10 @@ const concatKDF = (secret, s1, keyLen) => { const ctrs = Buffer.from([ctr >> 24, ctr >> 16, ctr >> 8, ctr]); // Buffer.from([ctr >> 24, ctr >> 16, ctr >> 8, ctr]) const tmp = [ hashSum, - crypto - .createHash("sha256") + createHash("sha256") .update(Buffer.concat([ctrs, secret, s1])) .digest(), ]; - console.log(tmp); hashSum = Buffer.concat(tmp); } return hashSum.slice(0, keyLen); diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index fd36530db4..436ddf7b80 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -1195,7 +1195,7 @@ subtask( types.string ) .addParam( - "encryptedKey", + "message", "Encrypted validator key returned form P2P API", undefined, types.string diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 5e0638a4f1..38bcc30b88 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -1294,6 +1294,15 @@ path-browserify "^1.0.0" url "^0.11.0" +"@rigidity/bls-signatures@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@rigidity/bls-signatures/-/bls-signatures-2.0.5.tgz#4bd32a4594bb0c61a54101e4e1736ffc4de17e49" + integrity sha512-ybuB+z1+Duyy7wuyBbuM0xRc+pEbMqDQ7UjjkzceYQRWg78RmsFcNs0tNvZbmThYc/IFvb7sWmdgzbOcvtevYA== + dependencies: + chai "^4.3.6" + jssha "^3.2.0" + randombytes "^2.1.0" + "@rollup/plugin-commonjs@^25.0.7": version "25.0.7" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz#145cec7589ad952171aeb6a585bbeabd0fd3b4cf" @@ -2757,6 +2766,19 @@ chai@^4.3.4: pathval "^1.1.1" type-detect "^4.0.5" +chai@^4.3.6: + version "4.4.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" + integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2789,6 +2811,13 @@ check-error@^1.0.2: resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + chokidar@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" @@ -3311,7 +3340,7 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -deep-eql@^4.1.2: +deep-eql@^4.1.2, deep-eql@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== @@ -4694,6 +4723,11 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" @@ -5886,6 +5920,11 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" +jssha@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jssha/-/jssha-3.3.1.tgz#c5b7fc7fb9aa745461923b87df0e247dd59c7ea8" + integrity sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ== + jszip@^3.10.1, jszip@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" @@ -6164,6 +6203,13 @@ loupe@^2.3.1: dependencies: get-func-name "^2.0.0" +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -8598,7 +8644,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@^4.0.0, type-detect@^4.0.5: +type-detect@^4.0.0, type-detect@^4.0.5, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== From 9b99aa2a40254f1466710538dfeb4dcd1a751883 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 5 Jun 2024 10:24:22 +1000 Subject: [PATCH 8/8] formatting of crypto functions --- contracts/tasks/crypto.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/contracts/tasks/crypto.js b/contracts/tasks/crypto.js index 0e4d2735bb..b4c038880b 100644 --- a/contracts/tasks/crypto.js +++ b/contracts/tasks/crypto.js @@ -1,5 +1,6 @@ const bls = require("@rigidity/bls-signatures"); const { + subtle, createCipheriv, createECDH, createHash, @@ -17,20 +18,18 @@ const genECDHKey = async ({ privateKey }) => { ecdh.generateKeys(); } - const privateKeyHex = ecdh.getPrivateKey("hex"); const publicKeyBase64 = ecdh.getPublicKey("base64"); - console.log(`Private key: ${privateKeyHex}`); console.log(`Public key: ${publicKeyBase64}`); - const subtleKey = await crypto.subtle.importKey( + const subtleKey = await subtle.importKey( "raw", ecdh.getPublicKey(), { name: "ECDH", namedCurve: "P-256" }, true, [] ); - const fmtKey = await crypto.subtle.exportKey("spki", subtleKey); + const fmtKey = await subtle.exportKey("spki", subtleKey); const publicKeyPEM = `-----BEGIN PUBLIC KEY-----\n${Buffer.from(fmtKey) .toString("base64") .replace(/.{64}/g, "$&\n") @@ -43,21 +42,16 @@ const genECDHKey = async ({ privateKey }) => { }; const decryptValidatorKey = async ({ privateKey, message }) => { - const client = createECDH("prime256v1"); - client.setPrivateKey(privateKey, "hex"); + const ecdh = createECDH(ecdhCurveName); + ecdh.setPrivateKey(privateKey, "hex"); - const validatorPrivateKey = decrypt( - client.getPrivateKey(), - Buffer.from(message, "base64") - ); + const validatorPrivateKey = decrypt(ecdh, Buffer.from(message, "base64")); const vsk = bls.PrivateKey.fromBytes(validatorPrivateKey); console.log(`Validator public key: ${vsk.getG1().toHex()}`); }; -const decrypt = (privateKey, msg) => { - const ecdh = createECDH("prime256v1"); - ecdh.setPrivateKey(privateKey); +const decrypt = (ecdh, msg) => { const epk = msg.slice(0, 65); const message = msg.slice(65, msg.length - 32); const sharedSecret = ecdh.computeSecret(epk);