mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
documentation
This commit is contained in:
parent
f606016994
commit
922457d12b
@ -34,6 +34,11 @@ function unpackEncryptedMessage(encryptedMessage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Keypair {
|
class Keypair {
|
||||||
|
/**
|
||||||
|
* Initialize a new keypair. Generates a random private key if not defined
|
||||||
|
*
|
||||||
|
* @param {string} privkey
|
||||||
|
*/
|
||||||
constructor(privkey = ethers.Wallet.createRandom().privateKey) {
|
constructor(privkey = ethers.Wallet.createRandom().privateKey) {
|
||||||
this.privkey = privkey
|
this.privkey = privkey
|
||||||
this.pubkey = poseidonHash([this.privkey])
|
this.pubkey = poseidonHash([this.privkey])
|
||||||
@ -44,10 +49,21 @@ class Keypair {
|
|||||||
return toFixedHex(this.pubkey) + Buffer.from(this.encryptionKey, 'base64').toString('hex')
|
return toFixedHex(this.pubkey) + Buffer.from(this.encryptionKey, 'base64').toString('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key address for this keypair, alias to {@link toString}
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
address() {
|
address() {
|
||||||
return this.toString()
|
return this.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize new keypair from address string
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @returns {Keypair}
|
||||||
|
*/
|
||||||
static fromString(str) {
|
static fromString(str) {
|
||||||
if (str.length === 130) {
|
if (str.length === 130) {
|
||||||
str = str.slice(2)
|
str = str.slice(2)
|
||||||
@ -62,10 +78,22 @@ class Keypair {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt data using keypair encryption key
|
||||||
|
*
|
||||||
|
* @param {Buffer} bytes
|
||||||
|
* @returns {string} a hex string with encrypted data
|
||||||
|
*/
|
||||||
encrypt(bytes) {
|
encrypt(bytes) {
|
||||||
return packEncryptedMessage(encrypt(this.encryptionKey, { data: bytes.toString('base64') }, 'x25519-xsalsa20-poly1305'))
|
return packEncryptedMessage(encrypt(this.encryptionKey, { data: bytes.toString('base64') }, 'x25519-xsalsa20-poly1305'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt data using keypair private key
|
||||||
|
*
|
||||||
|
* @param {string} data a hex string with data
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
decrypt(data) {
|
decrypt(data) {
|
||||||
return Buffer.from(decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)), 'base64')
|
return Buffer.from(decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)), 'base64')
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ const poseidonHash2 = (a, b) => poseidonHash([a, b])
|
|||||||
const FIELD_SIZE = BigNumber.from(
|
const FIELD_SIZE = BigNumber.from(
|
||||||
'21888242871839275222246405745257275088548364400416034343698204186575808495617',
|
'21888242871839275222246405745257275088548364400416034343698204186575808495617',
|
||||||
)
|
)
|
||||||
|
|
||||||
/** Generate random number of specified byte length */
|
/** Generate random number of specified byte length */
|
||||||
const randomBN = (nbytes = 31) => BigNumber.from(crypto.randomBytes(nbytes))
|
const randomBN = (nbytes = 31) => BigNumber.from(crypto.randomBytes(nbytes))
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ const toFixedHex = (number, length = 32) =>
|
|||||||
: BigNumber.from(number).toHexString().slice(2)
|
: BigNumber.from(number).toHexString().slice(2)
|
||||||
).padStart(length * 2, '0')
|
).padStart(length * 2, '0')
|
||||||
|
|
||||||
|
/** Convert value into buffer of specified byte length */
|
||||||
const toBuffer = (value, length) =>
|
const toBuffer = (value, length) =>
|
||||||
Buffer.from(
|
Buffer.from(
|
||||||
BigNumber.from(value)
|
BigNumber.from(value)
|
||||||
|
43
src/utxo.js
43
src/utxo.js
@ -1,16 +1,28 @@
|
|||||||
const { ethers } = require('hardhat')
|
const { ethers } = require('hardhat')
|
||||||
const { BigNumber } = ethers
|
const { BigNumber } = ethers
|
||||||
const { randomBN, poseidonHash } = require('./utils')
|
const { randomBN, poseidonHash, toBuffer } = require('./utils')
|
||||||
const Keypair = require('./keypair')
|
const Keypair = require('./keypair')
|
||||||
|
|
||||||
class Utxo {
|
class Utxo {
|
||||||
constructor({ amount = 0, keypair = new Keypair(), blinding = randomBN(), index } = {}) {
|
/**
|
||||||
|
*
|
||||||
|
* @param {BigNumber | BigInt | number | string} amount UTXO amount
|
||||||
|
* @param {BigNumber | BigInt | number | string} blinding Blinding factor
|
||||||
|
* @param {Keypair} keypair
|
||||||
|
* @param {number|null} index UTXO index in the merkle tree
|
||||||
|
*/
|
||||||
|
constructor({ amount = 0, keypair = new Keypair(), blinding = randomBN(), index = null} = {}) {
|
||||||
this.amount = BigNumber.from(amount)
|
this.amount = BigNumber.from(amount)
|
||||||
this.blinding = BigNumber.from(blinding)
|
this.blinding = BigNumber.from(blinding)
|
||||||
this.keypair = keypair
|
this.keypair = keypair
|
||||||
this.index = index
|
this.index = index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns commitment for this UTXO
|
||||||
|
*
|
||||||
|
* @returns {BigNumber}
|
||||||
|
*/
|
||||||
getCommitment() {
|
getCommitment() {
|
||||||
if (!this._commitment) {
|
if (!this._commitment) {
|
||||||
this._commitment = poseidonHash([this.amount, this.blinding, this.keypair.pubkey])
|
this._commitment = poseidonHash([this.amount, this.blinding, this.keypair.pubkey])
|
||||||
@ -18,6 +30,11 @@ class Utxo {
|
|||||||
return this._commitment
|
return this._commitment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns nullifier for this UTXO
|
||||||
|
*
|
||||||
|
* @returns {BigNumber}
|
||||||
|
*/
|
||||||
getNullifier() {
|
getNullifier() {
|
||||||
if (!this._nullifier) {
|
if (!this._nullifier) {
|
||||||
if (this.amount > 0 && (this.index === undefined || this.keypair.privkey === undefined || this.keypair.privkey === null)) {
|
if (this.amount > 0 && (this.index === undefined || this.keypair.privkey === undefined || this.keypair.privkey === null)) {
|
||||||
@ -28,18 +45,24 @@ class Utxo {
|
|||||||
return this._nullifier
|
return this._nullifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt UTXO data using the current keypair
|
||||||
|
*
|
||||||
|
* @returns {string} `0x`-prefixed hex string with data
|
||||||
|
*/
|
||||||
encrypt() {
|
encrypt() {
|
||||||
const blindingBuf = Buffer.from(this.blinding.toHexString().slice(2), 'hex')
|
const bytes = Buffer.concat([toBuffer(this.blinding, 31), toBuffer(this.amount, 31)])
|
||||||
const amountBuf = Buffer.from(this.amount.toHexString().slice(2), 'hex')
|
|
||||||
const bytes = Buffer.concat([
|
|
||||||
Buffer.alloc(31 - blindingBuf.length),
|
|
||||||
blindingBuf,
|
|
||||||
Buffer.alloc(31 - amountBuf.length),
|
|
||||||
amountBuf,
|
|
||||||
])
|
|
||||||
return this.keypair.encrypt(bytes)
|
return this.keypair.encrypt(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt a UTXO
|
||||||
|
*
|
||||||
|
* @param {Keypair} keypair keypair used to decrypt
|
||||||
|
* @param {string} data hex string with data
|
||||||
|
* @param {number} index UTXO index in merkle tree
|
||||||
|
* @returns {Utxo}
|
||||||
|
*/
|
||||||
static decrypt(keypair, data, index) {
|
static decrypt(keypair, data, index) {
|
||||||
const buf = keypair.decrypt(data)
|
const buf = keypair.decrypt(data)
|
||||||
return new Utxo({
|
return new Utxo({
|
||||||
|
@ -8,8 +8,6 @@ const {
|
|||||||
toFixedHex,
|
toFixedHex,
|
||||||
takeSnapshot,
|
takeSnapshot,
|
||||||
revertSnapshot,
|
revertSnapshot,
|
||||||
packEncryptedMessage,
|
|
||||||
unpackEncryptedMessage,
|
|
||||||
} = require('../src/utils')
|
} = require('../src/utils')
|
||||||
const Utxo = require('../src/utxo')
|
const Utxo = require('../src/utxo')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user