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

Update Client Service to enable Regulator for transfers #1373

Merged
merged 10 commits into from
Feb 12, 2023
1 change: 1 addition & 0 deletions common-files/constants/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"DEPOSIT": "deposit",
"DEPOSIT_FEE": "depositfee",
"TRANSFER": "transfer",
"TRANSFER_REGULATOR": "transfer_regulator",
"WITHDRAW": "withdraw",
"TOKENISE": "tokenise",
"BURN": "burn",
Expand Down
8 changes: 8 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ module.exports = {
`ws://${process.env.BLOCKCHAIN_WS_HOST}:${process.env.BLOCKCHAIN_PORT}${
process.env.BLOCKCHAIN_PATH || ''
}`,
REGULATOR_URL: process.env.REGULATOR_URL,
NONCE_ENCRYPTION_BITS: process.env.NONCE_ENCRYPTION_BITS || 48,
ETH_PRIVATE_KEY: process.env.ETH_PRIVATE_KEY, // owner's/deployer's private key
ETH_ADDRESS: process.env.ETH_ADDRESS,
WEB3_OPTIONS: {
Expand Down Expand Up @@ -165,6 +167,12 @@ module.exports = {
isEscrowRequired: false,
isWithdrawing: false,
},
transfer_regulator: {
numberNullifiers: 4,
numberCommitments: 3,
isEscrowRequired: false,
isWithdrawing: false,
},
withdraw: {
numberNullifiers: 4,
numberCommitments: 2,
Expand Down
5 changes: 3 additions & 2 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ services:
- mongodb
environment:
AUTOSTART_RETRIES: ${AUTOSTART_RETRIES:-600}
BLOCKCHAIN_URL: ${BLOCKCHAIN_URL}
BLOCKCHAIN_URL: ${BLOCKCHAIN_URL}
BLOCKCHAIN_WS_HOST: ${BLOCKCHAIN_WS_HOST:-blockchain}
BLOCKCHAIN_PORT: ${BLOCKCHAIN_PORT:-8546}
CIRCOM_WORKER_HOST: ${CIRCOM_WORKER_HOST:-worker}
Expand All @@ -58,6 +58,7 @@ services:
OPTIMIST_PORT: ${OPTIMIST_PORT:-80}
STATE_GENESIS_BLOCK: ${STATE_GENESIS_BLOCK:-0}
USE_EXTERNAL_NODE: ${USE_EXTERNAL_NODE}
REGULATOR_URL: ${REGULATOR_URL}
daveroga marked this conversation as resolved.
Show resolved Hide resolved
command: ['npm', 'run', 'dev']

# Temporary container to deploy contracts and circuits and populate volumes
Expand Down Expand Up @@ -99,7 +100,7 @@ services:
USDC_RESTRICT: ${USDC_RESTRICT}
UPGRADE: ${UPGRADE_CONTRACTS}
WHITELISTING: ${WHITELISTING}
WETH_RESTRICT: ${WETH_RESTRICT}
WETH_RESTRICT: ${WETH_RESTRICT}

hosted-utils-api-server:
build:
Expand Down
12 changes: 11 additions & 1 deletion nightfall-client/src/routes/transfer.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
/**
Route for transferring a crypto commitment.
*/
import config from 'config';
import express from 'express';
import transfer from '../services/transfer.mjs';
import transferRegulator from '../services/transfer-regulator.mjs';

const { REGULATOR_URL } = config;
const router = express.Router();

router.post('/', async (req, res, next) => {
try {
const { rawTransaction: txDataToSign, transaction } = await transfer(req.body);
let txDataToSign;
let transaction;

if (!REGULATOR_URL) {
({ rawTransaction: txDataToSign, transaction } = await transfer(req.body));
} else {
({ rawTransaction: txDataToSign, transaction } = await transferRegulator(req.body));
}
res.json({ txDataToSign, transaction });
} catch (err) {
res.json({ error: err.message });
Expand Down
26 changes: 19 additions & 7 deletions nightfall-client/src/services/commitment-sync.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
commitmentsync services to decrypt commitments from transaction blockproposed events
or use clientCommitmentSync to decrypt when new zkpPrivateKey is received.
*/

import config from 'config';
import logger from '@polygon-nightfall/common-files/utils/logger.mjs';
import { generalise } from 'general-number';
import { edwardsDecompress } from '@polygon-nightfall/common-files/utils/curve-maths/curves.mjs';
Expand All @@ -15,7 +15,7 @@ import { ZkpKeys } from './keys.mjs';
import Commitment from '../classes/commitment.mjs';

const { ZERO } = constants;

const { REGULATOR_URL } = config;
/**
decrypt commitments for a transaction given zkpPrivateKeys and nullifierKeys.
*/
Expand All @@ -30,11 +30,23 @@ export async function decryptCommitment(transaction, zkpPrivateKey, nullifierKey
transaction.recipientAddress, // It contains the tokenID encrypted (which is a field)
...transaction.compressedSecrets,
];
const [packedErc, unpackedTokenID, ...rest] = decrypt(
generalise(key),
generalise(edwardsDecompress(transaction.tokenId)), // Compressed public key is stored in token ID
generalise(cipherTexts),
);
let packedErc;
let unpackedTokenID;
let rest;
if (!REGULATOR_URL) {
[packedErc, unpackedTokenID, ...rest] = decrypt(
generalise(key),
generalise(edwardsDecompress(transaction.tokenId)), // Compressed public key is stored in token ID
generalise(cipherTexts),
);
} else {
[packedErc, unpackedTokenID, ...rest] = decrypt(
generalise(key),
generalise(edwardsDecompress(transaction.tokenId)), // Compressed public key is stored in token ID
generalise(cipherTexts),
BigInt(transaction.value),
israelboudoux marked this conversation as resolved.
Show resolved Hide resolved
);
}
const [erc, tokenId] = packSecrets(generalise(packedErc), generalise(unpackedTokenID), 2, 0);
const plainTexts = generalise([erc, tokenId, ...rest]);
const commitment = new Commitment({
Expand Down
51 changes: 44 additions & 7 deletions nightfall-client/src/services/kem-dem.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { scalarMult } from '@polygon-nightfall/common-files/utils/curve-maths/curves.mjs';
import { randValueLT } from '@polygon-nightfall/common-files/utils/crypto/crypto-random.mjs';
import { generalise, stitchLimbs } from 'general-number';
import { generalise, stitchLimbs, GN } from 'general-number';
import poseidon from '@polygon-nightfall/common-files/utils/crypto/poseidon/poseidon.mjs';
import constants from '@polygon-nightfall/common-files/constants/index.mjs';

Expand Down Expand Up @@ -105,19 +105,51 @@ const deDem = (encryptionKey, ciphertexts) => {
return plainTexts;
};

/**
This function generates the transfer key pair for the observers
@function genTransferKeysForObservers
@param {GeneralNumber} senderPrivateKey - The private key of the sender
@param {Array<GeneralNumber>} receiverPublicKey - The public pkd of the recipient
@returns {Promise<Array<GeneralNumber, Array<BigInt>>>} The private and public key pair
*/
const genTransferKeysForObservers = async (senderPrivateKey, receiverPublicKey) => {
daveroga marked this conversation as resolved.
Show resolved Hide resolved
daveroga marked this conversation as resolved.
Show resolved Hide resolved
// We generate a private key derived from sender private key and receiver private key
// to be deterministic for the sender
let privateKey = await kem(senderPrivateKey, receiverPublicKey).toString(16);
privateKey = new GN(`0x${privateKey}`, 'hex');
const publicKey = scalarMult(privateKey.bigInt, BABYJUBJUB.GENERATOR);
return [privateKey, publicKey];
};

/**
This function gets a random nonce between min and max.
@function randomNonce
@param {Number} min - Min value of the nonce
@param {Number} max - Max value of the nonce
@returns {GeneralNumber} The random hex nonce
*/
export const randomNonce = (min, max) => {
const nonce = BigInt(Math.floor(Math.random() * (max - min + 1) + min));
return nonce;
};
daveroga marked this conversation as resolved.
Show resolved Hide resolved

/**
This function performs the kem-dem required to encrypt plaintext.
@function encrypt
@param {GeneralNumber} ephemeralPrivate - The private key that generates the ephemeralPub
@param {Array<GeneralNumber>} ephemeralPub - The ephemeralPubKey
@param {Array<GeneralNumber>} recipientPkds - The public pkd of the recipients
@param {Array<BigInt>} plaintexts - The array of plain text to be encrypted, the ordering is [ercAddress,tokenId, value, salt]
@param {BigInt} nonce - Nonce to do XOR
daveroga marked this conversation as resolved.
Show resolved Hide resolved
@returns {Array<BigInt>} The encrypted ciphertexts.
*/
const encrypt = (ephemeralPrivate, recipientPkds, plaintexts) => {
const encKey = kem(ephemeralPrivate, recipientPkds);
const encrypt = (ephemeralPrivate, recipientPkds, plaintexts, nonce) => {
let encKey = kem(ephemeralPrivate, recipientPkds);
if (nonce) {
// eslint-disable-next-line no-bitwise
encKey ^= nonce;
}
return dem(encKey, plaintexts);
// return cipherTexts;
};

/**
Expand All @@ -126,11 +158,16 @@ This function performs the kem-deDem required to decrypt plaintext.
@param {GeneralNumber} privateKey - The private key of the recipient pkd
@param {Array<GeneralNumber>} ephemeralPub - The ephemeralPubKey
@param {Array<GeneralNumber>} ciphertexts - The array of ciphertexts to be decrypted
@param {BigInt} nonce - Nonce to do XOR
@returns {Array<GeneralNumber>} The decrypted plaintexts, the ordering is [ercAddress,tokenId, value, salt]
*/
const decrypt = (privateKey, ephemeralPub, cipherTexts) => {
const encKey = kem(privateKey, ephemeralPub);
const decrypt = (privateKey, ephemeralPub, cipherTexts, nonce) => {
let encKey = kem(privateKey, ephemeralPub);
if (nonce) {
// eslint-disable-next-line no-bitwise
encKey ^= nonce;
}
return deDem(encKey, cipherTexts);
};

export { encrypt, decrypt, genEphemeralKeys, packSecrets };
export { encrypt, decrypt, genEphemeralKeys, genTransferKeysForObservers, packSecrets };
Loading