mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
101 lines
2.9 KiB
JavaScript
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,
|
|
}
|