tornado-nova/src/utils.js
2021-06-15 15:48:26 +03:00

101 lines
2.9 KiB
JavaScript

const crypto = require('crypto')
const { ethers } = require('hardhat')
const BigNumber = ethers.BigNumber
const { poseidon } = require('circomlib')
const poseidonHash = (items) => BigNumber.from(poseidon(items).toString())
const poseidonHash2 = (a, b) => poseidonHash([a, b])
const FIELD_SIZE = BigNumber.from(
'21888242871839275222246405745257275088548364400416034343698204186575808495617',
)
/** Generate random number of specified byte length */
const randomBN = (nbytes = 31) => BigNumber.from(crypto.randomBytes(nbytes))
function getExtDataHash({ recipient, relayer, encryptedOutput1, encryptedOutput2 }) {
const abi = new ethers.utils.AbiCoder()
const encodedData = abi.encode(
['tuple(address recipient,address relayer,bytes encryptedOutput1,bytes encryptedOutput2)'],
[
{
recipient: toFixedHex(recipient, 20),
relayer: toFixedHex(relayer, 20),
encryptedOutput1: encryptedOutput1,
encryptedOutput2: encryptedOutput2,
},
],
)
const hash = ethers.utils.keccak256(encodedData)
return BigNumber.from(hash).mod(FIELD_SIZE)
}
/** BigNumber to hex string of specified length */
const toFixedHex = (number, length = 32) =>
'0x' +
(number instanceof Buffer
? number.toString('hex')
: BigNumber.from(number).toHexString().slice(2)
).padStart(length * 2, '0')
const toBuffer = (value, length) =>
Buffer.from(
BigNumber.from(value)
.toHexString()
.slice(2)
.padStart(length * 2, '0'),
'hex',
)
async function takeSnapshot() {
return await ethers.provider.send('evm_snapshot', [])
}
async function revertSnapshot(id) {
await ethers.provider.send('evm_revert', [id])
}
function packEncryptedMessage(encryptedMessage) {
const nonceBuf = Buffer.from(encryptedMessage.nonce, 'base64')
const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, 'base64')
const ciphertextBuf = Buffer.from(encryptedMessage.ciphertext, 'base64')
const messageBuff = Buffer.concat([
Buffer.alloc(24 - nonceBuf.length),
nonceBuf,
Buffer.alloc(32 - ephemPublicKeyBuf.length),
ephemPublicKeyBuf,
ciphertextBuf,
])
return '0x' + messageBuff.toString('hex')
}
function unpackEncryptedMessage(encryptedMessage) {
if (encryptedMessage.slice(0, 2) === '0x') {
encryptedMessage = encryptedMessage.slice(2)
}
const messageBuff = Buffer.from(encryptedMessage, 'hex')
const nonceBuf = messageBuff.slice(0, 24)
const ephemPublicKeyBuf = messageBuff.slice(24, 56)
const ciphertextBuf = messageBuff.slice(56)
return {
version: 'x25519-xsalsa20-poly1305',
nonce: nonceBuf.toString('base64'),
ephemPublicKey: ephemPublicKeyBuf.toString('base64'),
ciphertext: ciphertextBuf.toString('base64'),
}
}
module.exports = {
FIELD_SIZE,
randomBN,
toFixedHex,
toBuffer,
poseidonHash,
poseidonHash2,
getExtDataHash,
takeSnapshot,
revertSnapshot,
packEncryptedMessage,
unpackEncryptedMessage,
}