fix: note encryption & decription

This commit is contained in:
Wanseob Lim
2020-06-18 05:31:11 +09:00
parent 8404a5a485
commit 3afb92d549
10 changed files with 65 additions and 25 deletions

View File

@@ -30,6 +30,7 @@
"dependencies": {
"@zkopru/babyjubjub": "file:../babyjubjub",
"@zkopru/prisma": "file:../prisma",
"@zkopru/transaction": "file:../transaction",
"@zkopru/utils": "file:../utils",
"bip39": "^3.0.2",
"hdkey": "^1.1.1",

View File

@@ -3,13 +3,14 @@ import Web3 from 'web3'
import { Account, EncryptedKeystoreV3Json, AddAccount } from 'web3-core'
import { Field, Point, EdDSA, signEdDSA, verifyEdDSA } from '@zkopru/babyjubjub'
import { Keystore } from '@zkopru/prisma'
import { Note, ZkTx } from '@zkopru/transaction'
import { hexify } from '@zkopru/utils'
import assert from 'assert'
export class ZkAccount {
private snarkPK: Field
ethPK: string
private ethPK: string
address: string
@@ -58,6 +59,27 @@ export class ZkAccount {
}
}
decrypt(zkTx: ZkTx): Note | undefined {
const { memo } = zkTx
if (!memo) {
return
}
let note: Note | undefined
for (const outflow of zkTx.outflow) {
try {
note = Note.decrypt({
utxoHash: outflow.note,
memo,
privKey: this.snarkPK.toHex(32),
})
} catch (err) {
console.error(err)
}
if (note) break
}
return note
}
static fromEncryptedKeystoreV3Json(
obj: EncryptedKeystoreV3Json,
password: string,

View File

@@ -11,6 +11,7 @@
"references": [
{ "path": "../babyjubjub/tsconfig.build.json", "prepend": false },
{ "path": "../prisma/tsconfig.build.json", "prepend": false },
{ "path": "../transaction/tsconfig.build.json", "prepend": false },
{ "path": "../utils/tsconfig.build.json", "prepend": false }
]
}

View File

@@ -31,7 +31,7 @@
"blake-hash": "^1.1.0",
"bn.js": "^5.1.1",
"circomlib": "^0.1.1",
"snarkjs": "^0.1.25",
"ffjavascript": "^0.1.2",
"soltypes": "^1.2.0",
"web3-utils": "^1.2.6"
},

View File

@@ -1,6 +1,6 @@
import { hexToBuffer, hexify } from '@zkopru/utils'
import bigInt, { BigInteger } from 'big-integer'
import * as snarkjs from 'snarkjs'
import * as ffjs from 'ffjavascript'
import * as circomlib from 'circomlib'
import createBlakeHash from 'blake-hash'
import { Field, F } from './field'
@@ -49,19 +49,20 @@ export class Point {
return Point.from(result[0].toString(), result[1].toString())
}
static getMultiplier(key: string): Field {
const sBuff = circomlib.eddsa.pruneBuffer(
static getMultiplier(key: string | Buffer): Field {
const buff: Buffer = typeof key === 'string' ? hexToBuffer(key) : key
const sBuff = Buffer.from(
createBlakeHash('blake512')
.update(key)
.update(buff)
.digest()
.slice(0, 32),
)
return Field.from(
snarkjs.bigInt
.leBuff2int(sBuff)
.shr(3)
.toString(),
)
sBuff[0] &= 0xf8
sBuff[31] &= 0x7f
sBuff[31] |= 0x40
const s = ffjs.utils.leBuff2int(sBuff)
const multiplier = ffjs.Scalar.shr(s, 3)
return Field.from(multiplier)
}
static isOnJubjub(x: F, y: F): boolean {

View File

@@ -65,5 +65,11 @@ describe('baby jubjub point', () => {
})
expect(verifyEdDSA(msg, signature, pubKey)).toBe(true)
})
describe('fromPrivKey', () => {
it('should be able to same public key using Point.getMultiplier()', () => {
const multiplier = Point.getMultiplier(password)
expect(Point.BASE8.mul(multiplier).toHex()).toBe(pubKey.toHex())
})
})
})
})

View File

@@ -216,18 +216,19 @@ export class Note {
utxoHash: Field
memo: Buffer
privKey: string
}): Note | null {
}): Note | undefined {
const multiplier = Point.getMultiplier(privKey)
const ephemeralPubKey = Point.decode(memo.subarray(0, 32))
const sharedKey = ephemeralPubKey.mul(multiplier).encode()
const data = memo.subarray(32, 81)
const decrypted = chacha20.decrypt(sharedKey, 0, data) // prints "testing"
const decrypted = chacha20.decrypt(sharedKey, 0, data)
const salt = Field.fromBuffer(decrypted.subarray(0, 16))
const tokenAddress = TokenUtils.getTokenAddress(
decrypted.subarray(16, 17)[0],
)
if (tokenAddress === null) return null
if (tokenAddress === null) {
return
}
const value = Field.fromBuffer(decrypted.subarray(17, 49))
const myPubKey: Point = Point.fromPrivKey(privKey)
@@ -262,6 +263,6 @@ export class Note {
return nftNote
}
}
return null
return undefined
}
}

View File

@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/camelcase */
import { BigInteger } from 'big-integer'
import { soliditySha3 } from 'web3-utils'
import * as snarkjs from 'snarkjs'
import { Field } from '@zkopru/babyjubjub'
import * as Utils from '@zkopru/utils'
import { Bytes32 } from 'soltypes'
@@ -297,19 +296,21 @@ export class ZkTx {
}
circomProof(): {
pi_a: bigint[]
pi_b: bigint[][]
pi_c: bigint[]
pi_a: BigInteger[]
pi_b: BigInteger[][]
pi_c: BigInteger[]
protocol: string
} {
if (!this.proof) throw Error('Does not have SNARK proof')
const bigOne = Field.from(1).toIden3BigInt()
const bigZero = Field.zero.toIden3BigInt()
return {
pi_a: [...this.proof.pi_a.map(f => f.toIden3BigInt()), snarkjs.bigInt(1)],
pi_a: [...this.proof.pi_a.map(f => f.toIden3BigInt()), bigOne],
pi_b: [
...this.proof.pi_b.map(arr => arr.map(f => f.toIden3BigInt())),
[snarkjs.bigInt(1), snarkjs.bigInt(0)],
[bigOne, bigZero],
],
pi_c: [...this.proof.pi_c.map(f => f.toIden3BigInt()), snarkjs.bigInt(1)],
pi_c: [...this.proof.pi_c.map(f => f.toIden3BigInt()), bigOne],
protocol: 'groth',
}
}

View File

@@ -94,6 +94,7 @@ export class ZkWallet {
const utxoSqls = await this.db.prisma.note.findMany({
where: {
pubKey: { in: [account.pubKey.toHex()] },
usedFor: null,
},
})
const utxos: Utxo[] = []
@@ -338,6 +339,7 @@ export class ZkWallet {
const { verifier } = this.node
const snarkValid = await verifier.snarkVerifier.verifyTx(zkTx)
assert(snarkValid, 'generated snark proof is invalid')
assert(zkTx.memo, 'memo does not exist')
const response = await fetch(`${this.coordinator}/tx`, {
method: 'post',
body: zkTx.encode().toString('hex'),

View File

@@ -54,6 +54,7 @@ export class ZkWizard {
account: ZkAccount
toMemo?: number
}): Promise<ZkTx> {
logger.info(`shield to memo(${toMemo})`)
return new Promise<ZkTx>((resolve, reject) => {
const merkleProof: { [hash: string]: MerkleProof<Field> } = {}
const eddsa: { [hash: string]: EdDSA } = {}
@@ -240,6 +241,10 @@ export class ZkWizard {
)
// let { proof, publicSignals } = Utils.genProof(snarkjs.unstringifyBigInts(provingKey), witness);
// TODO handle genProof exception
let memo: Buffer | undefined
if (toMemo !== undefined) {
memo = tx.outflow[toMemo].encrypt()
}
const zkTx: ZkTx = new ZkTx({
inflow: tx.inflow.map((utxo, index) => {
return {
@@ -257,7 +262,7 @@ export class ZkWizard {
pi_c: proof.pi_c.map(Field.from),
},
swap: tx.swap,
memo: toMemo ? tx.outflow[toMemo].encrypt() : undefined,
memo,
})
return zkTx
}