From 74cb490dfa7633d331c6de4a8043bdef63e66daa Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Jun 2017 14:45:30 +1200 Subject: [PATCH] Implement JSDescription creation (minus proof) --- src/jsdescription.js | 138 ++++++++++++++++++ src/jsinput.js | 87 +++++++++++ src/jsoutput.js | 95 ++++++++++++ src/proof_witness.js | 128 ++++++++++++++++ src/types.js | 23 +++ test/fixtures/hsig.json | 40 +++++ test/fixtures/proof_witness.json | 242 +++++++++++++++++++++++++++++++ test/jsdescription.js | 17 +++ test/proof_witness.js | 34 +++++ 9 files changed, 804 insertions(+) create mode 100644 src/jsinput.js create mode 100644 src/jsoutput.js create mode 100644 src/proof_witness.js create mode 100644 test/fixtures/hsig.json create mode 100644 test/fixtures/proof_witness.json create mode 100644 test/proof_witness.js diff --git a/src/jsdescription.js b/src/jsdescription.js index 022ea8c..90efa32 100644 --- a/src/jsdescription.js +++ b/src/jsdescription.js @@ -1,10 +1,33 @@ 'use strict' +var blake2b = require('./blake2b') var bufferutils = require('./bufferutils') +var prf = require('./prf') +var typeforce = require('typeforce') +var types = require('./types') +var util = require('./util') var zconst = require('./const') +var JSProofWitness = require('./proof_witness') +var NotePlaintext = require('./note_plaintext') +var ZCNoteEncryption = require('./note_encryption') var ZCProof = require('./proof') +function hSig (randomSeed, nullifiers, pubKeyHash) { + typeforce(types.tuple( + types.Buffer256bit, + types.arrayOf(types.Buffer256bit), + types.Buffer256bit + ), arguments) + + return Buffer.from(blake2b.crypto_generichash_blake2b_salt_personal( + 32, + Buffer.concat([randomSeed].concat(nullifiers).concat([pubKeyHash])), + undefined, // No key. + undefined, // No salt. + 'ZcashComputehSig')) +} + function JSDescription () { this.nullifiers = [] this.commitments = [] @@ -152,4 +175,119 @@ JSDescription.prototype.toHex = function () { return this.toBuffer().toString('hex') } +JSDescription.prototype.h_sig = function (joinSplitPubKey) { + return hSig(this.randomSeed, this.nullifiers, joinSplitPubKey) +} + +JSDescription.withWitness = function (inputs, outputs, pubKeyHash, vpubOld, vpubNew, rt) { + typeforce(types.tuple( + types.arrayOf(types.JSInput), + types.arrayOf(types.JSOutput), + types.Buffer256bit, + types.Zatoshi, + types.Zatoshi, + types.Buffer256bit + ), arguments) + + if (inputs.length !== zconst.ZC_NUM_JS_INPUTS) { + throw new Error(`invalid number of inputs (found ${inputs.length}, expected ${zconst.ZC_NUM_JS_INPUTS}`) + } + if (outputs.length !== zconst.ZC_NUM_JS_OUTPUTS) { + throw new Error(`invalid number of inputs (found ${outputs.length}, expected ${zconst.ZC_NUM_JS_OUTPUTS}`) + } + + var jsdesc = new JSDescription() + jsdesc.vpub_old = vpubOld + jsdesc.vpub_new = vpubNew + jsdesc.anchor = rt + + var lhsValue = vpubOld + var rhsValue = vpubNew + + inputs.forEach(function (input) { + // Sanity checks of input + + // If note has nonzero value + if (input.note.value !== 0) { + // The witness root must equal the input root. + if (input.witness.root() !== rt) { + throw new Error('joinsplit not anchored to the correct root') + } + + // The tree must witness the correct element + if (input.note.cm() !== input.witness.element()) { + throw new Error('witness of wrong element for joinsplit input') + } + } + + // Ensure we have the key to this note. + if (input.note.a_pk.toString('hex') !== input.key.address().a_pk.toString('hex')) { + throw new Error('input note not authorized to spend with given key') + } + + // Balance must be sensical + typeforce(types.Zatoshi, input.note.value) + lhsValue += input.note.value + typeforce(types.Zatoshi, lhsValue) + + // Compute nullifier of input + jsdesc.nullifiers.push(input.nullifier()) + }) + + // Sample randomSeed + jsdesc.randomSeed = util.random_uint256() + + // Compute h_sig + var hSig = jsdesc.h_sig(pubKeyHash) + + // Sample phi + var phi = util.random_uint252() + + // Compute notes for outputs + var notes = [] + outputs.forEach(function (output, i) { + // Sanity checks of output + typeforce(types.Zatoshi, output.value) + rhsValue += output.value + typeforce(types.Zatoshi, rhsValue) + + // Sample r + var r = util.random_uint256() + + notes.push(output.note(phi, r, i, hSig)) + }) + + if (lhsValue !== rhsValue) { + throw new Error('invalid joinsplit balance') + } + + // Compute the output commitments + notes.forEach(function (note) { + jsdesc.commitments.push(note.cm()) + }) + + // Encrypt the ciphertexts containing the note + // plaintexts to the recipients of the value. + var encryptor = new ZCNoteEncryption(hSig) + + notes.forEach(function (note, i) { + var pt = new NotePlaintext(note, outputs[i].memo) + + jsdesc.ciphertexts.push(pt.encrypt(encryptor, outputs[i].addr.pk_enc)) + }) + + jsdesc.ephemeralKey = encryptor.epk + + // Authenticate hSig with each of the input + // spending keys, producing macs which protect + // against malleability. + inputs.forEach(function (input, i) { + jsdesc.macs.push(prf.PRF_pk(inputs[i].key.a_sk, i, hSig)) + }) + + jsdesc.witness = new JSProofWitness(phi, rt, hSig, inputs, notes, vpubOld, vpubNew) + + return jsdesc +} + module.exports = JSDescription diff --git a/src/jsinput.js b/src/jsinput.js new file mode 100644 index 0000000..d7da9c9 --- /dev/null +++ b/src/jsinput.js @@ -0,0 +1,87 @@ +'use strict' + +var typeforce = require('typeforce') +var types = require('./types') +var zaddr = require('./address') + +var Note = require('./note') +var ZCIncrementalMerkleTree = require('./incremental_merkle_tree') +var ZCIncrementalWitness = require('./incremental_witness') + +function JSInput (witness, note, key) { + typeforce(types.tuple( + types.ZCIncrementalWitness, + types.Note, + types.SpendingKey + ), arguments) + + this.witness = witness + this.note = note + this.key = key +} + +JSInput.dummy = function () { + var key = zaddr.SpendingKey.random() + var note = Note.dummy(key.address().a_pk) + var dummyTree = new ZCIncrementalMerkleTree() + dummyTree.append(note.cm()) + return new JSInput(ZCIncrementalWitness.fromTree(dummyTree), note, key) +} + +JSInput.fromBuffer = function (buffer) { + var offset = 0 + function readZCIncrementalWitness () { + var witness = ZCIncrementalWitness.fromBuffer(buffer.slice(offset), true) + offset += witness.byteLength() + return witness + } + + function readNote () { + var proof = Note.fromBuffer(buffer.slice(offset), true) + offset += proof.byteLength() + return proof + } + + function readSpendingKey () { + var sk = zaddr.SpendingKey.fromBuffer(buffer.slice(offset), true) + offset += sk.byteLength() + return sk + } + + var witness = readZCIncrementalWitness() + var note = readNote() + var key = readSpendingKey() + var input = new JSInput(witness, note, key) + + return input +} + +JSInput.prototype.byteLength = function () { + return ( + this.witness.byteLength() + + this.note.byteLength() + + this.key.byteLength() + ) +} + +JSInput.prototype.toBuffer = function () { + var buffer = Buffer.alloc(this.byteLength()) + + var offset = 0 + function writeSlice (slice) { + slice.copy(buffer, offset) + offset += slice.length + } + + writeSlice(this.witness.toBuffer()) + writeSlice(this.note.toBuffer()) + writeSlice(this.key.toBuffer()) + + return buffer +} + +JSInput.prototype.nullifier = function () { + return this.note.nullifier(this.key) +} + +module.exports = JSInput diff --git a/src/jsoutput.js b/src/jsoutput.js new file mode 100644 index 0000000..bd2b1a4 --- /dev/null +++ b/src/jsoutput.js @@ -0,0 +1,95 @@ +'use strict' + +var bufferutils = require('./bufferutils') +var prf = require('./prf') +var typeforce = require('typeforce') +var types = require('./types') +var zaddr = require('./address') +var zconst = require('./const') + +var Note = require('./note') + +function JSOutput (addr, value, memo) { + typeforce(types.tuple( + types.PaymentAddress, + types.Zatoshi, + types.maybe(types.Buffer) + ), arguments) + + if (!memo) { + memo = Buffer.alloc(zconst.ZC_MEMO_SIZE) + memo.fill(0) + memo[0] = 0xF6 // 0xF6 is invalid UTF8 as per spec + } + + this.addr = addr + this.value = value + this.memo = memo +} + +JSOutput.dummy = function () { + var aSk = zaddr.SpendingKey.random() + return new JSOutput(aSk.address(), 0) +} + +JSOutput.fromBuffer = function (buffer) { + var offset = 0 + function readSlice (n) { + offset += n + return buffer.slice(offset - n, offset) + } + + function readUInt64 () { + var i = bufferutils.readUInt64LE(buffer, offset) + offset += 8 + return i + } + + function readPaymentAddress () { + var addr = zaddr.PaymentAddress.fromBuffer(buffer.slice(offset), true) + offset += addr.byteLength() + return addr + } + + var addr = readPaymentAddress() + var value = readUInt64() + var memo = readSlice(zconst.ZC_MEMO_SIZE) + var output = new JSOutput(addr, value, memo) + + return output +} + +JSOutput.prototype.toBuffer = function () { + var buffer = Buffer.alloc(this.byteLength()) + + var offset = 0 + function writeSlice (slice) { + slice.copy(buffer, offset) + offset += slice.length + } + + function writeUInt64 (i) { + bufferutils.writeUInt64LE(buffer, i, offset) + offset += 8 + } + + writeSlice(this.addr.toBuffer()) + writeUInt64(this.value) + writeSlice(this.memo) + + return buffer +} + +JSOutput.prototype.note = function (phi, r, i, hSig) { + typeforce(types.tuple( + types.Buffer252bit, + types.Buffer256bit, + types.Number, + types.Buffer256bit + ), arguments) + + var rho = prf.PRF_rho(phi, i, hSig) + return new Note(this.addr.a_pk, this.value, rho, r) +} + +module.exports = JSOutput diff --git a/src/proof_witness.js b/src/proof_witness.js new file mode 100644 index 0000000..35ac491 --- /dev/null +++ b/src/proof_witness.js @@ -0,0 +1,128 @@ +'use strict' + +var bufferutils = require('./bufferutils') +var typeforce = require('typeforce') +var types = require('./types') +var zconst = require('./const') + +var JSInput = require('./jsinput') +var Note = require('./note') + +function JSProofWitness (phi, rt, hSig, inputs, notes, vpubOld, vpubNew) { + typeforce(types.tuple( + types.Buffer252bit, + types.Buffer256bit, + types.Buffer256bit, + [types.JSInput], + [types.Note], + types.Zatoshi, + types.Zatoshi + ), arguments) + + this.phi = phi + this.rt = rt + this.hSig = hSig + this.inputs = inputs + this.notes = notes + this.vpub_old = vpubOld + this.vpub_new = vpubNew +} + +JSProofWitness.fromBuffer = function (buffer, __noStrict) { + var offset = 0 + function readSlice (n) { + offset += n + return buffer.slice(offset - n, offset) + } + + function readUInt64 () { + var i = bufferutils.readUInt64LE(buffer, offset) + offset += 8 + return i + } + + function readJSInput () { + var input = JSInput.fromBuffer(buffer.slice(offset), true) + offset += input.byteLength() + return input + } + + function readNote () { + var proof = Note.fromBuffer(buffer.slice(offset), true) + offset += proof.byteLength() + return proof + } + + var phi = readSlice(32) + var rt = readSlice(32) + var hSig = readSlice(32) + + var inputs = [] + for (var i = 0; i < zconst.ZC_NUM_JS_INPUTS; ++i) { + inputs.push(readJSInput()) + } + + var notes = [] + for (i = 0; i < zconst.ZC_NUM_JS_OUTPUTS; ++i) { + notes.push(readNote()) + } + + var vpubOld = readUInt64() + var vpubNew = readUInt64() + var witness = new JSProofWitness(phi, rt, hSig, inputs, notes, vpubOld, vpubNew) + + if (__noStrict) return witness + if (offset !== buffer.length) throw new Error('JSProofWitness has unexpected data') + + return witness +} + +JSProofWitness.fromHex = function (hex) { + return JSProofWitness.fromBuffer(Buffer.from(hex, 'hex')) +} + +JSProofWitness.prototype.byteLength = function () { + return ( + 112 + + this.inputs.reduce(function (sum, input) { return sum + input.byteLength() }, 0) + + this.notes.reduce(function (sum, note) { return sum + note.byteLength() }, 0) + ) +} + +JSProofWitness.prototype.toBuffer = function () { + var buffer = Buffer.alloc(this.byteLength()) + + var offset = 0 + function writeSlice (slice) { + slice.copy(buffer, offset) + offset += slice.length + } + + function writeUInt64 (i) { + bufferutils.writeUInt64LE(buffer, i, offset) + offset += 8 + } + + writeSlice(this.phi) + writeSlice(this.rt) + writeSlice(this.hSig) + + this.inputs.forEach(function (input) { + writeSlice(input.toBuffer()) + }) + + this.notes.forEach(function (note) { + writeSlice(note.toBuffer()) + }) + + writeUInt64(this.vpub_old) + writeUInt64(this.vpub_new) + + return buffer +} + +JSProofWitness.prototype.toHex = function () { + return this.toBuffer().toString('hex') +} + +module.exports = JSProofWitness diff --git a/src/types.js b/src/types.js index cc6c92f..27bc813 100644 --- a/src/types.js +++ b/src/types.js @@ -29,15 +29,38 @@ var PaymentAddress = typeforce.compile({ var SpendingKey = typeforce.compile({ a_sk: Buffer252bit }) +var ZCIncrementalMerkleTree = typeforce.compile({ + left: typeforce.maybe(typeforce.BufferN(32)), + right: typeforce.maybe(typeforce.BufferN(32)), + parents: [typeforce.maybe(typeforce.BufferN(32))] +}) +var ZCIncrementalWitness = typeforce.compile({ + tree: ZCIncrementalMerkleTree, + filled: [typeforce.BufferN(32)], + cursor: typeforce.maybe(ZCIncrementalMerkleTree) +}) +var JSInput = typeforce.compile({ + witness: ZCIncrementalWitness, + note: Note, + key: SpendingKey +}) +var JSOutput = typeforce.compile({ + addr: PaymentAddress, + value: Zatoshi, + memo: typeforce.Buffer +}) // extend typeforce types with ours var types = { BoolNum: BoolNum, Buffer252bit: Buffer252bit, Buffer256bit: typeforce.BufferN(32), + JSInput: JSInput, + JSOutput: JSOutput, Note: Note, PaymentAddress: PaymentAddress, SpendingKey: SpendingKey, + ZCIncrementalWitness: ZCIncrementalWitness, Zatoshi: Zatoshi } diff --git a/test/fixtures/hsig.json b/test/fixtures/hsig.json new file mode 100644 index 0000000..8c06ae8 --- /dev/null +++ b/test/fixtures/hsig.json @@ -0,0 +1,40 @@ +{ + "valid": [ + { + "randomSeed": "6161616161616161616161616161616161616161616161616161616161616161", + "nullifiers": [ + "6262626262626262626262626262626262626262626262626262626262626262", + "6363636363636363636363636363636363636363636363636363636363636363" + ], + "pubKeyHash": "6464646464646464646464646464646464646464646464646464646464646464", + "hex": "a8cba69f1fa329c055756b4af900f8a00b61e44f4cb8a1824ceb58b90a5b8113" + }, + { + "randomSeed": "0000000000000000000000000000000000000000000000000000000000000000", + "nullifiers": [ + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000" + ], + "pubKeyHash": "0000000000000000000000000000000000000000000000000000000000000000", + "hex": "697322276b5dd93b12fb1fcbd2144b2960f24c73aac6c6a0811447be1e7f1e19" + }, + { + "randomSeed": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "nullifiers": [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ], + "pubKeyHash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "hex": "4961048919f0ca79d49c9378c36a91a8767060001f4212fe6f7d426f3ccf9f32" + }, + { + "randomSeed": "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", + "nullifiers": [ + "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", + "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100" + ], + "pubKeyHash": "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", + "hex": "b61110ec162693bc3d9ca7fb0eec3afd2e278e2f41394b3ff11d7cb761ad4b27" + } + ] +} \ No newline at end of file diff --git a/test/fixtures/proof_witness.json b/test/fixtures/proof_witness.json new file mode 100644 index 0000000..2fdff37 --- /dev/null +++ b/test/fixtures/proof_witness.json @@ -0,0 +1,242 @@ +{ + "valid": [ + { + "raw": { + "phi": "0821a4b79971d66f5c32aaee4862c0e7dbf02349d94e0c1399b75a13b4dd198a", + "anchor": "d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259", + "hSig": "4f63be3f04e86555ce0903be8bf3b6ab3979b54fba42e23cb9c74b495fe043b5", + "inputs": [ + { + "witness": "01c6afccb8d6ddfd6944ee34fd4f313bb6dc5d6ae36968bdf024d21cbbd29d32b900000000", + "note": { + "a_pk": "7d85863f30b911fc308a4ae6b184327996fddd3fed3ce8b3c23b7b4ae3cbe377", + "value": 0, + "rho": "6f77d89f12b6ead91cfc2d810650e5a0d61be88018ddad9119cdd34336e21fc9", + "r": "986bafaa8e6af7a3da6c364307ffed45b2210d6c3cc4d05192622a34949d1504" + }, + "key": "0b5852ae184f4e6b29bb0c72c3af6c2f9424690361a0a05ae0860f0c069cafa2" + }, + { + "witness": "0164d931c08f715ec3073cbc1178a3ba93c8099212537bc67f8acadd0e1419641400000000", + "note": { + "a_pk": "a3544b9d81c005c895bf9c466a5a764702fe9011889418de0e5895c3f834052c", + "value": 0, + "rho": "53b1526f62991b34cf3414344cdd3463247f75a094efb6fdf2545aa1d772c15e", + "r": "d13c9048ed6f5d93c69f2670e33541c47e7a6773bae09dad6030e304eb5cd4c4" + }, + "key": "021fb709e13f91ccf72365dfc93c39c2c16c0aac513a18f5a717dd4e798f238c" + } + ], + "notes": [ + { + "a_pk": "20d3ee586bccfa649b780f60b278505f2305c87a6f92083dfeca07cd7d924464", + "value": 0, + "rho": "c0184fb4bd55fed5b1d9f4eb238816a192bd724437d8a2a79d357ff25ceec824", + "r": "4cb7c8af6c342e3ccb543f54b835e050d01b4ee3dcd2696af619c5d37ac5618a" + }, + { + "a_pk": "53115f3ed4b61487d17a53aff200524eafd81557eaf67a482bf29adb730e88c4", + "value": 0, + "rho": "20c50c50b6817652cdaf68df5d50bc6d94e3aaf73c272c39297909ce0feaad30", + "r": "5755ca435d9ecab5241a3c397bb2a6d9da5ce7c29f0baa4022be2096225c1de4" + } + ], + "vpub_old": 0, + "vpub_new": 0 + }, + "hex": "0821a4b79971d66f5c32aaee4862c0e7dbf02349d94e0c1399b75a13b4dd198ad7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd2594f63be3f04e86555ce0903be8bf3b6ab3979b54fba42e23cb9c74b495fe043b501c6afccb8d6ddfd6944ee34fd4f313bb6dc5d6ae36968bdf024d21cbbd29d32b9000000007d85863f30b911fc308a4ae6b184327996fddd3fed3ce8b3c23b7b4ae3cbe37700000000000000006f77d89f12b6ead91cfc2d810650e5a0d61be88018ddad9119cdd34336e21fc9986bafaa8e6af7a3da6c364307ffed45b2210d6c3cc4d05192622a34949d15040b5852ae184f4e6b29bb0c72c3af6c2f9424690361a0a05ae0860f0c069cafa20164d931c08f715ec3073cbc1178a3ba93c8099212537bc67f8acadd0e1419641400000000a3544b9d81c005c895bf9c466a5a764702fe9011889418de0e5895c3f834052c000000000000000053b1526f62991b34cf3414344cdd3463247f75a094efb6fdf2545aa1d772c15ed13c9048ed6f5d93c69f2670e33541c47e7a6773bae09dad6030e304eb5cd4c4021fb709e13f91ccf72365dfc93c39c2c16c0aac513a18f5a717dd4e798f238c20d3ee586bccfa649b780f60b278505f2305c87a6f92083dfeca07cd7d9244640000000000000000c0184fb4bd55fed5b1d9f4eb238816a192bd724437d8a2a79d357ff25ceec8244cb7c8af6c342e3ccb543f54b835e050d01b4ee3dcd2696af619c5d37ac5618a53115f3ed4b61487d17a53aff200524eafd81557eaf67a482bf29adb730e88c4000000000000000020c50c50b6817652cdaf68df5d50bc6d94e3aaf73c272c39297909ce0feaad305755ca435d9ecab5241a3c397bb2a6d9da5ce7c29f0baa4022be2096225c1de400000000000000000000000000000000" + }, + { + "raw": { + "phi": "0c7dbe4dd2322b25ad0d769a30de42b6052b2e2491c1ab382d0a250cd93afc99", + "anchor": "d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259", + "hSig": "4ad816325cfb94107e2f20a277494c783b427f8997b5c91045367faf7a0b0da9", + "inputs": [ + { + "witness": "012b9768625c18122019a8aeaffddb2bb02623ad42bae0cbb48a636d2be3b1a73600000000", + "note": { + "a_pk": "142ccf78aebda099da086d21fb843d80fa18f6d3043da17f575172fdacfd67a1", + "value": 0, + "rho": "94f9c34e6668836609175c0c3d105571af4aea96976d9c5395278a2921c8d145", + "r": "d6d17f637820197b071ece0b3f91f7c9c290cc515b09055fdb1fef84d0a8c0bf" + }, + "key": "00a60d314131af1d3a4a2febe8a330e7b72f0ba61a9cb6032638fbb43277ce8a" + }, + { + "witness": "013af4e746a45de1e00458abd7a3eebd870c03eeff62284bba5d0d21ff41d8491e00000000", + "note": { + "a_pk": "079979d18dcf2a3ac587ff0c4dfc5b1267db6e705e53d929902ed5a4bb376736", + "value": 0, + "rho": "ddafb4091f65a38ebb58bb640a4e861fb66d43431b321370827ab5cd57c1aa23", + "r": "b97a433b48c4780a20a86d17d59ff9625d206ef450da1e1d9ab9536bd941e203" + }, + "key": "0c6e376d6d417c76d0c38bf7bdf5a44feebe004bf8d1682b17cafd9d3d838497" + } + ], + "notes": [ + { + "a_pk": "fc3ced2e6a13649987bc4e34e2666b4a61bdb4845eb1c8c95792f66d414a5eea", + "value": 0, + "rho": "f7a55cbb2c2a9906c7edd47add1808f2ab1de7e3cdad3fdd5671d7834a347259", + "r": "f6e9dd659ce7b004a964fa4ea95a0cd3c7b8a302de87e1e87ba041580b1bc204" + }, + { + "a_pk": "69c8951057caa7b9190cbcce9d1898564ad015caceb3bc8b73170fedca80555a", + "value": 0, + "rho": "d1937d7d8380812fbc7bea791a1819364d7713bd3f929a3924a9515bc6b89465", + "r": "d4e4568a4552c884230865725a89748902c40bd5f5a67cbdba41363794de1315" + } + ], + "vpub_old": 0, + "vpub_new": 0 + }, + "hex": "0c7dbe4dd2322b25ad0d769a30de42b6052b2e2491c1ab382d0a250cd93afc99d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd2594ad816325cfb94107e2f20a277494c783b427f8997b5c91045367faf7a0b0da9012b9768625c18122019a8aeaffddb2bb02623ad42bae0cbb48a636d2be3b1a73600000000142ccf78aebda099da086d21fb843d80fa18f6d3043da17f575172fdacfd67a1000000000000000094f9c34e6668836609175c0c3d105571af4aea96976d9c5395278a2921c8d145d6d17f637820197b071ece0b3f91f7c9c290cc515b09055fdb1fef84d0a8c0bf00a60d314131af1d3a4a2febe8a330e7b72f0ba61a9cb6032638fbb43277ce8a013af4e746a45de1e00458abd7a3eebd870c03eeff62284bba5d0d21ff41d8491e00000000079979d18dcf2a3ac587ff0c4dfc5b1267db6e705e53d929902ed5a4bb3767360000000000000000ddafb4091f65a38ebb58bb640a4e861fb66d43431b321370827ab5cd57c1aa23b97a433b48c4780a20a86d17d59ff9625d206ef450da1e1d9ab9536bd941e2030c6e376d6d417c76d0c38bf7bdf5a44feebe004bf8d1682b17cafd9d3d838497fc3ced2e6a13649987bc4e34e2666b4a61bdb4845eb1c8c95792f66d414a5eea0000000000000000f7a55cbb2c2a9906c7edd47add1808f2ab1de7e3cdad3fdd5671d7834a347259f6e9dd659ce7b004a964fa4ea95a0cd3c7b8a302de87e1e87ba041580b1bc20469c8951057caa7b9190cbcce9d1898564ad015caceb3bc8b73170fedca80555a0000000000000000d1937d7d8380812fbc7bea791a1819364d7713bd3f929a3924a9515bc6b89465d4e4568a4552c884230865725a89748902c40bd5f5a67cbdba41363794de131500000000000000000000000000000000" + }, + { + "raw": { + "phi": "0d0a648ec7372355cdeb579208aed6e3bf7e0de63e2a8e1b46bf87f248baa8ea", + "anchor": "d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259", + "hSig": "065d68e4eb0814b6e4a1a7e43ef5f1ff9c2541dad7c55fa6f20d20097e2fbc34", + "inputs": [ + { + "witness": "01977f7070d292c39dd373213e8319034ae63e9bbcf5c5fd2fa229fbade2a2b50300000000", + "note": { + "a_pk": "6f0a02aefa6664ec54a2b10bca40f210e2d7e624d8c5e236ab1d95dfdb4daa42", + "value": 0, + "rho": "3a6cb835826834a31471fccd50059f2eac27e3c352eb496668da16b7dd471b1c", + "r": "cbfa04eb3adc72d9a4721064bce7f5e283aac4611134ba42e44baae07017833f" + }, + "key": "00b0da3dd30a10486d84efe9c6795e1feb17834c1494ceb4bcf87405c5877600" + }, + { + "witness": "01d392fae5e5f067751ae2f84e815a7ca1a62d3939160327707d18a2bb3705eb5700000000", + "note": { + "a_pk": "52d865a631df718d813b6afb88d2048061719adc5066ccde17c68d288adb15fa", + "value": 0, + "rho": "caec424837f2e7f4a78d4be9371b718a4fa2818ab58a5f892a9dd44151305119", + "r": "58c4ce71dea83d517d3a28026a3fc20e823594e90547e34e32d95b5c76b56d56" + }, + "key": "00eb969b13fb570a5023c9f2f5a5426263f5cda3180450dd247e164b7582abf5" + } + ], + "notes": [ + { + "a_pk": "585874b0f1d7bd6fa417c63e98f49971cba3d38c49c2f634d9f1d9ebf99cfd6e", + "value": 0, + "rho": "392a8d6758abc23e4105b77453758a95a13c28279cb34ad2a6ced686a1f05816", + "r": "e28498fa9986e3842d8faebe5cd2bdbf714b91c16e716c54d1a3810342de0b19" + }, + { + "a_pk": "4d1e027a3a8b2599f706135fba9478a6edcbe7a1fd8a09b4599af2326af36d21", + "value": 0, + "rho": "7e91e4e6aa67f889375ebc2e473307e7ff0c337f02ae8f5af621f4634b772214", + "r": "dbc4f86c6aa86df023bf70d86660631d7dc24fdec68d45dd640add55f121b17b" + } + ], + "vpub_old": 0, + "vpub_new": 0 + }, + "hex": "0d0a648ec7372355cdeb579208aed6e3bf7e0de63e2a8e1b46bf87f248baa8ead7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259065d68e4eb0814b6e4a1a7e43ef5f1ff9c2541dad7c55fa6f20d20097e2fbc3401977f7070d292c39dd373213e8319034ae63e9bbcf5c5fd2fa229fbade2a2b503000000006f0a02aefa6664ec54a2b10bca40f210e2d7e624d8c5e236ab1d95dfdb4daa4200000000000000003a6cb835826834a31471fccd50059f2eac27e3c352eb496668da16b7dd471b1ccbfa04eb3adc72d9a4721064bce7f5e283aac4611134ba42e44baae07017833f00b0da3dd30a10486d84efe9c6795e1feb17834c1494ceb4bcf87405c587760001d392fae5e5f067751ae2f84e815a7ca1a62d3939160327707d18a2bb3705eb570000000052d865a631df718d813b6afb88d2048061719adc5066ccde17c68d288adb15fa0000000000000000caec424837f2e7f4a78d4be9371b718a4fa2818ab58a5f892a9dd4415130511958c4ce71dea83d517d3a28026a3fc20e823594e90547e34e32d95b5c76b56d5600eb969b13fb570a5023c9f2f5a5426263f5cda3180450dd247e164b7582abf5585874b0f1d7bd6fa417c63e98f49971cba3d38c49c2f634d9f1d9ebf99cfd6e0000000000000000392a8d6758abc23e4105b77453758a95a13c28279cb34ad2a6ced686a1f05816e28498fa9986e3842d8faebe5cd2bdbf714b91c16e716c54d1a3810342de0b194d1e027a3a8b2599f706135fba9478a6edcbe7a1fd8a09b4599af2326af36d2100000000000000007e91e4e6aa67f889375ebc2e473307e7ff0c337f02ae8f5af621f4634b772214dbc4f86c6aa86df023bf70d86660631d7dc24fdec68d45dd640add55f121b17b00000000000000000000000000000000" + }, + { + "raw": { + "phi": "01f4e3dfd4e35a5a597bb68e1d4659aa40cdf7e9b4d6bce299bcb6efaa2afeea", + "anchor": "d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259", + "hSig": "a6ea90e941a1a2583d3207dcda9adf41ce7de6019b49a40ef0472de4e34ad881", + "inputs": [ + { + "witness": "01381e8b11a0611c7c28bdf0ed30d5383a94fe30ce38c6ef8dd23a1d85216fbfb700000000", + "note": { + "a_pk": "12db749049f760203a770fddf6e80729e7736d263613438cde9764fb660972c3", + "value": 0, + "rho": "5edcc18ec561878cea4e68b97c67f2ae3203b18d96838264e8ce217f5d6610fa", + "r": "3d0ad949feb5a75f24ba6d58d8716a4d406ebcdd2349f0d057a1d309bf4f0a2b" + }, + "key": "010f16110d9a93f4e987033f7cb85715c7719dc5d53c572f4f67cd9d5e1fe847" + }, + { + "witness": "011b9dbce37a1f6a90f710a6c71ee718a0d9043e422214a536e832987e235ba60c00000000", + "note": { + "a_pk": "b7c799b08b6afceb7bc397142146fcc443bc3e6733cf09c7aaa9caf35e103ea3", + "value": 0, + "rho": "5afbb0cc79687c6eb6912931e4fd4e22b51d9f9847207b7800c07ab6f0be9dd4", + "r": "e59634d762c2145f4787ba2dadff938fb5905c8f1c0514f56db274e620d1a5e7" + }, + "key": "0ffe822d661c5bedccd12a0fd4c16dfdaaf67cd4a21a1b04deadd41181b82bbb" + } + ], + "notes": [ + { + "a_pk": "8b83998109b346fa45a5a735465888402d5c9bed982cb9bf95af11e365e256ac", + "value": 0, + "rho": "a17d9e69852133a097f7a9800ab1e172993aae96e85ef7a774e05d006c5401a3", + "r": "b9cd93580296cce5210cbaa903cfa4523f9a487376630ca4f14a90faffc33734" + }, + { + "a_pk": "532f776a85a176947724d9e0cec7d34a71f3bf394c24033a4acda49adab4ffc7", + "value": 0, + "rho": "4893a0a21fbbd9d7a2ddb1c87de9d410c05657f18a77c18108e4cd8831257f56", + "r": "0778a5516340b11118dfd61d53d6dca72a828b4716781ca9687a60b1dcd40405" + } + ], + "vpub_old": 0, + "vpub_new": 0 + }, + "hex": "01f4e3dfd4e35a5a597bb68e1d4659aa40cdf7e9b4d6bce299bcb6efaa2afeead7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259a6ea90e941a1a2583d3207dcda9adf41ce7de6019b49a40ef0472de4e34ad88101381e8b11a0611c7c28bdf0ed30d5383a94fe30ce38c6ef8dd23a1d85216fbfb70000000012db749049f760203a770fddf6e80729e7736d263613438cde9764fb660972c300000000000000005edcc18ec561878cea4e68b97c67f2ae3203b18d96838264e8ce217f5d6610fa3d0ad949feb5a75f24ba6d58d8716a4d406ebcdd2349f0d057a1d309bf4f0a2b010f16110d9a93f4e987033f7cb85715c7719dc5d53c572f4f67cd9d5e1fe847011b9dbce37a1f6a90f710a6c71ee718a0d9043e422214a536e832987e235ba60c00000000b7c799b08b6afceb7bc397142146fcc443bc3e6733cf09c7aaa9caf35e103ea300000000000000005afbb0cc79687c6eb6912931e4fd4e22b51d9f9847207b7800c07ab6f0be9dd4e59634d762c2145f4787ba2dadff938fb5905c8f1c0514f56db274e620d1a5e70ffe822d661c5bedccd12a0fd4c16dfdaaf67cd4a21a1b04deadd41181b82bbb8b83998109b346fa45a5a735465888402d5c9bed982cb9bf95af11e365e256ac0000000000000000a17d9e69852133a097f7a9800ab1e172993aae96e85ef7a774e05d006c5401a3b9cd93580296cce5210cbaa903cfa4523f9a487376630ca4f14a90faffc33734532f776a85a176947724d9e0cec7d34a71f3bf394c24033a4acda49adab4ffc700000000000000004893a0a21fbbd9d7a2ddb1c87de9d410c05657f18a77c18108e4cd8831257f560778a5516340b11118dfd61d53d6dca72a828b4716781ca9687a60b1dcd4040500000000000000000000000000000000" + }, + { + "raw": { + "phi": "03fb6a5ca0679f5cf070364f46277ffdef3ba1c31ee837ae6a7b395a15269890", + "anchor": "d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd259", + "hSig": "0e11db074d3af0aca06bf4bc7875f8f849f344cf72f7fe34fdf6ae5742d83f83", + "inputs": [ + { + "witness": "01ed6ce7fb34bd756cfe27d2ff4e45a8d85db47795347ec1a2116573eeccdcc38800000000", + "note": { + "a_pk": "9733afbfb6b7d56da19b43af4ef1ef0c9b0766a8d0d7574a4a477bf6aa301b7b", + "value": 0, + "rho": "f2a506f9f5f49f7878f14f4bd9b9e45e50500f9b7445fcb0100d030acb59d4f7", + "r": "5cdf75c862c1cc01d5a60f8f1008387feeecc81e6f02b90d8ed6bf1e22dc7007" + }, + "key": "0bd24836f1d6d562cf3f1415f9d6cee17023d4dbb9e784f2ab5521f5727782fc" + }, + { + "witness": "016ab05aece4c6c121d4581f892a8fcb93edf7b85886fae4251004be66e7c7e0ed00000000", + "note": { + "a_pk": "336683d7b004676f7d0e5a6867eddc325589d1dd45e2bf5c3461313b07662090", + "value": 0, + "rho": "26bfc3ef01683121f9eb6d7fcf52d2028022bc6d018f22c4cb2d8390333eb19a", + "r": "43a26361212959f787b91a95b072826c5bd70bcb9fb52f86dcf9aad0addadc87" + }, + "key": "0452a218d5b15bcac5905133ae714325482f9fbe4b7da7c5fd70c7aa06bde952" + } + ], + "notes": [ + { + "a_pk": "63ef5198f2827ba4036d49beee6d7fb4007a74f2b5fc4b49dbf6917d4bd16395", + "value": 0, + "rho": "e1b20c36b7aa72a3e8fb8e0122208594df8224ea2169d03e0718c62d6467e398", + "r": "a6024f9d2adf3f623a8e2a5e7887d24ba4631037f2a7c0d5a6ed457c9b151538" + }, + { + "a_pk": "361f300cf3f45065a623f178415dda857c0ab344913753f8469517d040597313", + "value": 0, + "rho": "bfedc03329eb135c58fceb445c3b4b0f23944d1f418ba6475e7fdc5261ab9ba1", + "r": "06e661811e4ab6e8846a6e07ef4f0a64134691de2d0d4429e01ae6a225f90b50" + } + ], + "vpub_old": 0, + "vpub_new": 0 + }, + "hex": "03fb6a5ca0679f5cf070364f46277ffdef3ba1c31ee837ae6a7b395a15269890d7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd2590e11db074d3af0aca06bf4bc7875f8f849f344cf72f7fe34fdf6ae5742d83f8301ed6ce7fb34bd756cfe27d2ff4e45a8d85db47795347ec1a2116573eeccdcc388000000009733afbfb6b7d56da19b43af4ef1ef0c9b0766a8d0d7574a4a477bf6aa301b7b0000000000000000f2a506f9f5f49f7878f14f4bd9b9e45e50500f9b7445fcb0100d030acb59d4f75cdf75c862c1cc01d5a60f8f1008387feeecc81e6f02b90d8ed6bf1e22dc70070bd24836f1d6d562cf3f1415f9d6cee17023d4dbb9e784f2ab5521f5727782fc016ab05aece4c6c121d4581f892a8fcb93edf7b85886fae4251004be66e7c7e0ed00000000336683d7b004676f7d0e5a6867eddc325589d1dd45e2bf5c3461313b07662090000000000000000026bfc3ef01683121f9eb6d7fcf52d2028022bc6d018f22c4cb2d8390333eb19a43a26361212959f787b91a95b072826c5bd70bcb9fb52f86dcf9aad0addadc870452a218d5b15bcac5905133ae714325482f9fbe4b7da7c5fd70c7aa06bde95263ef5198f2827ba4036d49beee6d7fb4007a74f2b5fc4b49dbf6917d4bd163950000000000000000e1b20c36b7aa72a3e8fb8e0122208594df8224ea2169d03e0718c62d6467e398a6024f9d2adf3f623a8e2a5e7887d24ba4631037f2a7c0d5a6ed457c9b151538361f300cf3f45065a623f178415dda857c0ab344913753f8469517d0405973130000000000000000bfedc03329eb135c58fceb445c3b4b0f23944d1f418ba6475e7fdc5261ab9ba106e661811e4ab6e8846a6e07ef4f0a64134691de2d0d4429e01ae6a225f90b5000000000000000000000000000000000" + } + ], + "invalid": { + "fromBufferStrict": [ + { + "exception": "JSProofWitness has unexpected data", + "hex": "0821a4b79971d66f5c32aaee4862c0e7dbf02349d94e0c1399b75a13b4dd198ad7c612c817793191a1e68652121876d6b3bde40f4fa52bc314145ce6e5cdd2594f63be3f04e86555ce0903be8bf3b6ab3979b54fba42e23cb9c74b495fe043b501c6afccb8d6ddfd6944ee34fd4f313bb6dc5d6ae36968bdf024d21cbbd29d32b9000000007d85863f30b911fc308a4ae6b184327996fddd3fed3ce8b3c23b7b4ae3cbe37700000000000000006f77d89f12b6ead91cfc2d810650e5a0d61be88018ddad9119cdd34336e21fc9986bafaa8e6af7a3da6c364307ffed45b2210d6c3cc4d05192622a34949d15040b5852ae184f4e6b29bb0c72c3af6c2f9424690361a0a05ae0860f0c069cafa20164d931c08f715ec3073cbc1178a3ba93c8099212537bc67f8acadd0e1419641400000000a3544b9d81c005c895bf9c466a5a764702fe9011889418de0e5895c3f834052c000000000000000053b1526f62991b34cf3414344cdd3463247f75a094efb6fdf2545aa1d772c15ed13c9048ed6f5d93c69f2670e33541c47e7a6773bae09dad6030e304eb5cd4c4021fb709e13f91ccf72365dfc93c39c2c16c0aac513a18f5a717dd4e798f238c20d3ee586bccfa649b780f60b278505f2305c87a6f92083dfeca07cd7d9244640000000000000000c0184fb4bd55fed5b1d9f4eb238816a192bd724437d8a2a79d357ff25ceec8244cb7c8af6c342e3ccb543f54b835e050d01b4ee3dcd2696af619c5d37ac5618a53115f3ed4b61487d17a53aff200524eafd81557eaf67a482bf29adb730e88c4000000000000000020c50c50b6817652cdaf68df5d50bc6d94e3aaf73c272c39297909ce0feaad305755ca435d9ecab5241a3c397bb2a6d9da5ce7c29f0baa4022be2096225c1de400000000000000000000000000000000ffffffff" + } + ] + } +} \ No newline at end of file diff --git a/test/jsdescription.js b/test/jsdescription.js index dfe3995..cd7da0f 100644 --- a/test/jsdescription.js +++ b/test/jsdescription.js @@ -6,6 +6,7 @@ var JSDescription = require('../src/jsdescription') var ZCProof = require('../src/proof') var fixtures = require('./fixtures/jsdescription') +var hSigFixtures = require('./fixtures/hsig') describe('JSDescription', function () { function fromRaw (raw) { @@ -90,4 +91,20 @@ describe('JSDescription', function () { }) }) }) + + describe('hSig', function () { + hSigFixtures.valid.forEach(function (f) { + it('equals ' + f.hex, function () { + var jsdesc = new JSDescription() + jsdesc.randomSeed = [].reverse.call(Buffer.from(f.randomSeed, 'hex')) + f.nullifiers.forEach(function (nullifier) { + jsdesc.nullifiers.push([].reverse.call(Buffer.from(nullifier, 'hex'))) + }) + + var actual = jsdesc.h_sig([].reverse.call(Buffer.from(f.pubKeyHash, 'hex'))) + var expected = [].reverse.call(Buffer.from(f.hex, 'hex')) + assert.strictEqual(Buffer.from(actual).toString('hex'), expected.toString('hex')) + }) + }) + }) }) diff --git a/test/proof_witness.js b/test/proof_witness.js new file mode 100644 index 0000000..f81d8f3 --- /dev/null +++ b/test/proof_witness.js @@ -0,0 +1,34 @@ +/* global describe, it */ +'use strict' + +var assert = require('assert') + +var JSProofWitness = require('../src/proof_witness') + +var fixtures = require('./fixtures/proof_witness') + +describe('JSProofWitness', function () { + describe('fromBuffer/fromHex', function () { + fixtures.valid.forEach(function (f, i) { + it('imports random proof witness ' + i, function () { + var actual = JSProofWitness.fromHex(f.hex) + + assert.strictEqual(actual.toHex(), f.hex, actual.toHex()) + }) + }) + + fixtures.invalid.fromBufferStrict.forEach(function (f) { + it('throws on ' + f.exception, function () { + assert.throws(function () { + JSProofWitness.fromHex(f.hex) + }, new RegExp(f.exception)) + }) + + it('passes with __noStrict = true on ' + f.exception, function () { + assert.doesNotThrow(function () { + JSProofWitness.fromBuffer(Buffer.from(f.hex, 'hex'), true) + }, new RegExp(f.exception)) + }) + }) + }) +})