diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..0977ded --- /dev/null +++ b/Changelog.md @@ -0,0 +1,12 @@ +# Version 1.1.0, 2020-06, Simplifications + +Interface definition: +- *(breaking)* Renamed R1CSContraints to ConstraintSystem. +- *(breaking)* Moved r1cs_generation and witness_generation from Circuit to Command. +- Added a dedicated Command message type to help with interoperable execution. +- Added an example file in binary and JSON. + +Rust: +- *(breaking)* Moved "writing" helpers to the "owned" modules. +- Added "owned" versions of all message types. +- Added a tool to convert to JSON. diff --git a/README.md b/README.md index 029cbdf..5cac412 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ See also the [WebAssembly modules](https://github.com/QED-it/zkinterface-wasm/) | ------------------------- | --------------------------- | | `zkInterface.pdf` | The interface specification | | `zkinterface.fbs` | The gadget interface definition using FlatBuffers | +| `examples/` | An example circuit in binary and JSON | | `rust/` | Cargo package `zkinterface` | | `rust/src/zkinterface_generated.rs` | Generated Rust code | | `rust/src/reading.rs` | Rust helpers to read messages | diff --git a/examples/example.json b/examples/example.json new file mode 100644 index 0000000..552be0d --- /dev/null +++ b/examples/example.json @@ -0,0 +1,135 @@ +{ + "circuits": [ + { + "connections": { + "variable_ids": [ + 1, + 2, + 3 + ], + "values": [ + 3, + 0, + 0, + 0, + 4, + 0, + 0, + 0, + 25, + 0, + 0, + 0 + ] + }, + "free_variable_id": 6, + "field_maximum": null + } + ], + "constraint_systems": [ + { + "constraints": [ + { + "linear_combination_a": { + "variable_ids": [ + 1 + ], + "values": [ + 1 + ] + }, + "linear_combination_b": { + "variable_ids": [ + 1 + ], + "values": [ + 1 + ] + }, + "linear_combination_c": { + "variable_ids": [ + 4 + ], + "values": [ + 1 + ] + } + }, + { + "linear_combination_a": { + "variable_ids": [ + 2 + ], + "values": [ + 1 + ] + }, + "linear_combination_b": { + "variable_ids": [ + 2 + ], + "values": [ + 1 + ] + }, + "linear_combination_c": { + "variable_ids": [ + 5 + ], + "values": [ + 1 + ] + } + }, + { + "linear_combination_a": { + "variable_ids": [ + 0 + ], + "values": [ + 1 + ] + }, + "linear_combination_b": { + "variable_ids": [ + 4, + 5 + ], + "values": [ + 1, + 1 + ] + }, + "linear_combination_c": { + "variable_ids": [ + 3 + ], + "values": [ + 1 + ] + } + } + ] + } + ], + "witnesses": [ + { + "assigned_variables": { + "variable_ids": [ + 4, + 5 + ], + "values": [ + 9, + 0, + 0, + 0, + 16, + 0, + 0, + 0 + ] + } + } + ] +} \ No newline at end of file diff --git a/examples/example.zkif b/examples/example.zkif new file mode 100644 index 0000000..ba38a4e Binary files /dev/null and b/examples/example.zkif differ diff --git a/js/zkinterface_generated.js b/js/zkinterface_generated.js index 8b5c99e..8a50850 100644 --- a/js/zkinterface_generated.js +++ b/js/zkinterface_generated.js @@ -7,13 +7,39 @@ var zkinterface = zkinterface || {}; /** - * @enum + * @enum {number} */ zkinterface.Message = { - NONE: 0, 0: 'NONE', - Circuit: 1, 1: 'Circuit', - R1CSConstraints: 2, 2: 'R1CSConstraints', - Witness: 3, 3: 'Witness' + NONE: 0, + Circuit: 1, + R1CSConstraints: 2, + Witness: 3 +}; + +/** + * @enum {string} + */ +zkinterface.MessageName = { + '0': 'NONE', + '1': 'Circuit', + '2': 'R1CSConstraints', + '3': 'Witness' +}; + +/** + * @enum {number} + */ +zkinterface.CircuitType = { + R1CS: 0, + FanIn2: 1 +}; + +/** + * @enum {string} + */ +zkinterface.CircuitTypeName = { + '0': 'R1CS', + '1': 'FanIn2' }; /** @@ -55,6 +81,16 @@ zkinterface.Circuit.getRootAsCircuit = function(bb, obj) { return (obj || new zkinterface.Circuit).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.Circuit=} obj + * @returns {zkinterface.Circuit} + */ +zkinterface.Circuit.getSizePrefixedRootAsCircuit = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.Circuit).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * Variables to use as connections to the sub-circuit. * @@ -134,6 +170,16 @@ zkinterface.Circuit.prototype.fieldMaximumArray = function() { return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; }; +/** + * Whether this is R1CS or arithmetic circuit. + * + * @returns {zkinterface.CircuitType} + */ +zkinterface.Circuit.prototype.circuitType = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? /** @type {zkinterface.CircuitType} */ (this.bb.readInt8(this.bb_pos + offset)) : zkinterface.CircuitType.R1CS; +}; + /** * Optional: Any custom parameter that may influence the circuit construction. * @@ -146,7 +192,7 @@ zkinterface.Circuit.prototype.fieldMaximumArray = function() { * @returns {zkinterface.KeyValue} */ zkinterface.Circuit.prototype.configuration = function(index, obj) { - var offset = this.bb.__offset(this.bb_pos, 14); + var offset = this.bb.__offset(this.bb_pos, 16); return offset ? (obj || new zkinterface.KeyValue).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; }; @@ -154,7 +200,7 @@ zkinterface.Circuit.prototype.configuration = function(index, obj) { * @returns {number} */ zkinterface.Circuit.prototype.configurationLength = function() { - var offset = this.bb.__offset(this.bb_pos, 14); + var offset = this.bb.__offset(this.bb_pos, 16); return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; @@ -162,7 +208,7 @@ zkinterface.Circuit.prototype.configurationLength = function() { * @param {flatbuffers.Builder} builder */ zkinterface.Circuit.startCircuit = function(builder) { - builder.startObject(6); + builder.startObject(7); }; /** @@ -226,12 +272,20 @@ zkinterface.Circuit.startFieldMaximumVector = function(builder, numElems) { builder.startVector(1, numElems, 1); }; +/** + * @param {flatbuffers.Builder} builder + * @param {zkinterface.CircuitType} circuitType + */ +zkinterface.Circuit.addCircuitType = function(builder, circuitType) { + builder.addFieldInt8(5, circuitType, zkinterface.CircuitType.R1CS); +}; + /** * @param {flatbuffers.Builder} builder * @param {flatbuffers.Offset} configurationOffset */ zkinterface.Circuit.addConfiguration = function(builder, configurationOffset) { - builder.addFieldOffset(5, configurationOffset, 0); + builder.addFieldOffset(6, configurationOffset, 0); }; /** @@ -264,6 +318,29 @@ zkinterface.Circuit.endCircuit = function(builder) { return offset; }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} connectionsOffset + * @param {flatbuffers.Long} freeVariableId + * @param {boolean} r1csGeneration + * @param {boolean} witnessGeneration + * @param {flatbuffers.Offset} fieldMaximumOffset + * @param {zkinterface.CircuitType} circuitType + * @param {flatbuffers.Offset} configurationOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.Circuit.createCircuit = function(builder, connectionsOffset, freeVariableId, r1csGeneration, witnessGeneration, fieldMaximumOffset, circuitType, configurationOffset) { + zkinterface.Circuit.startCircuit(builder); + zkinterface.Circuit.addConnections(builder, connectionsOffset); + zkinterface.Circuit.addFreeVariableId(builder, freeVariableId); + zkinterface.Circuit.addR1csGeneration(builder, r1csGeneration); + zkinterface.Circuit.addWitnessGeneration(builder, witnessGeneration); + zkinterface.Circuit.addFieldMaximum(builder, fieldMaximumOffset); + zkinterface.Circuit.addCircuitType(builder, circuitType); + zkinterface.Circuit.addConfiguration(builder, configurationOffset); + return zkinterface.Circuit.endCircuit(builder); +} + /** * R1CSConstraints represents constraints to be added to the constraint system. * @@ -303,6 +380,16 @@ zkinterface.R1CSConstraints.getRootAsR1CSConstraints = function(bb, obj) { return (obj || new zkinterface.R1CSConstraints).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.R1CSConstraints=} obj + * @returns {zkinterface.R1CSConstraints} + */ +zkinterface.R1CSConstraints.getSizePrefixedRootAsR1CSConstraints = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.R1CSConstraints).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * @param {number} index * @param {zkinterface.BilinearConstraint=} obj @@ -418,6 +505,19 @@ zkinterface.R1CSConstraints.endR1CSConstraints = function(builder) { return offset; }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} constraintsOffset + * @param {flatbuffers.Offset} infoOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.R1CSConstraints.createR1CSConstraints = function(builder, constraintsOffset, infoOffset) { + zkinterface.R1CSConstraints.startR1CSConstraints(builder); + zkinterface.R1CSConstraints.addConstraints(builder, constraintsOffset); + zkinterface.R1CSConstraints.addInfo(builder, infoOffset); + return zkinterface.R1CSConstraints.endR1CSConstraints(builder); +} + /** * Witness represents an assignment of values to variables. * @@ -459,6 +559,16 @@ zkinterface.Witness.getRootAsWitness = function(bb, obj) { return (obj || new zkinterface.Witness).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.Witness=} obj + * @returns {zkinterface.Witness} + */ +zkinterface.Witness.getSizePrefixedRootAsWitness = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.Witness).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * @param {zkinterface.Variables=} obj * @returns {zkinterface.Variables|null} @@ -492,6 +602,17 @@ zkinterface.Witness.endWitness = function(builder) { return offset; }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} assignedVariablesOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.Witness.createWitness = function(builder, assignedVariablesOffset) { + zkinterface.Witness.startWitness(builder); + zkinterface.Witness.addAssignedVariables(builder, assignedVariablesOffset); + return zkinterface.Witness.endWitness(builder); +} + /** * A single R1CS constraint between variables. * @@ -533,6 +654,16 @@ zkinterface.BilinearConstraint.getRootAsBilinearConstraint = function(bb, obj) { return (obj || new zkinterface.BilinearConstraint).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.BilinearConstraint=} obj + * @returns {zkinterface.BilinearConstraint} + */ +zkinterface.BilinearConstraint.getSizePrefixedRootAsBilinearConstraint = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.BilinearConstraint).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * @param {zkinterface.Variables=} obj * @returns {zkinterface.Variables|null} @@ -600,6 +731,21 @@ zkinterface.BilinearConstraint.endBilinearConstraint = function(builder) { return offset; }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} linearCombinationAOffset + * @param {flatbuffers.Offset} linearCombinationBOffset + * @param {flatbuffers.Offset} linearCombinationCOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.BilinearConstraint.createBilinearConstraint = function(builder, linearCombinationAOffset, linearCombinationBOffset, linearCombinationCOffset) { + zkinterface.BilinearConstraint.startBilinearConstraint(builder); + zkinterface.BilinearConstraint.addLinearCombinationA(builder, linearCombinationAOffset); + zkinterface.BilinearConstraint.addLinearCombinationB(builder, linearCombinationBOffset); + zkinterface.BilinearConstraint.addLinearCombinationC(builder, linearCombinationCOffset); + return zkinterface.BilinearConstraint.endBilinearConstraint(builder); +} + /** * A description of multiple variables. * @@ -645,6 +791,16 @@ zkinterface.Variables.getRootAsVariables = function(bb, obj) { return (obj || new zkinterface.Variables).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.Variables=} obj + * @returns {zkinterface.Variables} + */ +zkinterface.Variables.getSizePrefixedRootAsVariables = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.Variables).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * The IDs of the variables. * @@ -831,6 +987,21 @@ zkinterface.Variables.endVariables = function(builder) { return offset; }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} variableIdsOffset + * @param {flatbuffers.Offset} valuesOffset + * @param {flatbuffers.Offset} infoOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.Variables.createVariables = function(builder, variableIdsOffset, valuesOffset, infoOffset) { + zkinterface.Variables.startVariables(builder); + zkinterface.Variables.addVariableIds(builder, variableIdsOffset); + zkinterface.Variables.addValues(builder, valuesOffset); + zkinterface.Variables.addInfo(builder, infoOffset); + return zkinterface.Variables.endVariables(builder); +} + /** * Generic key-value for custom attributes. * @@ -868,6 +1039,16 @@ zkinterface.KeyValue.getRootAsKeyValue = function(bb, obj) { return (obj || new zkinterface.KeyValue).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.KeyValue=} obj + * @returns {zkinterface.KeyValue} + */ +zkinterface.KeyValue.getSizePrefixedRootAsKeyValue = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.KeyValue).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * @param {flatbuffers.Encoding=} optionalEncoding * @returns {string|Uint8Array|null} @@ -955,6 +1136,19 @@ zkinterface.KeyValue.endKeyValue = function(builder) { return offset; }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} keyOffset + * @param {flatbuffers.Offset} valueOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.KeyValue.createKeyValue = function(builder, keyOffset, valueOffset) { + zkinterface.KeyValue.startKeyValue(builder); + zkinterface.KeyValue.addKey(builder, keyOffset); + zkinterface.KeyValue.addValue(builder, valueOffset); + return zkinterface.KeyValue.endKeyValue(builder); +} + /** * @constructor */ @@ -990,6 +1184,16 @@ zkinterface.Root.getRootAsRoot = function(bb, obj) { return (obj || new zkinterface.Root).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {zkinterface.Root=} obj + * @returns {zkinterface.Root} + */ +zkinterface.Root.getSizePrefixedRootAsRoot = function(bb, obj) { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new zkinterface.Root).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + /** * @param {flatbuffers.ByteBuffer} bb * @returns {boolean} @@ -1055,5 +1259,26 @@ zkinterface.Root.finishRootBuffer = function(builder, offset) { builder.finish(offset, 'zkif'); }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} offset + */ +zkinterface.Root.finishSizePrefixedRootBuffer = function(builder, offset) { + builder.finish(offset, 'zkif', true); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {zkinterface.Message} messageType + * @param {flatbuffers.Offset} messageOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.Root.createRoot = function(builder, messageType, messageOffset) { + zkinterface.Root.startRoot(builder); + zkinterface.Root.addMessageType(builder, messageType); + zkinterface.Root.addMessage(builder, messageOffset); + return zkinterface.Root.endRoot(builder); +} + // Exports for Node.js and RequireJS this.zkinterface = zkinterface; diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 5cf6f63..e62a2e4 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -34,6 +34,11 @@ dependencies = [ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.2.0" @@ -53,6 +58,22 @@ dependencies = [ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "1.1.0" @@ -73,6 +94,39 @@ dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "smallvec" version = "0.6.7" @@ -81,6 +135,16 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -94,6 +158,11 @@ name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -114,11 +183,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "zkinterface" -version = "1.0.6" +version = "1.1.0" dependencies = [ "cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "flatbuffers 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] @@ -127,14 +198,23 @@ dependencies = [ "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum flatbuffers 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea0c34f669be9911826facafe996adfda978aeee67285a13556869e2d8b8331f" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" +"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +"checksum serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" +"checksum serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" +"checksum serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"checksum syn 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 3d86cea..0b00955 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zkinterface" -version = "1.0.6" +version = "1.1.0" authors = ["Aurélien Nicolas "] license = "MIT" build = "build.rs" @@ -19,6 +19,8 @@ cpp = [] [dependencies] flatbuffers = "0.5.0" +serde = { version = "1.0.111", features = ["derive"] } +serde_json = "1.0.53" [build-dependencies] regex = "1" diff --git a/rust/build.rs b/rust/build.rs index 31b0338..cc744eb 100644 --- a/rust/build.rs +++ b/rust/build.rs @@ -4,6 +4,7 @@ fn main() { use std::path::Path; use std::process::Command; + // Latest flatc version: 1.12.0 match Command::new("flatc").args(&[ "--rust", "--cpp", diff --git a/rust/src/bin/example.rs b/rust/src/bin/example.rs index b233504..b4f47ba 100644 --- a/rust/src/bin/example.rs +++ b/rust/src/bin/example.rs @@ -7,9 +7,9 @@ use std::error::Error; // Example: // -// cargo run --bin example > example.zkif +// cargo run --bin example > ../examples/example.zkif // -pub fn main() -> Result<(), Box> { +pub fn main() -> Result<(), Box> { example_circuit().write(stdout())?; write_example_constraints(stdout())?; diff --git a/rust/src/bin/print.rs b/rust/src/bin/print.rs index f1d664e..3749f31 100644 --- a/rust/src/bin/print.rs +++ b/rust/src/bin/print.rs @@ -7,9 +7,9 @@ use std::error::Error; // Example: // -// cargo run --bin print < example.zkif +// cargo run --bin print < ../examples/example.zkif // -pub fn main() -> Result<(), Box> { +pub fn main() -> Result<(), Box> { let mut messages = Messages::new(1); let mut buffer = vec![]; diff --git a/rust/src/bin/stats.rs b/rust/src/bin/stats.rs new file mode 100644 index 0000000..cdff75e --- /dev/null +++ b/rust/src/bin/stats.rs @@ -0,0 +1,71 @@ +extern crate serde; +extern crate serde_json; +extern crate zkinterface; + +use std::error::Error; +use std::io::{stdin, Read}; +use serde::{Deserialize, Serialize}; + +use zkinterface::reading::Messages; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +struct Stats { + num_public_inputs: u64, + num_private_variables: u64, + multiplications: u64, + additions: u64, + additions_a: u64, + additions_b: u64, + additions_c: u64, +} + +impl Stats { + fn new() -> Stats { + return Stats { num_public_inputs: 0, num_private_variables: 0, multiplications: 0, additions_a: 0, additions_b: 0, additions_c: 0, additions: 0 }; + } + + fn finish(&mut self) { + self.additions = self.additions_a + self.additions_b + self.additions_c; + } +} + +// Example: +// +// cargo run --bin stats < ../examples/example.zkif +// +pub fn main() -> Result<(), Box> { + let pretty = true; + + let mut messages = Messages::new(1); + + let mut buffer = vec![]; + stdin().read_to_end(&mut buffer)?; + messages.push_message(buffer)?; + + let mut stats = Stats::new(); + + let circuit = messages.last_circuit().unwrap(); + stats.num_public_inputs = circuit.connections().unwrap().variable_ids().unwrap().len() as u64; + stats.num_private_variables = circuit.free_variable_id() - stats.num_public_inputs - 1; + + for constraint in messages.iter_constraints() { + stats.multiplications += 1; + if constraint.a.len() > 0 { + stats.additions_a += (constraint.a.len() - 1) as u64; + } + if constraint.b.len() > 0 { + stats.additions_b += (constraint.b.len() - 1) as u64; + } + if constraint.c.len() > 0 { + stats.additions_c += (constraint.c.len() - 1) as u64; + } + } + stats.finish(); + + if pretty { + serde_json::to_writer_pretty(std::io::stdout(), &stats)?; + } else { + serde_json::to_writer(std::io::stdout(), &stats)?; + } + Ok(()) +} diff --git a/rust/src/bin/zkif_json.rs b/rust/src/bin/zkif_json.rs new file mode 100644 index 0000000..eb67317 --- /dev/null +++ b/rust/src/bin/zkif_json.rs @@ -0,0 +1,31 @@ +extern crate serde; +extern crate serde_json; +extern crate zkinterface; + +use std::error::Error; +use std::io::{stdin, Read}; + +use zkinterface::{owned::message::MessagesOwned, reading::Messages}; + +// Example: +// +// cargo run --bin zkif_json < ../examples/example.zkif +// +pub fn main() -> Result<(), Box> { + let pretty = true; + + let mut messages_raw = Messages::new(1); + + let mut buffer = vec![]; + stdin().read_to_end(&mut buffer)?; + messages_raw.push_message(buffer)?; + + let messages = MessagesOwned::from(&messages_raw); + + if pretty { + serde_json::to_writer_pretty(std::io::stdout(), &messages)?; + } else { + serde_json::to_writer(std::io::stdout(), &messages)?; + } + Ok(()) +} diff --git a/rust/src/cpp_gadget.rs b/rust/src/cpp_gadget.rs index 6b5516e..37dff34 100644 --- a/rust/src/cpp_gadget.rs +++ b/rust/src/cpp_gadget.rs @@ -5,7 +5,7 @@ use reading::Messages; use std::error::Error; use std::slice; -use writing::CircuitOwned; +use owned::circuit::CircuitOwned; #[allow(improper_ctypes)] extern "C" { @@ -50,7 +50,7 @@ fn callback_c( context.push_message(Vec::from(buf)).is_ok() } -pub fn call_gadget_wrapper(circuit: &CircuitOwned) -> Result> { +pub fn call_gadget_wrapper(circuit: &CircuitOwned) -> Result> { let mut message_buf = vec![]; circuit.write(&mut message_buf)?; @@ -77,7 +77,7 @@ pub fn call_gadget_wrapper(circuit: &CircuitOwned) -> Result CircuitOwned { @@ -29,7 +18,6 @@ pub fn example_circuit_inputs(x: u32, y: u32, zz: u32) -> CircuitOwned { values: Some(serialize_small(&[x, y, zz])), }, free_variable_id: 6, - r1cs_generation: true, field_maximum: None, } } @@ -68,13 +56,13 @@ pub fn write_example_constraints(mut writer: W) -> io::Result<()> } let constraints_built = builder.create_vector(&constraints_built); - let r1cs = R1CSConstraints::create(&mut builder, &R1CSConstraintsArgs { + let r1cs = ConstraintSystem::create(&mut builder, &ConstraintSystemArgs { constraints: Some(constraints_built), info: None, }); let message = Root::create(&mut builder, &RootArgs { - message_type: Message::R1CSConstraints, + message_type: Message::ConstraintSystem, message: Some(r1cs.as_union_value()), }); builder.finish_size_prefixed(message, None); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 9ade097..3fe2310 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,9 +1,11 @@ pub extern crate flatbuffers; +pub extern crate serde; +#[allow(unused_imports)] pub mod zkinterface_generated; pub mod reading; -pub mod writing; +pub mod owned; pub mod cpp_gadget; diff --git a/rust/src/writing.rs b/rust/src/owned/circuit.rs similarity index 59% rename from rust/src/writing.rs rename to rust/src/owned/circuit.rs index 5954d55..118d025 100644 --- a/rust/src/writing.rs +++ b/rust/src/owned/circuit.rs @@ -2,38 +2,37 @@ use flatbuffers::{FlatBufferBuilder, WIPOffset}; use std::io; +use serde::{Deserialize, Serialize}; use zkinterface_generated::zkinterface::{ Circuit, CircuitArgs, Message, Root, RootArgs, - Variables, - VariablesArgs, }; +use owned::variables::VariablesOwned; -// ==== Gadget Call ==== - -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct CircuitOwned { pub connections: VariablesOwned, pub free_variable_id: u64, - pub r1cs_generation: bool, - // witness_generation deduced from the presence of connections.values - pub field_maximum: Option>, //pub configuration: Option>, } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct VariablesOwned { - pub variable_ids: Vec, - pub values: Option>, - // pub info: Option>, +impl<'a> From> for CircuitOwned { + /// Convert from Flatbuffers references to owned structure. + fn from(circuit_ref: Circuit) -> CircuitOwned { + CircuitOwned { + connections: VariablesOwned::from(circuit_ref.connections().unwrap()), + free_variable_id: circuit_ref.free_variable_id(), + field_maximum: None, + } + } } impl CircuitOwned { @@ -47,7 +46,6 @@ impl CircuitOwned { values: None, }, free_variable_id: first_local_id, - r1cs_generation: false, field_maximum: None, } } @@ -63,11 +61,11 @@ impl CircuitOwned { values: None, }, free_variable_id: first_local_id + num_locals, - r1cs_generation: false, field_maximum: None, } } + /// Add this structure into a Flatbuffers message builder. pub fn build<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( &'args self, builder: &'mut_bldr mut FlatBufferBuilder<'bldr>, @@ -81,8 +79,6 @@ impl CircuitOwned { let call = Circuit::create(builder, &CircuitArgs { connections, free_variable_id: self.free_variable_id, - r1cs_generation: self.r1cs_generation, - witness_generation: self.connections.values.is_some(), field_maximum, configuration: None, }); @@ -93,6 +89,7 @@ impl CircuitOwned { }) } + /// Write this structure as a Flatbuffers message. pub fn write(&self, mut writer: W) -> io::Result<()> { let mut builder = FlatBufferBuilder::new(); let message = self.build(&mut builder); @@ -100,46 +97,3 @@ impl CircuitOwned { writer.write_all(builder.finished_data()) } } - -impl<'a> From> for CircuitOwned { - fn from(circuit: Circuit) -> CircuitOwned { - CircuitOwned { - connections: VariablesOwned::from(circuit.connections().unwrap()), - free_variable_id: circuit.free_variable_id(), - r1cs_generation: circuit.r1cs_generation(), - field_maximum: None, - } - } -} - -impl VariablesOwned { - pub fn build<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( - &'args self, - builder: &'mut_bldr mut FlatBufferBuilder<'bldr>, - ) -> WIPOffset> - { - let variable_ids = Some(builder.create_vector(&self.variable_ids)); - - let values = self.values.as_ref().map(|values| - builder.create_vector(values)); - - Variables::create(builder, &VariablesArgs { - variable_ids, - values, - info: None, - }) - } -} - -impl<'a> From> for VariablesOwned { - fn from(vars: Variables) -> VariablesOwned { - VariablesOwned { - variable_ids: match vars.variable_ids() { - Some(var_ids) => Vec::from(var_ids.safe_slice()), - None => vec![], - }, - values: vars.values().map(|bytes| - Vec::from(bytes)), - } - } -} \ No newline at end of file diff --git a/rust/src/owned/constraints.rs b/rust/src/owned/constraints.rs new file mode 100644 index 0000000..7163be6 --- /dev/null +++ b/rust/src/owned/constraints.rs @@ -0,0 +1,36 @@ +use owned::variables::VariablesOwned; +use serde::{Deserialize, Serialize}; +use zkinterface_generated::zkinterface::ConstraintSystem; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct ConstraintSystemOwned { + pub constraints: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct BilinearConstraintOwned { + pub linear_combination_a: VariablesOwned, + pub linear_combination_b: VariablesOwned, + pub linear_combination_c: VariablesOwned, +} + +impl<'a> From> for ConstraintSystemOwned { + /// Convert from Flatbuffers references to owned structure. + fn from(constraints_ref: ConstraintSystem) -> ConstraintSystemOwned { + let mut owned = ConstraintSystemOwned { + constraints: vec![], + }; + + let cons_ref = constraints_ref.constraints().unwrap(); + for i in 0..cons_ref.len() { + let con_ref = cons_ref.get(i); + owned.constraints.push(BilinearConstraintOwned { + linear_combination_a: VariablesOwned::from(con_ref.linear_combination_a().unwrap()), + linear_combination_b: VariablesOwned::from(con_ref.linear_combination_b().unwrap()), + linear_combination_c: VariablesOwned::from(con_ref.linear_combination_c().unwrap()), + }); + } + + owned + } +} diff --git a/rust/src/owned/message.rs b/rust/src/owned/message.rs new file mode 100644 index 0000000..db39b5e --- /dev/null +++ b/rust/src/owned/message.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; + +use owned::circuit::CircuitOwned; +use owned::constraints::ConstraintSystemOwned; +use owned::witness::WitnessOwned; +use reading::Messages; +use zkinterface_generated::zkinterface::Message; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct MessagesOwned { + circuits: Vec, + constraint_systems: Vec, + witnesses: Vec, +} + +impl From<&Messages> for MessagesOwned { + /// Convert from Flatbuffers messages to owned structure. + fn from(messages: &Messages) -> MessagesOwned { + let mut owned = MessagesOwned { + circuits: vec![], + constraint_systems: vec![], + witnesses: vec![], + }; + + for msg in messages.into_iter() { + match msg.message_type() { + Message::Circuit => { + let circuit_ref = msg.message_as_circuit().unwrap(); + owned.circuits.push(CircuitOwned::from(circuit_ref)); + } + Message::ConstraintSystem => { + let constraints_ref = msg.message_as_constraint_system().unwrap(); + owned + .constraint_systems + .push(ConstraintSystemOwned::from(constraints_ref)); + } + Message::Witness => { + let witness_ref = msg.message_as_witness().unwrap(); + owned.witnesses.push(WitnessOwned::from(witness_ref)); + } + Message::Command => {} + Message::NONE => {} + } + } + owned + } +} diff --git a/rust/src/owned/mod.rs b/rust/src/owned/mod.rs new file mode 100644 index 0000000..4cb37a4 --- /dev/null +++ b/rust/src/owned/mod.rs @@ -0,0 +1,5 @@ +pub mod message; +pub mod circuit; +pub mod constraints; +pub mod witness; +pub mod variables; \ No newline at end of file diff --git a/rust/src/owned/variables.rs b/rust/src/owned/variables.rs new file mode 100644 index 0000000..cfc1ef5 --- /dev/null +++ b/rust/src/owned/variables.rs @@ -0,0 +1,70 @@ +use serde::{Deserialize, Serialize}; + +use flatbuffers::{FlatBufferBuilder, WIPOffset}; +use zkinterface_generated::zkinterface::{ + Variables, + VariablesArgs, +}; +use reading::Variable; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct VariablesOwned { + pub variable_ids: Vec, + pub values: Option>, + // pub info: Option>, +} + +impl<'a> From> for VariablesOwned { + /// Convert from Flatbuffers references to owned structure. + fn from(variables_ref: Variables) -> VariablesOwned { + VariablesOwned { + variable_ids: match variables_ref.variable_ids() { + Some(var_ids) => Vec::from(var_ids.safe_slice()), + None => vec![], + }, + values: match variables_ref.values() { + Some(bytes) => Some(Vec::from(bytes)), + None => None, + }, + } + } +} + +impl VariablesOwned { + pub fn get_variables(&self) -> Vec { + let values = match self.values { + Some(ref values) => values as &[u8], + None => &[], // No values, only variable ids and empty values. + }; + + let n_vars = self.variable_ids.len(); + let stride = values.len() / n_vars; + + (0..n_vars) + .map(|var_i| + Variable { + id: self.variable_ids[var_i], + // Extract the value. Possibly empty. + value: &values[stride * var_i..stride * (var_i + 1)], + } + ).collect() + } + + /// Add this structure into a Flatbuffers message builder. + pub fn build<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + &'args self, + builder: &'mut_bldr mut FlatBufferBuilder<'bldr>, + ) -> WIPOffset> + { + let variable_ids = Some(builder.create_vector(&self.variable_ids)); + + let values = self.values.as_ref().map(|values| + builder.create_vector(values)); + + Variables::create(builder, &VariablesArgs { + variable_ids, + values, + info: None, + }) + } +} diff --git a/rust/src/owned/witness.rs b/rust/src/owned/witness.rs new file mode 100644 index 0000000..84674fe --- /dev/null +++ b/rust/src/owned/witness.rs @@ -0,0 +1,17 @@ +use owned::variables::VariablesOwned; +use serde::{Deserialize, Serialize}; +use zkinterface_generated::zkinterface::Witness; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct WitnessOwned { + assigned_variables: VariablesOwned, +} + +impl<'a> From> for WitnessOwned { + /// Convert from Flatbuffers references to owned structure. + fn from(witness_ref: Witness) -> WitnessOwned { + WitnessOwned { + assigned_variables: VariablesOwned::from(witness_ref.assigned_variables().unwrap()), + } + } +} diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 815b2c4..10a8f69 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -18,18 +18,18 @@ pub fn parse_call(call_msg: &[u8]) -> Option<(Circuit, Vec)> { let call = get_size_prefixed_root_as_root(call_msg).message_as_circuit()?; let input_var_ids = call.connections()?.variable_ids()?.safe_slice(); - let assigned = if call.witness_generation() { - let bytes = call.connections()?.values()?; - let stride = bytes.len() / input_var_ids.len(); - - (0..input_var_ids.len()).map(|i| - Variable { - id: input_var_ids[i], - value: &bytes[stride * i..stride * (i + 1)], - } - ).collect() - } else { - vec![] + let assigned = match call.connections()?.values() { + Some(bytes) => { + let stride = bytes.len() / input_var_ids.len(); + + (0..input_var_ids.len()).map(|i| + Variable { + id: input_var_ids[i], + value: &bytes[stride * i..stride * (i + 1)], + } + ).collect() + } + None => vec![], }; Some((call, assigned)) @@ -76,11 +76,12 @@ impl fmt::Debug for Messages { let mut has_witness = false; let mut has_constraints = false; - for root in self { + for root in self.into_iter() { match root.message_type() { Circuit => has_circuit = true, Witness => has_witness = true, - R1CSConstraints => has_constraints = true, + ConstraintSystem => has_constraints = true, + Command => {} NONE => {} } } @@ -94,7 +95,7 @@ impl fmt::Debug for Messages { } } if let Some(circuit) = self.last_circuit() { - //write!(f, "{:?}\n", super::writing::CircuitOwned::from(circuit))?; + //write!(f, "{:?}\n", super::owned::circuit::CircuitOwned::from(circuit))?; write!(f, "Free variable id: {}\n", circuit.free_variable_id())?; } } @@ -110,7 +111,7 @@ impl fmt::Debug for Messages { } if has_constraints { - write!(f, "\nZkInterface {:?}\n", R1CSConstraints)?; + write!(f, "\nZkInterface {:?}\n", ConstraintSystem)?; for constraint in self.iter_constraints() { write!(f, "{:?}\n", constraint)?; } @@ -328,7 +329,7 @@ impl<'a> Iterator for R1CSIterator<'a> { let message = self.messages_iter.next()?; // Parse the message, skip irrelevant message types, or fail if invalid. - let constraints = match message.message_as_r1csconstraints() { + let constraints = match message.message_as_constraint_system() { Some(message) => message.constraints().unwrap(), None => continue, }; @@ -391,6 +392,23 @@ impl<'a> Variable<'a> { pub fn has_value(&self) -> bool { self.value.len() > 0 } + + pub fn is_constant_one(&self) -> bool { + if self.id != 0 { + return false; + } + if self.value.len() > 0 { + if self.value[0] != 1 { + return false; + } + for v in self.value[1..].iter() { + if *v != 0 { + return false; + } + } + } + return true; + } } impl<'a> fmt::Debug for Variable<'a> { diff --git a/rust/src/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index ebeb1f8..e24c071 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -1,9 +1,15 @@ // automatically generated by the FlatBuffers compiler, do not modify + +use std::mem; +use std::cmp::Ordering; + +extern crate flatbuffers; +use self::flatbuffers::EndianScalar; + +#[allow(unused_imports, dead_code)] pub mod zkinterface { - #![allow(dead_code)] - #![allow(unused_imports)] use std::mem; use std::cmp::Ordering; @@ -13,17 +19,18 @@ pub mod zkinterface { #[allow(non_camel_case_types)] #[repr(u8)] -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Message { NONE = 0, Circuit = 1, - R1CSConstraints = 2, + ConstraintSystem = 2, Witness = 3, + Command = 4, } -const ENUM_MIN_MESSAGE: u8 = 0; -const ENUM_MAX_MESSAGE: u8 = 3; +pub const ENUM_MIN_MESSAGE: u8 = 0; +pub const ENUM_MAX_MESSAGE: u8 = 4; impl<'a> flatbuffers::Follow<'a> for Message { type Inner = Self; @@ -57,33 +64,35 @@ impl flatbuffers::Push for Message { } #[allow(non_camel_case_types)] -const ENUM_VALUES_MESSAGE:[Message; 4] = [ +pub const ENUM_VALUES_MESSAGE:[Message; 5] = [ Message::NONE, Message::Circuit, - Message::R1CSConstraints, - Message::Witness + Message::ConstraintSystem, + Message::Witness, + Message::Command ]; #[allow(non_camel_case_types)] -const ENUM_NAMES_MESSAGE:[&'static str; 4] = [ +pub const ENUM_NAMES_MESSAGE:[&'static str; 5] = [ "NONE", "Circuit", - "R1CSConstraints", - "Witness" + "ConstraintSystem", + "Witness", + "Command" ]; pub fn enum_name_message(e: Message) -> &'static str { - let index: usize = e as usize; - ENUM_NAMES_MESSAGE[index] + let index = e as u8; + ENUM_NAMES_MESSAGE[index as usize] } pub struct MessageUnionTableOffset {} -/// A description of a circuit or sub-circuit. -/// This can be a complete circuit ready for proving, -/// or a part of a circuit being built. pub enum CircuitOffset {} #[derive(Copy, Clone, Debug, PartialEq)] +/// A description of a circuit or sub-circuit. +/// This can be a complete circuit ready for proving, +/// or a part of a circuit being built. pub struct Circuit<'a> { pub _tab: flatbuffers::Table<'a>, } @@ -114,17 +123,13 @@ impl<'a> Circuit<'a> { if let Some(x) = args.configuration { builder.add_configuration(x); } if let Some(x) = args.field_maximum { builder.add_field_maximum(x); } if let Some(x) = args.connections { builder.add_connections(x); } - builder.add_witness_generation(args.witness_generation); - builder.add_r1cs_generation(args.r1cs_generation); builder.finish() } pub const VT_CONNECTIONS: flatbuffers::VOffsetT = 4; pub const VT_FREE_VARIABLE_ID: flatbuffers::VOffsetT = 6; - pub const VT_R1CS_GENERATION: flatbuffers::VOffsetT = 8; - pub const VT_WITNESS_GENERATION: flatbuffers::VOffsetT = 10; - pub const VT_FIELD_MAXIMUM: flatbuffers::VOffsetT = 12; - pub const VT_CONFIGURATION: flatbuffers::VOffsetT = 14; + pub const VT_FIELD_MAXIMUM: flatbuffers::VOffsetT = 8; + pub const VT_CONFIGURATION: flatbuffers::VOffsetT = 10; /// Variables to use as connections to the sub-circuit. /// @@ -132,7 +137,7 @@ impl<'a> Circuit<'a> { /// - Or variables to use as output connections from the gadget. /// - Variables are allocated by the sender of this message. /// - The same structure must be provided for R1CS and witness generations. - /// - If `witness_generation=true`, variables must be assigned values. + /// - If using `Command.witness_generation`, variables must be assigned values. #[inline] pub fn connections(&self) -> Option> { self._tab.get::>>(Circuit::VT_CONNECTIONS, None) @@ -143,18 +148,6 @@ impl<'a> Circuit<'a> { pub fn free_variable_id(&self) -> u64 { self._tab.get::(Circuit::VT_FREE_VARIABLE_ID, Some(0)).unwrap() } - /// Whether a constraint system is being generated. - /// Provide constraints in R1CSConstraints messages. - #[inline] - pub fn r1cs_generation(&self) -> bool { - self._tab.get::(Circuit::VT_R1CS_GENERATION, Some(false)).unwrap() - } - /// Whether a witness is being generated. - /// Provide the witness in `connections.values` and Witness messages. - #[inline] - pub fn witness_generation(&self) -> bool { - self._tab.get::(Circuit::VT_WITNESS_GENERATION, Some(false)).unwrap() - } /// The largest element of the finite field used by the current system. /// A canonical little-endian representation of the field order minus one. /// See `Variables.values` below. @@ -176,8 +169,6 @@ impl<'a> Circuit<'a> { pub struct CircuitArgs<'a> { pub connections: Option>>, pub free_variable_id: u64, - pub r1cs_generation: bool, - pub witness_generation: bool, pub field_maximum: Option>>, pub configuration: Option>>>>, } @@ -187,8 +178,6 @@ impl<'a> Default for CircuitArgs<'a> { CircuitArgs { connections: None, free_variable_id: 0, - r1cs_generation: false, - witness_generation: false, field_maximum: None, configuration: None, } @@ -208,14 +197,6 @@ impl<'a: 'b, 'b> CircuitBuilder<'a, 'b> { self.fbb_.push_slot::(Circuit::VT_FREE_VARIABLE_ID, free_variable_id, 0); } #[inline] - pub fn add_r1cs_generation(&mut self, r1cs_generation: bool) { - self.fbb_.push_slot::(Circuit::VT_R1CS_GENERATION, r1cs_generation, false); - } - #[inline] - pub fn add_witness_generation(&mut self, witness_generation: bool) { - self.fbb_.push_slot::(Circuit::VT_WITNESS_GENERATION, witness_generation, false); - } - #[inline] pub fn add_field_maximum(&mut self, field_maximum: flatbuffers::WIPOffset>) { self.fbb_.push_slot_always::>(Circuit::VT_FIELD_MAXIMUM, field_maximum); } @@ -238,18 +219,18 @@ impl<'a: 'b, 'b> CircuitBuilder<'a, 'b> { } } -/// R1CSConstraints represents constraints to be added to the constraint system. -/// -/// Multiple such messages are equivalent to the concatenation of `constraints` arrays. -pub enum R1CSConstraintsOffset {} +pub enum ConstraintSystemOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct R1CSConstraints<'a> { +/// ConstraintSystem represents constraints to be added to the constraint system. +/// +/// Multiple such messages are equivalent to the concatenation of `constraints` arrays. +pub struct ConstraintSystem<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for R1CSConstraints<'a> { - type Inner = R1CSConstraints<'a>; +impl<'a> flatbuffers::Follow<'a> for ConstraintSystem<'a> { + type Inner = ConstraintSystem<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -258,18 +239,18 @@ impl<'a> flatbuffers::Follow<'a> for R1CSConstraints<'a> { } } -impl<'a> R1CSConstraints<'a> { +impl<'a> ConstraintSystem<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - R1CSConstraints { + ConstraintSystem { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args R1CSConstraintsArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = R1CSConstraintsBuilder::new(_fbb); + args: &'args ConstraintSystemArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = ConstraintSystemBuilder::new(_fbb); if let Some(x) = args.info { builder.add_info(x); } if let Some(x) = args.constraints { builder.add_constraints(x); } builder.finish() @@ -280,7 +261,7 @@ impl<'a> R1CSConstraints<'a> { #[inline] pub fn constraints(&self) -> Option>>> { - self._tab.get::>>>>(R1CSConstraints::VT_CONSTRAINTS, None) + self._tab.get::>>>>(ConstraintSystem::VT_CONSTRAINTS, None) } /// Optional: Any complementary info that may be useful. /// @@ -288,59 +269,59 @@ impl<'a> R1CSConstraints<'a> { /// Example: custom hints to an optimizer or analyzer. #[inline] pub fn info(&self) -> Option>>> { - self._tab.get::>>>>(R1CSConstraints::VT_INFO, None) + self._tab.get::>>>>(ConstraintSystem::VT_INFO, None) } } -pub struct R1CSConstraintsArgs<'a> { +pub struct ConstraintSystemArgs<'a> { pub constraints: Option>>>>, pub info: Option>>>>, } -impl<'a> Default for R1CSConstraintsArgs<'a> { +impl<'a> Default for ConstraintSystemArgs<'a> { #[inline] fn default() -> Self { - R1CSConstraintsArgs { + ConstraintSystemArgs { constraints: None, info: None, } } } -pub struct R1CSConstraintsBuilder<'a: 'b, 'b> { +pub struct ConstraintSystemBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> R1CSConstraintsBuilder<'a, 'b> { +impl<'a: 'b, 'b> ConstraintSystemBuilder<'a, 'b> { #[inline] pub fn add_constraints(&mut self, constraints: flatbuffers::WIPOffset>>>) { - self.fbb_.push_slot_always::>(R1CSConstraints::VT_CONSTRAINTS, constraints); + self.fbb_.push_slot_always::>(ConstraintSystem::VT_CONSTRAINTS, constraints); } #[inline] pub fn add_info(&mut self, info: flatbuffers::WIPOffset>>>) { - self.fbb_.push_slot_always::>(R1CSConstraints::VT_INFO, info); + self.fbb_.push_slot_always::>(ConstraintSystem::VT_INFO, info); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> R1CSConstraintsBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ConstraintSystemBuilder<'a, 'b> { let start = _fbb.start_table(); - R1CSConstraintsBuilder { + ConstraintSystemBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } +pub enum WitnessOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + /// Witness represents an assignment of values to variables. /// /// - Does not include variables already given in `Circuit.connections`. /// - Does not include the constant one variable. /// - Multiple such messages are equivalent to the concatenation of `Variables` arrays. -pub enum WitnessOffset {} -#[derive(Copy, Clone, Debug, PartialEq)] - pub struct Witness<'a> { pub _tab: flatbuffers::Table<'a>, } @@ -414,14 +395,130 @@ impl<'a: 'b, 'b> WitnessBuilder<'a, 'b> { } } +pub enum CommandOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +/// Optional: Command messages can be used to request actions from the receiver. This makes it +/// possible to write code that works in different environments. Commands and parameters +/// can be passed over the same byte stream as other messages; if so Command must be the first +/// message. This reduces the need for environment-specific methods (it can replace CLI --flags, etc). +pub struct Command<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Command<'a> { + type Inner = Command<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> Command<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Command { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args CommandArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = CommandBuilder::new(_fbb); + if let Some(x) = args.parameters { builder.add_parameters(x); } + builder.add_witness_generation(args.witness_generation); + builder.add_r1cs_generation(args.r1cs_generation); + builder.finish() + } + + pub const VT_R1CS_GENERATION: flatbuffers::VOffsetT = 4; + pub const VT_WITNESS_GENERATION: flatbuffers::VOffsetT = 6; + pub const VT_PARAMETERS: flatbuffers::VOffsetT = 8; + + /// For gadget flows. + /// Request the generation of a constraint system (or part thereof). + /// If true, this must be followed by a Circuit. + /// The response must be another Circuit message with a greater `free_variable_id` + /// followed by one or more ConstraintSystem messages. + #[inline] + pub fn r1cs_generation(&self) -> bool { + self._tab.get::(Command::VT_R1CS_GENERATION, Some(false)).unwrap() + } + /// For gadget flows. + /// Request the generation of a witness (or part thereof). + /// If true, this must be followed by a Circuit, and the `connections` + /// variables must contain input values. + /// The response must be another Circuit message, with a greater `free_variable_id`, + /// with output values in `connections` variables, followed by one or more `Witness` messages. + #[inline] + pub fn witness_generation(&self) -> bool { + self._tab.get::(Command::VT_WITNESS_GENERATION, Some(false)).unwrap() + } + /// Optional: Any complementary parameter that may be useful. + #[inline] + pub fn parameters(&self) -> Option>>> { + self._tab.get::>>>>(Command::VT_PARAMETERS, None) + } +} + +pub struct CommandArgs<'a> { + pub r1cs_generation: bool, + pub witness_generation: bool, + pub parameters: Option>>>>, +} +impl<'a> Default for CommandArgs<'a> { + #[inline] + fn default() -> Self { + CommandArgs { + r1cs_generation: false, + witness_generation: false, + parameters: None, + } + } +} +pub struct CommandBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> CommandBuilder<'a, 'b> { + #[inline] + pub fn add_r1cs_generation(&mut self, r1cs_generation: bool) { + self.fbb_.push_slot::(Command::VT_R1CS_GENERATION, r1cs_generation, false); + } + #[inline] + pub fn add_witness_generation(&mut self, witness_generation: bool) { + self.fbb_.push_slot::(Command::VT_WITNESS_GENERATION, witness_generation, false); + } + #[inline] + pub fn add_parameters(&mut self, parameters: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(Command::VT_PARAMETERS, parameters); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> CommandBuilder<'a, 'b> { + let start = _fbb.start_table(); + CommandBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum BilinearConstraintOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + /// A single R1CS constraint between variables. /// /// - Represents the linear combinations of variables A, B, C such that: /// (A) * (B) = (C) /// - A linear combination is given as a sequence of (variable ID, coefficient). -pub enum BilinearConstraintOffset {} -#[derive(Copy, Clone, Debug, PartialEq)] - pub struct BilinearConstraint<'a> { pub _tab: flatbuffers::Table<'a>, } @@ -519,6 +616,9 @@ impl<'a: 'b, 'b> BilinearConstraintBuilder<'a, 'b> { } } +pub enum VariablesOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + /// A description of multiple variables. /// /// - Each variable is identified by a numerical ID. @@ -528,9 +628,6 @@ impl<'a: 'b, 'b> BilinearConstraintBuilder<'a, 'b> { /// - During witness generation, the values form the assignment to the variables. /// - In `BilinearConstraint` linear combinations, the values are the coefficients /// applied to variables in a linear combination. -pub enum VariablesOffset {} -#[derive(Copy, Clone, Debug, PartialEq)] - pub struct Variables<'a> { pub _tab: flatbuffers::Table<'a>, } @@ -648,10 +745,10 @@ impl<'a: 'b, 'b> VariablesBuilder<'a, 'b> { } } -/// Generic key-value for custom attributes. pub enum KeyValueOffset {} #[derive(Copy, Clone, Debug, PartialEq)] +/// Generic key-value for custom attributes. pub struct KeyValue<'a> { pub _tab: flatbuffers::Table<'a>, } @@ -794,9 +891,9 @@ impl<'a> Root<'a> { #[inline] #[allow(non_snake_case)] - pub fn message_as_r1csconstraints(&self) -> Option> { - if self.message_type() == Message::R1CSConstraints { - self.message().map(|u| R1CSConstraints::init_from_table(u)) + pub fn message_as_constraint_system(&self) -> Option> { + if self.message_type() == Message::ConstraintSystem { + self.message().map(|u| ConstraintSystem::init_from_table(u)) } else { None } @@ -812,6 +909,16 @@ impl<'a> Root<'a> { } } + #[inline] + #[allow(non_snake_case)] + pub fn message_as_command(&self) -> Option> { + if self.message_type() == Message::Command { + self.message().map(|u| Command::init_from_table(u)) + } else { + None + } + } + } pub struct RootArgs { diff --git a/zkinterface.fbs b/zkinterface.fbs index 99d908e..1aef8f3 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -8,8 +8,9 @@ namespace zkinterface; union Message { Circuit, - R1CSConstraints, + ConstraintSystem, Witness, + Command, } /// A description of a circuit or sub-circuit. @@ -23,24 +24,13 @@ table Circuit { /// - Or variables to use as output connections from the gadget. /// - Variables are allocated by the sender of this message. /// - The same structure must be provided for R1CS and witness generations. - /// - If `witness_generation=true`, variables must be assigned values. + /// - If using `Command.witness_generation`, variables must be assigned values. connections :Variables; /// A variable ID greater than all IDs allocated by the sender of this message. /// The recipient of this message can allocate new IDs >= free_variable_id. free_variable_id :uint64; - // The fields below are required to call a backend or a gadget, - // but optional in the response from a gadget. - - /// Whether a constraint system is being generated. - /// Provide constraints in R1CSConstraints messages. - r1cs_generation :bool; - - /// Whether a witness is being generated. - /// Provide the witness in `connections.values` and Witness messages. - witness_generation :bool; - /// The largest element of the finite field used by the current system. /// A canonical little-endian representation of the field order minus one. /// See `Variables.values` below. @@ -54,10 +44,10 @@ table Circuit { configuration :[KeyValue]; } -/// R1CSConstraints represents constraints to be added to the constraint system. +/// ConstraintSystem represents constraints to be added to the constraint system. /// /// Multiple such messages are equivalent to the concatenation of `constraints` arrays. -table R1CSConstraints { +table ConstraintSystem { constraints :[BilinearConstraint]; /// Optional: Any complementary info that may be useful. @@ -76,6 +66,30 @@ table Witness { assigned_variables :Variables; } +/// Optional: Command messages can be used to request actions from the receiver. This makes it +/// possible to write code that works in different environments. Commands and parameters +/// can be passed over the same byte stream as other messages; if so Command must be the first +/// message. This reduces the need for environment-specific methods (it can replace CLI --flags, etc). +table Command { + /// For gadget flows. + /// Request the generation of a constraint system (or part thereof). + /// If true, this must be followed by a Circuit. + /// The response must be another Circuit message with a greater `free_variable_id` + /// followed by one or more ConstraintSystem messages. + r1cs_generation :bool; + + /// For gadget flows. + /// Request the generation of a witness (or part thereof). + /// If true, this must be followed by a Circuit, and the `connections` + /// variables must contain input values. + /// The response must be another Circuit message, with a greater `free_variable_id`, + /// with output values in `connections` variables, followed by one or more `Witness` messages. + witness_generation :bool; + + /// Optional: Any complementary parameter that may be useful. + parameters :[KeyValue]; +} + // ==== Secondary Types ====