Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for rsa pss #8

Merged
merged 9 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions contracts/certificate/signers/CRSAPSSSHA2Signer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import {RSAPSS} from "../../utils/RSAPSS.sol";

contract CRSAPSSSHA2Signer is Initializable {
using RSAPSS for bytes;

uint256 public exponent; // RSAPSS exponent

function __CRSAPSSSHA2Signer_init(uint256 exponent_) external initializer {
exponent = exponent_;
}

/**
* @notice Verifies ICAO member RSAPSS signature of the X509 certificate SA.
*/
function verifyICAOSignature(
bytes memory x509SignedAttributes_,
bytes memory icaoMemberSignature_,
bytes memory icaoMemberKey_
) external view returns (bool) {
return
x509SignedAttributes_.verify(
icaoMemberSignature_,
abi.encodePacked(exponent),
icaoMemberKey_
);
}
}
1 change: 1 addition & 0 deletions contracts/registration/types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity 0.8.16;

bytes32 constant C_RSA_4096 = keccak256("C_RSA_4096");
bytes32 constant C_RSA_2048 = keccak256("C_RSA_2048");
bytes32 constant C_RSAPSS_4096 = keccak256("C_RSAPSS_4096");

bytes32 constant P_NO_AA = keccak256("P_NO_AA");
bytes32 constant P_RSA_SHA1_2688 = keccak256("P_RSA_SHA1_2688");
Expand Down
120 changes: 120 additions & 0 deletions contracts/utils/RSAPSS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import {RSA} from "./RSA.sol";

library RSAPSS {
uint256 constant HASH_LEN = 32;
uint256 constant SALT_LEN = 32;
uint256 constant MS_BITS = 4095 & 7;
uint256 constant MS_BYTES = 512;

/**
* @notice RSAPSS verification algorithm
*/
function verify(
bytes memory message_,
bytes memory s_,
bytes memory e_,
bytes memory n_
) internal view returns (bool) {
if (s_.length == 0 || e_.length == 0 || n_.length == 0) {
return false;
}

bytes memory decipher_ = RSA.decrypt(s_, e_, n_);

return pss(message_, decipher_);
}

function pss(bytes memory message_, bytes memory signature_) private pure returns (bool) {
if (message_.length > 2 ** 61 - 1) {
return false;
}

bytes32 messageHash_ = sha256(message_);

if (MS_BYTES < HASH_LEN + SALT_LEN + 2) {
return false;
}

if (signature_[MS_BYTES - 1] != hex"BC") {
return false;
}

bytes memory db_ = new bytes(MS_BYTES - HASH_LEN - 1);
bytes memory h_ = new bytes(HASH_LEN);

for (uint256 i = 0; i < db_.length; ++i) {
db_[i] = signature_[i];
}

for (uint256 i = 0; i < HASH_LEN; ++i) {
h_[i] = signature_[i + db_.length];
}

if (uint8(db_[0] & bytes1(uint8(((0xFF << (MS_BITS)))))) == 1) {
return false;
}

bytes memory dbMask_ = mgf(h_, db_.length);

for (uint256 i = 0; i < db_.length; ++i) {
db_[i] ^= dbMask_[i];
}

if (MS_BITS > 0) {
db_[0] &= bytes1(uint8(0xFF >> (8 - MS_BITS)));
}

uint256 zeroBytes_;

for (
zeroBytes_ = 0;
db_[zeroBytes_] == 0 && zeroBytes_ < (db_.length - 1);
++zeroBytes_
) {}

if (db_[zeroBytes_++] != hex"01") {
return false;
}

bytes memory salt_ = new bytes(SALT_LEN);

for (uint256 i = 0; i < salt_.length; ++i) {
salt_[i] = db_[db_.length - salt_.length + i];
}

bytes32 hh_ = sha256(abi.encodePacked(hex"0000000000000000", messageHash_, salt_));

if (bytes32(h_) != hh_) {
return false;
}

return true;
}

function mgf(
bytes memory message_,
uint256 maskLen_
) private pure returns (bytes memory res_) {
bytes memory cnt_ = new bytes(4);

require(maskLen_ <= (2 ** 32) * HASH_LEN, "RSAPSS: mask too lengthy");

for (uint256 i = 0; i < (maskLen_ + HASH_LEN - 1) / HASH_LEN; ++i) {
cnt_[0] = bytes1(uint8((i >> 24) & 255));
cnt_[1] = bytes1(uint8((i >> 16) & 255));
cnt_[2] = bytes1(uint8((i >> 8) & 255));
cnt_[3] = bytes1(uint8(i & 255));

bytes32 hashedResInter_ = sha256(abi.encodePacked(message_, cnt_));

res_ = abi.encodePacked(res_, hashedResInter_);
}

assembly {
mstore(res_, maskLen_)
}
}
}
29 changes: 14 additions & 15 deletions deploy/10_setup.migration.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
import { Deployer } from "@solarity/hardhat-migrate";

import {
StateKeeperMock__factory,
Registration2Mock__factory,
CRSASHA2Dispatcher__factory,
PECDSASHA1Dispatcher__factory,
PInternalVerifier2__factory,
PNOAADispatcher__factory,
PRSASHA1Dispatcher__factory,
PECDSASHA1Dispatcher__factory,
PUniversal2048Verifier2__factory,
PUniversal4096Verifier2__factory,
PInternalVerifier2__factory,
Registration2Mock__factory,
StateKeeperMock__factory,
} from "@ethers-v6";

import {
Z_UNIVERSAL_2048,
Z_UNIVERSAL_4096,
Z_INTERNAL,
C_RSA_4096,
C_RSA_2048,
P_NO_AA,
C_RSA_4096,
C_RSAPSS_4096,
P_ECDSA_SHA1_2704,
P_NO_AA,
P_RSA_SHA1_2688,
P_RSA_SHA1_2688_3,
Z_INTERNAL,
Z_UNIVERSAL_2048,
Z_UNIVERSAL_4096,
} from "@/scripts/utils/types";

import { getConfig } from "./config/config";

export = async (deployer: Deployer) => {
const config = (await getConfig())!;

const stateKeeper = await deployer.deployed(StateKeeperMock__factory, "StateKeeper Proxy");

const registration = await deployer.deployed(Registration2Mock__factory, "Registration Proxy");

const cRsa4096Dispatcher = await deployer.deployed(CRSASHA2Dispatcher__factory, "CRSASHA2Dispatcher 65537 512");
const cRsa2048Dispatcher = await deployer.deployed(CRSASHA2Dispatcher__factory, "CRSASHA2Dispatcher 65537 256");

const cRsa4096Dispatcher = await deployer.deployed(CRSASHA2Dispatcher__factory, "CRSASHA2Dispatcher 512");
const cRsa2048Dispatcher = await deployer.deployed(CRSASHA2Dispatcher__factory, "CRSASHA2Dispatcher 256");
const cRsaPss4096Dispatcher = await deployer.deployed(CRSASHA2Dispatcher__factory, "CRSAPSSSHA2Dispatcher 512");
const pRsaSha12688Dispatcher = await deployer.deployed(PRSASHA1Dispatcher__factory, "PRSASHA1Dispatcher 65537");
const pRsaSha126883Dispatcher = await deployer.deployed(PRSASHA1Dispatcher__factory, "PRSASHA1Dispatcher 3");

const pNoAaDispatcher = await deployer.deployed(PNOAADispatcher__factory);
const pEcdsaSha12704Dispatcher = await deployer.deployed(PECDSASHA1Dispatcher__factory);

Expand All @@ -48,6 +46,7 @@ export = async (deployer: Deployer) => {

await registration.mockAddCertificateDispatcher(C_RSA_4096, await cRsa4096Dispatcher.getAddress());
await registration.mockAddCertificateDispatcher(C_RSA_2048, await cRsa2048Dispatcher.getAddress());
await registration.mockAddCertificateDispatcher(C_RSAPSS_4096, await cRsaPss4096Dispatcher.getAddress());

await registration.mockAddPassportDispatcher(P_NO_AA, await pNoAaDispatcher.getAddress());
await registration.mockAddPassportDispatcher(P_RSA_SHA1_2688, await pRsaSha12688Dispatcher.getAddress());
Expand Down
4 changes: 2 additions & 2 deletions deploy/11_downgrade.migration.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Deployer } from "@solarity/hardhat-migrate";

import {
StateKeeper__factory,
StateKeeperMock__factory,
Registration2__factory,
Registration2Mock__factory,
StateKeeper__factory,
StateKeeperMock__factory,
} from "@ethers-v6";

export = async (deployer: Deployer) => {
Expand Down
45 changes: 13 additions & 32 deletions deploy/1_state.migration.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,26 @@
import { Deployer, Reporter } from "@solarity/hardhat-migrate";
import { deployPoseidons } from "./helpers/helper";
import { deployPoseidons, deployProxy, deploySMTProxy } from "./helpers/helper";

import { StateKeeperMock__factory, PoseidonSMT__factory, ERC1967Proxy__factory } from "@ethers-v6";
import { PoseidonSMT, StateKeeperMock, StateKeeperMock__factory } from "@ethers-v6";

import { getConfig } from "./config/config";

const smtInit = async (smt: PoseidonSMT, stateKeeper: StateKeeperMock, config: any) => {
await smt.__PoseidonSMT_init(config.tssSigner, config.chainName, await stateKeeper.getAddress(), config.treeSize);
};

export = async (deployer: Deployer) => {
const config = (await getConfig())!;

await deployPoseidons(deployer, [1, 2, 3, 5]);

let registrationSmt = await deployer.deploy(PoseidonSMT__factory, { name: "RegistrationSMT" });
await deployer.deploy(ERC1967Proxy__factory, [await registrationSmt.getAddress(), "0x"], {
name: "RegistrationSMT Proxy",
});
registrationSmt = await deployer.deployed(PoseidonSMT__factory, "RegistrationSMT Proxy");

let certificatesSmt = await deployer.deploy(PoseidonSMT__factory, { name: "CertificatesSMT" });
await deployer.deploy(ERC1967Proxy__factory, [await certificatesSmt.getAddress(), "0x"], {
name: "CertificatesSMT Proxy",
});
certificatesSmt = await deployer.deployed(PoseidonSMT__factory, "CertificatesSMT Proxy");

let stateKeeper = await deployer.deploy(StateKeeperMock__factory);
await deployer.deploy(ERC1967Proxy__factory, [await stateKeeper.getAddress(), "0x"], {
name: "StateKeeper Proxy",
});
stateKeeper = await deployer.deployed(StateKeeperMock__factory, "StateKeeper Proxy");

await registrationSmt.__PoseidonSMT_init(
config.tssSigner,
config.chainName,
await stateKeeper.getAddress(),
config.treeSize,
);
await certificatesSmt.__PoseidonSMT_init(
config.tssSigner,
config.chainName,
await stateKeeper.getAddress(),
config.treeSize,
);
const registrationSmt = await deploySMTProxy(deployer, "RegistrationSMT");
const certificatesSmt = await deploySMTProxy(deployer, "CertificatesSMT");

const stateKeeper = await deployProxy(deployer, StateKeeperMock__factory, "StateKeeper");

await smtInit(registrationSmt, stateKeeper, config);
await smtInit(certificatesSmt, stateKeeper, config);

await stateKeeper.__StateKeeper_init(
config.tssSigner,
Expand Down
54 changes: 38 additions & 16 deletions deploy/2_registration.migration.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,55 @@
import { Deployer, Reporter } from "@solarity/hardhat-migrate";

import {
StateKeeperMock__factory,
ERC1967Proxy__factory,
Registration2Mock__factory,
CRSAPSSSHA2Signer__factory,
CRSASHA2Dispatcher__factory,
CRSASHA2Signer__factory,
PNOAADispatcher__factory,
PRSASHA1Dispatcher__factory,
PECDSASHA1Authenticator__factory,
PECDSASHA1Dispatcher__factory,
PInternalVerifier2__factory,
PNOAADispatcher__factory,
PRSASHA1Authenticator__factory,
PECDSASHA1Authenticator__factory,
PRSASHA1Dispatcher__factory,
PUniversal2048Verifier2__factory,
PUniversal4096Verifier2__factory,
PInternalVerifier2__factory,
Registration2Mock__factory,
StateKeeperMock__factory,
} from "@ethers-v6";

import { BaseContract } from "ethers";
import { getConfig } from "./config/config";
import { deployProxy } from "./helpers/helper";

const deployCDispatcher = async (
deployer: Deployer,
signer: BaseContract,
keyLength: string,
keyPrefix: string,
name: string,
) => {
const dispatcher = await deployer.deploy(CRSASHA2Dispatcher__factory, { name: `${name} ${keyLength}` });
await dispatcher.__CRSASHA2Dispatcher_init(await signer.getAddress(), keyLength, keyPrefix);
};

const deployCRSASHA2Dispatcher = async (deployer: Deployer, exponent: string, keyLength: string, keyPrefix: string) => {
const signer = await deployer.deploy(CRSASHA2Signer__factory, { name: `CRSASHA2Signer ${exponent} ${keyLength}` });
const dispatcher = await deployer.deploy(CRSASHA2Dispatcher__factory, { name: `CRSASHA2Dispatcher ${keyLength}` });

await signer.__CRSASHA2Signer_init(exponent);
await dispatcher.__CRSASHA2Dispatcher_init(await signer.getAddress(), keyLength, keyPrefix);

await deployCDispatcher(deployer, signer, keyLength, keyPrefix, "CRSASHA2Dispatcher");
};

const deployCRSAPSSSHA2Dispatcher = async (
deployer: Deployer,
exponent: string,
keyLength: string,
keyPrefix: string,
) => {
const signer = await deployer.deploy(CRSAPSSSHA2Signer__factory, {
name: `CRSAPSSSHA2Signer ${exponent} ${keyLength}`,
});
await signer.__CRSAPSSSHA2Signer_init(exponent);

await deployCDispatcher(deployer, signer, keyLength, keyPrefix, "CRSAPSSSHA2Dispatcher");
};

const deployPNOAADispatcher = async (deployer: Deployer) => {
Expand Down Expand Up @@ -61,18 +87,14 @@ export = async (deployer: Deployer) => {
const config = (await getConfig())!;
const stateKeeper = await deployer.deployed(StateKeeperMock__factory, "StateKeeper Proxy");

let registration = await deployer.deploy(Registration2Mock__factory);
await deployer.deploy(ERC1967Proxy__factory, [await registration.getAddress(), "0x"], {
name: "Registration Proxy",
});
registration = await deployer.deployed(Registration2Mock__factory, "Registration Proxy");

const registration = await deployProxy(deployer, Registration2Mock__factory, "Registration");
await registration.__Registration_init(config.tssSigner, config.chainName, await stateKeeper.getAddress());

await deployPVerifiers(deployer);

await deployCRSASHA2Dispatcher(deployer, "65537", "512", "0x0282020100");
await deployCRSASHA2Dispatcher(deployer, "65537", "256", "0x0282010100");
await deployCRSAPSSSHA2Dispatcher(deployer, "65537", "512", "0x0282020100");

await deployPRSASHA12688Dispatcher(deployer, "65537");
await deployPRSASHA12688Dispatcher(deployer, "3");
Expand Down
Loading
Loading