From 1a9d8901ac1a4cd971827c2397e11becae5d348b Mon Sep 17 00:00:00 2001 From: aurel Date: Mon, 1 Jun 2020 22:27:18 +0200 Subject: [PATCH 01/17] Fix warnings (dyn Error) --- rust/src/bin/example.rs | 2 +- rust/src/bin/print.rs | 2 +- rust/src/cpp_gadget.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/src/bin/example.rs b/rust/src/bin/example.rs index b233504..4d6f394 100644 --- a/rust/src/bin/example.rs +++ b/rust/src/bin/example.rs @@ -9,7 +9,7 @@ use std::error::Error; // // cargo run --bin example > 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..2a3bacb 100644 --- a/rust/src/bin/print.rs +++ b/rust/src/bin/print.rs @@ -9,7 +9,7 @@ use std::error::Error; // // cargo run --bin print < 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/cpp_gadget.rs b/rust/src/cpp_gadget.rs index 6b5516e..1d10b79 100644 --- a/rust/src/cpp_gadget.rs +++ b/rust/src/cpp_gadget.rs @@ -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)?; From 1e9a578b075dda7dc71455953cdbbbd4f5181f19 Mon Sep 17 00:00:00 2001 From: aurel Date: Mon, 1 Jun 2020 22:33:18 +0200 Subject: [PATCH 02/17] Update flatc generated code (rust, js) --- js/zkinterface_generated.js | 199 +++++++++++++++++++++++++++++- rust/build.rs | 1 + rust/src/zkinterface_generated.rs | 50 ++++---- 3 files changed, 220 insertions(+), 30 deletions(-) diff --git a/js/zkinterface_generated.js b/js/zkinterface_generated.js index 8b5c99e..0c574fe 100644 --- a/js/zkinterface_generated.js +++ b/js/zkinterface_generated.js @@ -7,13 +7,23 @@ 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' }; /** @@ -55,6 +65,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. * @@ -264,6 +284,27 @@ 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 {flatbuffers.Offset} configurationOffset + * @returns {flatbuffers.Offset} + */ +zkinterface.Circuit.createCircuit = function(builder, connectionsOffset, freeVariableId, r1csGeneration, witnessGeneration, fieldMaximumOffset, 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.addConfiguration(builder, configurationOffset); + return zkinterface.Circuit.endCircuit(builder); +} + /** * R1CSConstraints represents constraints to be added to the constraint system. * @@ -303,6 +344,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 +469,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 +523,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 +566,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 +618,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 +695,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 +755,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 +951,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 +1003,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 +1100,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 +1148,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 +1223,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/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/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index ebeb1f8..ce769c3 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -1,9 +1,9 @@ // automatically generated by the FlatBuffers compiler, do not modify +extern crate flatbuffers; +#[allow(unused_imports, dead_code)] pub mod zkinterface { - #![allow(dead_code)] - #![allow(unused_imports)] use std::mem; use std::cmp::Ordering; @@ -13,7 +13,7 @@ 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, @@ -22,8 +22,8 @@ pub enum Message { } -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 = 3; impl<'a> flatbuffers::Follow<'a> for Message { type Inner = Self; @@ -57,7 +57,7 @@ impl flatbuffers::Push for Message { } #[allow(non_camel_case_types)] -const ENUM_VALUES_MESSAGE:[Message; 4] = [ +pub const ENUM_VALUES_MESSAGE:[Message; 4] = [ Message::NONE, Message::Circuit, Message::R1CSConstraints, @@ -65,7 +65,7 @@ const ENUM_VALUES_MESSAGE:[Message; 4] = [ ]; #[allow(non_camel_case_types)] -const ENUM_NAMES_MESSAGE:[&'static str; 4] = [ +pub const ENUM_NAMES_MESSAGE:[&'static str; 4] = [ "NONE", "Circuit", "R1CSConstraints", @@ -73,17 +73,17 @@ const ENUM_NAMES_MESSAGE:[&'static str; 4] = [ ]; 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>, } @@ -238,12 +238,12 @@ 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 {} #[derive(Copy, Clone, Debug, PartialEq)] +/// R1CSConstraints represents constraints to be added to the constraint system. +/// +/// Multiple such messages are equivalent to the concatenation of `constraints` arrays. pub struct R1CSConstraints<'a> { pub _tab: flatbuffers::Table<'a>, } @@ -333,14 +333,14 @@ impl<'a: 'b, 'b> R1CSConstraintsBuilder<'a, 'b> { } } +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 +414,14 @@ impl<'a: 'b, 'b> WitnessBuilder<'a, 'b> { } } +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 +519,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 +531,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 +648,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>, } From e5b75864dd0babe81d79adf54610af12bb4180fd Mon Sep 17 00:00:00 2001 From: aurel Date: Mon, 1 Jun 2020 23:33:48 +0200 Subject: [PATCH 03/17] json: basic JSON converter tool --- rust/Cargo.lock | 82 ++++++++++++++++++++++++++++++++++++++- rust/Cargo.toml | 4 +- rust/src/bin/zkif_json.rs | 52 +++++++++++++++++++++++++ rust/src/lib.rs | 1 + rust/src/reading.rs | 2 +- rust/src/writing.rs | 5 ++- 6 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 rust/src/bin/zkif_json.rs 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/src/bin/zkif_json.rs b/rust/src/bin/zkif_json.rs new file mode 100644 index 0000000..e37d7ac --- /dev/null +++ b/rust/src/bin/zkif_json.rs @@ -0,0 +1,52 @@ +extern crate serde; +extern crate serde_json; +extern crate zkinterface; + +use serde::{Deserialize, Serialize}; +use std::error::Error; +use std::io::{stdin, Read}; + +use zkinterface::{ + reading::Messages, writing::CircuitOwned, zkinterface_generated::zkinterface::Message, +}; + +#[derive(Serialize, Deserialize, Debug)] +struct JsonCircuit { + circuit: CircuitOwned, +} + +// Example: +// +// cargo run --bin zkif_json < 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)?; + + for msg in messages.into_iter() { + match msg.message_type() { + Message::Circuit => { + let json = JsonCircuit { + circuit: CircuitOwned::from(msg.message_as_circuit().unwrap()), + }; + + if pretty { + serde_json::to_writer_pretty(std::io::stdout(), &json)?; + } else { + serde_json::to_writer(std::io::stdout(), &json)?; + } + } + Message::Witness => {} + Message::R1CSConstraints => {} + Message::NONE => {} + } + print!("\n"); + } + + Ok(()) +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 9ade097..ed7de57 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,4 +1,5 @@ pub extern crate flatbuffers; +pub extern crate serde; pub mod zkinterface_generated; diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 815b2c4..1268d5b 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -76,7 +76,7 @@ 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, diff --git a/rust/src/writing.rs b/rust/src/writing.rs index 5954d55..4ac6d0e 100644 --- a/rust/src/writing.rs +++ b/rust/src/writing.rs @@ -2,6 +2,7 @@ use flatbuffers::{FlatBufferBuilder, WIPOffset}; use std::io; +use serde::{Deserialize, Serialize}; use zkinterface_generated::zkinterface::{ Circuit, CircuitArgs, @@ -15,7 +16,7 @@ use zkinterface_generated::zkinterface::{ // ==== Gadget Call ==== -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct CircuitOwned { pub connections: VariablesOwned, @@ -29,7 +30,7 @@ pub struct CircuitOwned { //pub configuration: Option>, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct VariablesOwned { pub variable_ids: Vec, pub values: Option>, From 29a65c30c6e37575edda6954f99a523ae0044f74 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 00:00:24 +0200 Subject: [PATCH 04/17] arith: add attribute for arithmetic / fan-in 2 circuits --- js/zkinterface_generated.js | 46 ++++++++++++++++--- rust/src/examples.rs | 1 + rust/src/reading.rs | 10 +++++ rust/src/writing.rs | 7 +++ rust/src/zkinterface_generated.rs | 75 ++++++++++++++++++++++++++++++- zkinterface.fbs | 6 +++ 6 files changed, 139 insertions(+), 6 deletions(-) diff --git a/js/zkinterface_generated.js b/js/zkinterface_generated.js index 0c574fe..8a50850 100644 --- a/js/zkinterface_generated.js +++ b/js/zkinterface_generated.js @@ -26,6 +26,22 @@ zkinterface.MessageName = { '3': 'Witness' }; +/** + * @enum {number} + */ +zkinterface.CircuitType = { + R1CS: 0, + FanIn2: 1 +}; + +/** + * @enum {string} + */ +zkinterface.CircuitTypeName = { + '0': 'R1CS', + '1': 'FanIn2' +}; + /** * A description of a circuit or sub-circuit. * This can be a complete circuit ready for proving, @@ -154,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. * @@ -166,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; }; @@ -174,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; }; @@ -182,7 +208,7 @@ zkinterface.Circuit.prototype.configurationLength = function() { * @param {flatbuffers.Builder} builder */ zkinterface.Circuit.startCircuit = function(builder) { - builder.startObject(6); + builder.startObject(7); }; /** @@ -246,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); }; /** @@ -291,16 +325,18 @@ zkinterface.Circuit.endCircuit = function(builder) { * @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, configurationOffset) { +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); } diff --git a/rust/src/examples.rs b/rust/src/examples.rs index c1af26e..2c5747b 100644 --- a/rust/src/examples.rs +++ b/rust/src/examples.rs @@ -31,6 +31,7 @@ pub fn example_circuit_inputs(x: u32, y: u32, zz: u32) -> CircuitOwned { free_variable_id: 6, r1cs_generation: true, field_maximum: None, + circuit_type: "R1CS".to_string(), } } diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 1268d5b..4946199 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -9,6 +9,7 @@ use std::path::Path; use zkinterface_generated::zkinterface::{ BilinearConstraint, Circuit, + CircuitType, get_size_prefixed_root_as_root, Root, Variables, @@ -298,6 +299,15 @@ impl Messages { constraints: None, } } + + pub fn validate_circuit_type(&self) -> Result<(), String> { + for circuit in self.circuits() { + if circuit.circuit_type() != CircuitType::R1CS { + return Err("fan-in 2 not supported".to_string()); + } + } + Ok(()) + } } pub type Term<'a> = Variable<'a>; diff --git a/rust/src/writing.rs b/rust/src/writing.rs index 4ac6d0e..95c112e 100644 --- a/rust/src/writing.rs +++ b/rust/src/writing.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize}; use zkinterface_generated::zkinterface::{ Circuit, CircuitArgs, + CircuitType, Message, Root, RootArgs, @@ -27,6 +28,8 @@ pub struct CircuitOwned { pub field_maximum: Option>, + pub circuit_type: String, + //pub configuration: Option>, } @@ -50,6 +53,7 @@ impl CircuitOwned { free_variable_id: first_local_id, r1cs_generation: false, field_maximum: None, + circuit_type: "R1CS".to_string(), } } @@ -66,6 +70,7 @@ impl CircuitOwned { free_variable_id: first_local_id + num_locals, r1cs_generation: false, field_maximum: None, + circuit_type: "R1CS".to_string(), } } @@ -85,6 +90,7 @@ impl CircuitOwned { r1cs_generation: self.r1cs_generation, witness_generation: self.connections.values.is_some(), field_maximum, + circuit_type: CircuitType::R1CS, configuration: None, }); @@ -109,6 +115,7 @@ impl<'a> From> for CircuitOwned { free_variable_id: circuit.free_variable_id(), r1cs_generation: circuit.r1cs_generation(), field_maximum: None, + circuit_type: "R1CS".to_string(), } } } diff --git a/rust/src/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index ce769c3..5aa8e69 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -78,6 +78,66 @@ pub fn enum_name_message(e: Message) -> &'static str { } pub struct MessageUnionTableOffset {} +#[allow(non_camel_case_types)] +#[repr(i8)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum CircuitType { + R1CS = 0, + FanIn2 = 1, + +} + +pub const ENUM_MIN_CIRCUIT_TYPE: i8 = 0; +pub const ENUM_MAX_CIRCUIT_TYPE: i8 = 1; + +impl<'a> flatbuffers::Follow<'a> for CircuitType { + type Inner = Self; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::read_scalar_at::(buf, loc) + } +} + +impl flatbuffers::EndianScalar for CircuitType { + #[inline] + fn to_little_endian(self) -> Self { + let n = i8::to_le(self as i8); + let p = &n as *const i8 as *const CircuitType; + unsafe { *p } + } + #[inline] + fn from_little_endian(self) -> Self { + let n = i8::from_le(self as i8); + let p = &n as *const i8 as *const CircuitType; + unsafe { *p } + } +} + +impl flatbuffers::Push for CircuitType { + type Output = CircuitType; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, *self); + } +} + +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_CIRCUIT_TYPE:[CircuitType; 2] = [ + CircuitType::R1CS, + CircuitType::FanIn2 +]; + +#[allow(non_camel_case_types)] +pub const ENUM_NAMES_CIRCUIT_TYPE:[&'static str; 2] = [ + "R1CS", + "FanIn2" +]; + +pub fn enum_name_circuit_type(e: CircuitType) -> &'static str { + let index = e as i8; + ENUM_NAMES_CIRCUIT_TYPE[index as usize] +} + pub enum CircuitOffset {} #[derive(Copy, Clone, Debug, PartialEq)] @@ -114,6 +174,7 @@ 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_circuit_type(args.circuit_type); builder.add_witness_generation(args.witness_generation); builder.add_r1cs_generation(args.r1cs_generation); builder.finish() @@ -124,7 +185,8 @@ impl<'a> Circuit<'a> { 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_CIRCUIT_TYPE: flatbuffers::VOffsetT = 14; + pub const VT_CONFIGURATION: flatbuffers::VOffsetT = 16; /// Variables to use as connections to the sub-circuit. /// @@ -162,6 +224,11 @@ impl<'a> Circuit<'a> { pub fn field_maximum(&self) -> Option<&'a [u8]> { self._tab.get::>>(Circuit::VT_FIELD_MAXIMUM, None).map(|v| v.safe_slice()) } + /// Whether this is R1CS or arithmetic circuit. + #[inline] + pub fn circuit_type(&self) -> CircuitType { + self._tab.get::(Circuit::VT_CIRCUIT_TYPE, Some(CircuitType::R1CS)).unwrap() + } /// Optional: Any custom parameter that may influence the circuit construction. /// /// Example: function_name, if a gadget supports multiple function variants. @@ -179,6 +246,7 @@ pub struct CircuitArgs<'a> { pub r1cs_generation: bool, pub witness_generation: bool, pub field_maximum: Option>>, + pub circuit_type: CircuitType, pub configuration: Option>>>>, } impl<'a> Default for CircuitArgs<'a> { @@ -190,6 +258,7 @@ impl<'a> Default for CircuitArgs<'a> { r1cs_generation: false, witness_generation: false, field_maximum: None, + circuit_type: CircuitType::R1CS, configuration: None, } } @@ -220,6 +289,10 @@ impl<'a: 'b, 'b> CircuitBuilder<'a, 'b> { self.fbb_.push_slot_always::>(Circuit::VT_FIELD_MAXIMUM, field_maximum); } #[inline] + pub fn add_circuit_type(&mut self, circuit_type: CircuitType) { + self.fbb_.push_slot::(Circuit::VT_CIRCUIT_TYPE, circuit_type, CircuitType::R1CS); + } + #[inline] pub fn add_configuration(&mut self, configuration: flatbuffers::WIPOffset>>>) { self.fbb_.push_slot_always::>(Circuit::VT_CONFIGURATION, configuration); } diff --git a/zkinterface.fbs b/zkinterface.fbs index 99d908e..79f1b98 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -46,6 +46,9 @@ table Circuit { /// See `Variables.values` below. field_maximum :[ubyte]; + /// Whether this is an R1CS or arithmetic circuit. + circuit_type :CircuitType; + /// Optional: Any custom parameter that may influence the circuit construction. /// /// Example: function_name, if a gadget supports multiple function variants. @@ -54,6 +57,9 @@ table Circuit { configuration :[KeyValue]; } +// A circuit can be R1CS or arithmetic (fan-in 2 multiplications). +enum CircuitType : byte { R1CS = 0, FanIn2 = 1 } + /// R1CSConstraints represents constraints to be added to the constraint system. /// /// Multiple such messages are equivalent to the concatenation of `constraints` arrays. From 5b1531049df9c5f6129985916615f11e3b80eae6 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 14:34:46 +0200 Subject: [PATCH 05/17] json: support all message types. Organize "owned" structures. --- rust/Changelog | 7 +++ rust/src/bin/zkif_json.rs | 46 +++++++++++++--- rust/src/cpp_gadget.rs | 4 +- rust/src/examples.rs | 3 +- rust/src/lib.rs | 2 +- rust/src/{writing.rs => owned/circuit.rs} | 65 +++++------------------ rust/src/owned/constraints.rs | 36 +++++++++++++ rust/src/owned/mod.rs | 4 ++ rust/src/owned/variables.rs | 48 +++++++++++++++++ rust/src/owned/witness.rs | 17 ++++++ rust/src/reading.rs | 2 +- 11 files changed, 171 insertions(+), 63 deletions(-) create mode 100644 rust/Changelog rename rust/src/{writing.rs => owned/circuit.rs} (67%) create mode 100644 rust/src/owned/constraints.rs create mode 100644 rust/src/owned/mod.rs create mode 100644 rust/src/owned/variables.rs create mode 100644 rust/src/owned/witness.rs diff --git a/rust/Changelog b/rust/Changelog new file mode 100644 index 0000000..50f4004 --- /dev/null +++ b/rust/Changelog @@ -0,0 +1,7 @@ +# Version 1.1.0 (2020-06) + +- Added a tool to convert to JSON. +- Added "owned" versions of all message types. + +Breaking changes: +- Moved "writing" helpers to the "owned" modules. diff --git a/rust/src/bin/zkif_json.rs b/rust/src/bin/zkif_json.rs index e37d7ac..15417bf 100644 --- a/rust/src/bin/zkif_json.rs +++ b/rust/src/bin/zkif_json.rs @@ -7,14 +7,25 @@ use std::error::Error; use std::io::{stdin, Read}; use zkinterface::{ - reading::Messages, writing::CircuitOwned, zkinterface_generated::zkinterface::Message, + owned::constraints::ConstraintsOwned, reading::Messages, owned::witness::WitnessOwned, + owned::circuit::CircuitOwned, zkinterface_generated::zkinterface::Message, }; #[derive(Serialize, Deserialize, Debug)] -struct JsonCircuit { +struct CircuitJson { circuit: CircuitOwned, } +#[derive(Serialize, Deserialize, Debug)] +struct WitnessJson { + witness: WitnessOwned, +} + +#[derive(Serialize, Deserialize, Debug)] +struct ConstraintsJson { + constraints: ConstraintsOwned, +} + // Example: // // cargo run --bin zkif_json < example.zkif @@ -31,8 +42,33 @@ pub fn main() -> Result<(), Box> { for msg in messages.into_iter() { match msg.message_type() { Message::Circuit => { - let json = JsonCircuit { - circuit: CircuitOwned::from(msg.message_as_circuit().unwrap()), + let circuit_ref = msg.message_as_circuit().unwrap(); + let json = CircuitJson { + circuit: CircuitOwned::from(circuit_ref), + }; + + if pretty { + serde_json::to_writer_pretty(std::io::stdout(), &json)?; + } else { + serde_json::to_writer(std::io::stdout(), &json)?; + } + } + Message::Witness => { + let witness_ref = msg.message_as_witness().unwrap(); + let json = WitnessJson { + witness: WitnessOwned::from(witness_ref), + }; + + if pretty { + serde_json::to_writer_pretty(std::io::stdout(), &json)?; + } else { + serde_json::to_writer(std::io::stdout(), &json)?; + } + } + Message::R1CSConstraints => { + let constraints_ref = msg.message_as_r1csconstraints().unwrap(); + let json = ConstraintsJson { + constraints: ConstraintsOwned::from(constraints_ref), }; if pretty { @@ -41,8 +77,6 @@ pub fn main() -> Result<(), Box> { serde_json::to_writer(std::io::stdout(), &json)?; } } - Message::Witness => {} - Message::R1CSConstraints => {} Message::NONE => {} } print!("\n"); diff --git a/rust/src/cpp_gadget.rs b/rust/src/cpp_gadget.rs index 1d10b79..5dcd5b4 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" { @@ -77,7 +77,7 @@ pub fn call_gadget_wrapper(circuit: &CircuitOwned) -> Result>, } -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -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(), + r1cs_generation: circuit_ref.r1cs_generation(), + field_maximum: None, + } + } } impl CircuitOwned { @@ -69,6 +71,7 @@ impl CircuitOwned { } } + /// 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>, @@ -94,6 +97,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); @@ -101,46 +105,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..3611d19 --- /dev/null +++ b/rust/src/owned/constraints.rs @@ -0,0 +1,36 @@ +use owned::variables::VariablesOwned; +use serde::{Deserialize, Serialize}; +use zkinterface_generated::zkinterface::R1CSConstraints; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct ConstraintsOwned { + constraints: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct ConstraintOwned { + pub a: VariablesOwned, + pub b: VariablesOwned, + pub c: VariablesOwned, +} + +impl<'a> From> for ConstraintsOwned { + /// Convert from Flatbuffers references to owned structure. + fn from(constraints_ref: R1CSConstraints) -> ConstraintsOwned { + let mut owned = ConstraintsOwned { + 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(ConstraintOwned { + a: VariablesOwned::from(con_ref.linear_combination_a().unwrap()), + b: VariablesOwned::from(con_ref.linear_combination_b().unwrap()), + c: VariablesOwned::from(con_ref.linear_combination_c().unwrap()), + }); + } + + owned + } +} diff --git a/rust/src/owned/mod.rs b/rust/src/owned/mod.rs new file mode 100644 index 0000000..b02d9e6 --- /dev/null +++ b/rust/src/owned/mod.rs @@ -0,0 +1,4 @@ +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..53c102d --- /dev/null +++ b/rust/src/owned/variables.rs @@ -0,0 +1,48 @@ +use serde::{Deserialize, Serialize}; + +use flatbuffers::{FlatBufferBuilder, WIPOffset}; +use zkinterface_generated::zkinterface::{ + Variables, + VariablesArgs, +}; + +#[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: variables_ref.values().map(|bytes| + Vec::from(bytes)), + } + } +} + +impl VariablesOwned { + /// 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 1268d5b..26cff54 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -94,7 +94,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())?; } } From 5f0663d4bff47b5a7bec5cb8c803a50aac0ee67c Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 14:59:31 +0200 Subject: [PATCH 06/17] json: use message type as root field --- rust/src/bin/zkif_json.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/rust/src/bin/zkif_json.rs b/rust/src/bin/zkif_json.rs index 15417bf..4b18892 100644 --- a/rust/src/bin/zkif_json.rs +++ b/rust/src/bin/zkif_json.rs @@ -12,18 +12,21 @@ use zkinterface::{ }; #[derive(Serialize, Deserialize, Debug)] +#[allow(non_snake_case)] struct CircuitJson { - circuit: CircuitOwned, + Circuit: CircuitOwned, } #[derive(Serialize, Deserialize, Debug)] +#[allow(non_snake_case)] struct WitnessJson { - witness: WitnessOwned, + Witness: WitnessOwned, } #[derive(Serialize, Deserialize, Debug)] +#[allow(non_snake_case)] struct ConstraintsJson { - constraints: ConstraintsOwned, + R1CSConstraints: ConstraintsOwned, } // Example: @@ -44,7 +47,7 @@ pub fn main() -> Result<(), Box> { Message::Circuit => { let circuit_ref = msg.message_as_circuit().unwrap(); let json = CircuitJson { - circuit: CircuitOwned::from(circuit_ref), + Circuit: CircuitOwned::from(circuit_ref), }; if pretty { @@ -56,7 +59,7 @@ pub fn main() -> Result<(), Box> { Message::Witness => { let witness_ref = msg.message_as_witness().unwrap(); let json = WitnessJson { - witness: WitnessOwned::from(witness_ref), + Witness: WitnessOwned::from(witness_ref), }; if pretty { @@ -68,7 +71,7 @@ pub fn main() -> Result<(), Box> { Message::R1CSConstraints => { let constraints_ref = msg.message_as_r1csconstraints().unwrap(); let json = ConstraintsJson { - constraints: ConstraintsOwned::from(constraints_ref), + R1CSConstraints: ConstraintsOwned::from(constraints_ref), }; if pretty { From 8ac0668c2fac1e3300ea4b590214b855d9e4a0cf Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 15:37:17 +0200 Subject: [PATCH 07/17] arithmetic: validate that R1CS constraints are fan-in 2 --- rust/src/reading.rs | 35 +++++++++++++++++++++++++++++-- rust/src/zkinterface_generated.rs | 4 +++- zkinterface.fbs | 10 +++++---- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 7ba0a80..9868c89 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -302,8 +302,22 @@ impl Messages { pub fn validate_circuit_type(&self) -> Result<(), String> { for circuit in self.circuits() { - if circuit.circuit_type() != CircuitType::R1CS { - return Err("fan-in 2 not supported".to_string()); + if circuit.circuit_type() == CircuitType::FanIn2 { + for cons in self.iter_constraints() { + let n_a = cons.a.len(); + let n_b = cons.b.len(); + let n_c = cons.c.len(); + + let is_pure_multiplication = + n_a == 1 && n_b == 1 && n_c == 1; + + let is_pure_linear = + n_a == 0 && n_b == 0; + + if ! (is_pure_multiplication || is_pure_linear) { + return Err("The circuit should be fan-in 2 but constraints are not in the correct format.".to_string()); + } + } } } Ok(()) @@ -401,6 +415,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 5aa8e69..1196637 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -224,7 +224,9 @@ impl<'a> Circuit<'a> { pub fn field_maximum(&self) -> Option<&'a [u8]> { self._tab.get::>>(Circuit::VT_FIELD_MAXIMUM, None).map(|v| v.safe_slice()) } - /// Whether this is R1CS or arithmetic circuit. + /// Whether this is an R1CS or fan-in-2 arithmetic circuit. + /// A special case is a boolean circuit with XOR and AND gates, + /// then circuit_type == FanIn2 and field_maximum == 1. #[inline] pub fn circuit_type(&self) -> CircuitType { self._tab.get::(Circuit::VT_CIRCUIT_TYPE, Some(CircuitType::R1CS)).unwrap() diff --git a/zkinterface.fbs b/zkinterface.fbs index 79f1b98..3c3a24e 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -12,6 +12,9 @@ union Message { Witness, } +// A circuit can be R1CS or arithmetic (fan-in 2 multiplications). +enum CircuitType : byte { R1CS = 0, FanIn2 = 1 } + /// 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. @@ -46,7 +49,9 @@ table Circuit { /// See `Variables.values` below. field_maximum :[ubyte]; - /// Whether this is an R1CS or arithmetic circuit. + /// Whether this is an R1CS or fan-in-2 arithmetic circuit. + /// A special case is a boolean circuit with XOR and AND gates, + /// then circuit_type == FanIn2 and field_maximum == 1. circuit_type :CircuitType; /// Optional: Any custom parameter that may influence the circuit construction. @@ -57,9 +62,6 @@ table Circuit { configuration :[KeyValue]; } -// A circuit can be R1CS or arithmetic (fan-in 2 multiplications). -enum CircuitType : byte { R1CS = 0, FanIn2 = 1 } - /// R1CSConstraints represents constraints to be added to the constraint system. /// /// Multiple such messages are equivalent to the concatenation of `constraints` arrays. From cfddabc4f7840a0a2b498598c8c918f4df7b755c Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 19:43:03 +0200 Subject: [PATCH 08/17] json: collect all messages in a single JSON --- rust/src/bin/zkif_json.rs | 74 +++++---------------------------------- rust/src/owned/message.rs | 46 ++++++++++++++++++++++++ rust/src/owned/mod.rs | 1 + 3 files changed, 55 insertions(+), 66 deletions(-) create mode 100644 rust/src/owned/message.rs diff --git a/rust/src/bin/zkif_json.rs b/rust/src/bin/zkif_json.rs index 4b18892..7189abf 100644 --- a/rust/src/bin/zkif_json.rs +++ b/rust/src/bin/zkif_json.rs @@ -2,32 +2,10 @@ extern crate serde; extern crate serde_json; extern crate zkinterface; -use serde::{Deserialize, Serialize}; use std::error::Error; use std::io::{stdin, Read}; -use zkinterface::{ - owned::constraints::ConstraintsOwned, reading::Messages, owned::witness::WitnessOwned, - owned::circuit::CircuitOwned, zkinterface_generated::zkinterface::Message, -}; - -#[derive(Serialize, Deserialize, Debug)] -#[allow(non_snake_case)] -struct CircuitJson { - Circuit: CircuitOwned, -} - -#[derive(Serialize, Deserialize, Debug)] -#[allow(non_snake_case)] -struct WitnessJson { - Witness: WitnessOwned, -} - -#[derive(Serialize, Deserialize, Debug)] -#[allow(non_snake_case)] -struct ConstraintsJson { - R1CSConstraints: ConstraintsOwned, -} +use zkinterface::{owned::message::MessagesOwned, reading::Messages}; // Example: // @@ -36,54 +14,18 @@ struct ConstraintsJson { pub fn main() -> Result<(), Box> { let pretty = true; - let mut messages = Messages::new(1); + let mut messages_raw = Messages::new(1); let mut buffer = vec![]; stdin().read_to_end(&mut buffer)?; - messages.push_message(buffer)?; - - for msg in messages.into_iter() { - match msg.message_type() { - Message::Circuit => { - let circuit_ref = msg.message_as_circuit().unwrap(); - let json = CircuitJson { - Circuit: CircuitOwned::from(circuit_ref), - }; + messages_raw.push_message(buffer)?; - if pretty { - serde_json::to_writer_pretty(std::io::stdout(), &json)?; - } else { - serde_json::to_writer(std::io::stdout(), &json)?; - } - } - Message::Witness => { - let witness_ref = msg.message_as_witness().unwrap(); - let json = WitnessJson { - Witness: WitnessOwned::from(witness_ref), - }; + let messages = MessagesOwned::from(&messages_raw); - if pretty { - serde_json::to_writer_pretty(std::io::stdout(), &json)?; - } else { - serde_json::to_writer(std::io::stdout(), &json)?; - } - } - Message::R1CSConstraints => { - let constraints_ref = msg.message_as_r1csconstraints().unwrap(); - let json = ConstraintsJson { - R1CSConstraints: ConstraintsOwned::from(constraints_ref), - }; - - if pretty { - serde_json::to_writer_pretty(std::io::stdout(), &json)?; - } else { - serde_json::to_writer(std::io::stdout(), &json)?; - } - } - Message::NONE => {} - } - print!("\n"); + 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/owned/message.rs b/rust/src/owned/message.rs new file mode 100644 index 0000000..09e1fe7 --- /dev/null +++ b/rust/src/owned/message.rs @@ -0,0 +1,46 @@ +use serde::{Deserialize, Serialize}; + +use owned::circuit::CircuitOwned; +use owned::constraints::ConstraintsOwned; +use owned::witness::WitnessOwned; +use reading::Messages; +use zkinterface_generated::zkinterface::Message; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct MessagesOwned { + circuits: Vec, + constraints: 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![], + constraints: 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::R1CSConstraints => { + let constraints_ref = msg.message_as_r1csconstraints().unwrap(); + owned + .constraints + .push(ConstraintsOwned::from(constraints_ref)); + } + Message::Witness => { + let witness_ref = msg.message_as_witness().unwrap(); + owned.witnesses.push(WitnessOwned::from(witness_ref)); + } + Message::NONE => {} + } + } + owned + } +} diff --git a/rust/src/owned/mod.rs b/rust/src/owned/mod.rs index b02d9e6..4cb37a4 100644 --- a/rust/src/owned/mod.rs +++ b/rust/src/owned/mod.rs @@ -1,3 +1,4 @@ +pub mod message; pub mod circuit; pub mod constraints; pub mod witness; From f7a5c2e96dd25dcc67b3a61173c996501c9cefc0 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 19:54:31 +0200 Subject: [PATCH 09/17] json: match exactly the .fbs schema --- rust/src/owned/constraints.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rust/src/owned/constraints.rs b/rust/src/owned/constraints.rs index 3611d19..9f0aed9 100644 --- a/rust/src/owned/constraints.rs +++ b/rust/src/owned/constraints.rs @@ -4,14 +4,14 @@ use zkinterface_generated::zkinterface::R1CSConstraints; #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct ConstraintsOwned { - constraints: Vec, + constraints: Vec, } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -pub struct ConstraintOwned { - pub a: VariablesOwned, - pub b: VariablesOwned, - pub c: VariablesOwned, +pub struct BilinearConstraintOwned { + pub linear_combination_a: VariablesOwned, + pub linear_combination_b: VariablesOwned, + pub linear_combination_c: VariablesOwned, } impl<'a> From> for ConstraintsOwned { @@ -24,10 +24,10 @@ impl<'a> From> for ConstraintsOwned { let cons_ref = constraints_ref.constraints().unwrap(); for i in 0..cons_ref.len() { let con_ref = cons_ref.get(i); - owned.constraints.push(ConstraintOwned { - a: VariablesOwned::from(con_ref.linear_combination_a().unwrap()), - b: VariablesOwned::from(con_ref.linear_combination_b().unwrap()), - c: VariablesOwned::from(con_ref.linear_combination_c().unwrap()), + 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()), }); } From 70acb24be5891db1c871b204d00190c2083bb048 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 20:28:23 +0200 Subject: [PATCH 10/17] Rename message type to ConstraintSystem --- rust/src/examples.rs | 8 ++--- rust/src/owned/constraints.rs | 10 +++--- rust/src/owned/message.rs | 14 ++++---- rust/src/reading.rs | 6 ++-- rust/src/zkinterface_generated.rs | 56 +++++++++++++++---------------- zkinterface.fbs | 8 ++--- 6 files changed, 51 insertions(+), 51 deletions(-) diff --git a/rust/src/examples.rs b/rust/src/examples.rs index 47b4307..4ba8583 100644 --- a/rust/src/examples.rs +++ b/rust/src/examples.rs @@ -7,8 +7,8 @@ use zkinterface_generated::zkinterface::{ BilinearConstraint, BilinearConstraintArgs, Message, - R1CSConstraints, - R1CSConstraintsArgs, + ConstraintSystem, + ConstraintSystemArgs, Root, RootArgs, Variables, @@ -70,13 +70,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/owned/constraints.rs b/rust/src/owned/constraints.rs index 9f0aed9..f995967 100644 --- a/rust/src/owned/constraints.rs +++ b/rust/src/owned/constraints.rs @@ -1,9 +1,9 @@ use owned::variables::VariablesOwned; use serde::{Deserialize, Serialize}; -use zkinterface_generated::zkinterface::R1CSConstraints; +use zkinterface_generated::zkinterface::ConstraintSystem; #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -pub struct ConstraintsOwned { +pub struct ConstraintSystemOwned { constraints: Vec, } @@ -14,10 +14,10 @@ pub struct BilinearConstraintOwned { pub linear_combination_c: VariablesOwned, } -impl<'a> From> for ConstraintsOwned { +impl<'a> From> for ConstraintSystemOwned { /// Convert from Flatbuffers references to owned structure. - fn from(constraints_ref: R1CSConstraints) -> ConstraintsOwned { - let mut owned = ConstraintsOwned { + fn from(constraints_ref: ConstraintSystem) -> ConstraintSystemOwned { + let mut owned = ConstraintSystemOwned { constraints: vec![], }; diff --git a/rust/src/owned/message.rs b/rust/src/owned/message.rs index 09e1fe7..ec22abc 100644 --- a/rust/src/owned/message.rs +++ b/rust/src/owned/message.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use owned::circuit::CircuitOwned; -use owned::constraints::ConstraintsOwned; +use owned::constraints::ConstraintSystemOwned; use owned::witness::WitnessOwned; use reading::Messages; use zkinterface_generated::zkinterface::Message; @@ -9,7 +9,7 @@ use zkinterface_generated::zkinterface::Message; #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct MessagesOwned { circuits: Vec, - constraints: Vec, + constraint_systems: Vec, witnesses: Vec, } @@ -18,7 +18,7 @@ impl From<&Messages> for MessagesOwned { fn from(messages: &Messages) -> MessagesOwned { let mut owned = MessagesOwned { circuits: vec![], - constraints: vec![], + constraint_systems: vec![], witnesses: vec![], }; @@ -28,11 +28,11 @@ impl From<&Messages> for MessagesOwned { let circuit_ref = msg.message_as_circuit().unwrap(); owned.circuits.push(CircuitOwned::from(circuit_ref)); } - Message::R1CSConstraints => { - let constraints_ref = msg.message_as_r1csconstraints().unwrap(); + Message::ConstraintSystem => { + let constraints_ref = msg.message_as_constraint_system().unwrap(); owned - .constraints - .push(ConstraintsOwned::from(constraints_ref)); + .constraint_systems + .push(ConstraintSystemOwned::from(constraints_ref)); } Message::Witness => { let witness_ref = msg.message_as_witness().unwrap(); diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 9868c89..1365176 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -81,7 +81,7 @@ impl fmt::Debug for Messages { match root.message_type() { Circuit => has_circuit = true, Witness => has_witness = true, - R1CSConstraints => has_constraints = true, + ConstraintSystem => has_constraints = true, NONE => {} } } @@ -111,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)?; } @@ -352,7 +352,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, }; diff --git a/rust/src/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index 1196637..e99625c 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -17,7 +17,7 @@ pub mod zkinterface { pub enum Message { NONE = 0, Circuit = 1, - R1CSConstraints = 2, + ConstraintSystem = 2, Witness = 3, } @@ -60,7 +60,7 @@ impl flatbuffers::Push for Message { pub const ENUM_VALUES_MESSAGE:[Message; 4] = [ Message::NONE, Message::Circuit, - Message::R1CSConstraints, + Message::ConstraintSystem, Message::Witness ]; @@ -68,7 +68,7 @@ pub const ENUM_VALUES_MESSAGE:[Message; 4] = [ pub const ENUM_NAMES_MESSAGE:[&'static str; 4] = [ "NONE", "Circuit", - "R1CSConstraints", + "ConstraintSystem", "Witness" ]; @@ -206,7 +206,7 @@ impl<'a> Circuit<'a> { self._tab.get::(Circuit::VT_FREE_VARIABLE_ID, Some(0)).unwrap() } /// Whether a constraint system is being generated. - /// Provide constraints in R1CSConstraints messages. + /// Provide constraints in ConstraintSystem messages. #[inline] pub fn r1cs_generation(&self) -> bool { self._tab.get::(Circuit::VT_R1CS_GENERATION, Some(false)).unwrap() @@ -313,18 +313,18 @@ impl<'a: 'b, 'b> CircuitBuilder<'a, 'b> { } } -pub enum R1CSConstraintsOffset {} +pub enum ConstraintSystemOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -/// 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. -pub struct R1CSConstraints<'a> { +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 { @@ -333,18 +333,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() @@ -355,7 +355,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. /// @@ -363,46 +363,46 @@ 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()) } @@ -869,9 +869,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 } diff --git a/zkinterface.fbs b/zkinterface.fbs index 3c3a24e..413abc0 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -8,7 +8,7 @@ namespace zkinterface; union Message { Circuit, - R1CSConstraints, + ConstraintSystem, Witness, } @@ -37,7 +37,7 @@ table Circuit { // but optional in the response from a gadget. /// Whether a constraint system is being generated. - /// Provide constraints in R1CSConstraints messages. + /// Provide constraints in ConstraintSystem messages. r1cs_generation :bool; /// Whether a witness is being generated. @@ -62,10 +62,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. From 8382e9d917a398053939b68a071e941ab4b00836 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 21:44:35 +0200 Subject: [PATCH 11/17] arithmetic: move constraint_type on ConstraintSystem type --- rust/src/examples.rs | 16 +------- rust/src/owned/circuit.rs | 7 ---- rust/src/owned/constraints.rs | 25 +++++++++++- rust/src/reading.rs | 45 ++++++++++++--------- rust/src/zkinterface_generated.rs | 66 +++++++++++++++---------------- zkinterface.fbs | 16 ++++---- 6 files changed, 92 insertions(+), 83 deletions(-) diff --git a/rust/src/examples.rs b/rust/src/examples.rs index 4ba8583..8429f23 100644 --- a/rust/src/examples.rs +++ b/rust/src/examples.rs @@ -3,19 +3,7 @@ use std::io; use std::mem::size_of; use owned::circuit::CircuitOwned; use owned::variables::VariablesOwned; -use zkinterface_generated::zkinterface::{ - BilinearConstraint, - BilinearConstraintArgs, - Message, - ConstraintSystem, - ConstraintSystemArgs, - Root, - RootArgs, - Variables, - VariablesArgs, - Witness, - WitnessArgs, -}; +use zkinterface_generated::zkinterface::{BilinearConstraint, BilinearConstraintArgs, Message, ConstraintSystem, ConstraintSystemArgs, Root, RootArgs, Variables, VariablesArgs, Witness, WitnessArgs, ConstraintType}; pub fn example_circuit() -> CircuitOwned { @@ -32,7 +20,6 @@ pub fn example_circuit_inputs(x: u32, y: u32, zz: u32) -> CircuitOwned { free_variable_id: 6, r1cs_generation: true, field_maximum: None, - circuit_type: "R1CS".to_string(), } } @@ -72,6 +59,7 @@ pub fn write_example_constraints(mut writer: W) -> io::Result<()> let constraints_built = builder.create_vector(&constraints_built); let r1cs = ConstraintSystem::create(&mut builder, &ConstraintSystemArgs { constraints: Some(constraints_built), + constraint_type: ConstraintType::R1CS, info: None, }); diff --git a/rust/src/owned/circuit.rs b/rust/src/owned/circuit.rs index cd89800..86db7e8 100644 --- a/rust/src/owned/circuit.rs +++ b/rust/src/owned/circuit.rs @@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize}; use zkinterface_generated::zkinterface::{ Circuit, CircuitArgs, - CircuitType, Message, Root, RootArgs, @@ -25,8 +24,6 @@ pub struct CircuitOwned { pub field_maximum: Option>, - pub circuit_type: String, - //pub configuration: Option>, } @@ -38,7 +35,6 @@ impl<'a> From> for CircuitOwned { free_variable_id: circuit_ref.free_variable_id(), r1cs_generation: circuit_ref.r1cs_generation(), field_maximum: None, - circuit_type: "R1CS".to_string(), } } } @@ -56,7 +52,6 @@ impl CircuitOwned { free_variable_id: first_local_id, r1cs_generation: false, field_maximum: None, - circuit_type: "R1CS".to_string(), } } @@ -73,7 +68,6 @@ impl CircuitOwned { free_variable_id: first_local_id + num_locals, r1cs_generation: false, field_maximum: None, - circuit_type: "R1CS".to_string(), } } @@ -94,7 +88,6 @@ impl CircuitOwned { r1cs_generation: self.r1cs_generation, witness_generation: self.connections.values.is_some(), field_maximum, - circuit_type: CircuitType::R1CS, configuration: None, }); diff --git a/rust/src/owned/constraints.rs b/rust/src/owned/constraints.rs index f995967..6948157 100644 --- a/rust/src/owned/constraints.rs +++ b/rust/src/owned/constraints.rs @@ -1,10 +1,30 @@ use owned::variables::VariablesOwned; use serde::{Deserialize, Serialize}; -use zkinterface_generated::zkinterface::ConstraintSystem; +use zkinterface_generated::zkinterface::{ConstraintSystem, ConstraintType}; +use owned::constraints::ConstraintTypeOwned::R1CS; + +#[allow(non_camel_case_types)] +#[repr(i8)] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub enum ConstraintTypeOwned { + R1CS = 0, + FanIn2 = 1, +} + +impl From for ConstraintTypeOwned { + fn from(ct: ConstraintType) -> Self { + match ct { + ConstraintType::R1CS => ConstraintTypeOwned::R1CS, + ConstraintType::FanIn2 => ConstraintTypeOwned::FanIn2, + } + } +} #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct ConstraintSystemOwned { - constraints: Vec, + pub constraints: Vec, + + pub constraint_type: ConstraintTypeOwned, } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] @@ -19,6 +39,7 @@ impl<'a> From> for ConstraintSystemOwned { fn from(constraints_ref: ConstraintSystem) -> ConstraintSystemOwned { let mut owned = ConstraintSystemOwned { constraints: vec![], + constraint_type: constraints_ref.constraint_type().into(), }; let cons_ref = constraints_ref.constraints().unwrap(); diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 1365176..b073e75 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -9,7 +9,7 @@ use std::path::Path; use zkinterface_generated::zkinterface::{ BilinearConstraint, Circuit, - CircuitType, + ConstraintType, get_size_prefixed_root_as_root, Root, Variables, @@ -300,25 +300,32 @@ impl Messages { } } - pub fn validate_circuit_type(&self) -> Result<(), String> { - for circuit in self.circuits() { - if circuit.circuit_type() == CircuitType::FanIn2 { - for cons in self.iter_constraints() { - let n_a = cons.a.len(); - let n_b = cons.b.len(); - let n_c = cons.c.len(); - - let is_pure_multiplication = - n_a == 1 && n_b == 1 && n_c == 1; - - let is_pure_linear = - n_a == 0 && n_b == 0; - - if ! (is_pure_multiplication || is_pure_linear) { - return Err("The circuit should be fan-in 2 but constraints are not in the correct format.".to_string()); + pub fn validate_constraint_type(&self) -> Result<(), String> { + for message in self.into_iter() { + match message.message_as_constraint_system() { + None => continue, + Some(cs) => { + if cs.constraint_type() == ConstraintType::FanIn2 { + let constraints = cs.constraints().unwrap(); + for i in 0..constraints.len() { + let constraint = constraints.get(i); + let n_a = constraint.linear_combination_a().unwrap().variable_ids().unwrap().len(); + let n_b = constraint.linear_combination_b().unwrap().variable_ids().unwrap().len(); + let n_c = constraint.linear_combination_c().unwrap().variable_ids().unwrap().len(); + + let is_pure_multiplication = + n_a == 1 && n_b == 1 && n_c == 1; + + let is_pure_linear = + n_a == 0 && n_b == 0; + + if ! (is_pure_multiplication || is_pure_linear) { + return Err("The circuit should be fan-in 2 but constraints are not in the correct format.".to_string()); + } + } } - } - } + }, + }; } Ok(()) } diff --git a/rust/src/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index e99625c..faba796 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -81,16 +81,16 @@ pub struct MessageUnionTableOffset {} #[allow(non_camel_case_types)] #[repr(i8)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum CircuitType { +pub enum ConstraintType { R1CS = 0, FanIn2 = 1, } -pub const ENUM_MIN_CIRCUIT_TYPE: i8 = 0; -pub const ENUM_MAX_CIRCUIT_TYPE: i8 = 1; +pub const ENUM_MIN_CONSTRAINT_TYPE: i8 = 0; +pub const ENUM_MAX_CONSTRAINT_TYPE: i8 = 1; -impl<'a> flatbuffers::Follow<'a> for CircuitType { +impl<'a> flatbuffers::Follow<'a> for ConstraintType { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { @@ -98,44 +98,44 @@ impl<'a> flatbuffers::Follow<'a> for CircuitType { } } -impl flatbuffers::EndianScalar for CircuitType { +impl flatbuffers::EndianScalar for ConstraintType { #[inline] fn to_little_endian(self) -> Self { let n = i8::to_le(self as i8); - let p = &n as *const i8 as *const CircuitType; + let p = &n as *const i8 as *const ConstraintType; unsafe { *p } } #[inline] fn from_little_endian(self) -> Self { let n = i8::from_le(self as i8); - let p = &n as *const i8 as *const CircuitType; + let p = &n as *const i8 as *const ConstraintType; unsafe { *p } } } -impl flatbuffers::Push for CircuitType { - type Output = CircuitType; +impl flatbuffers::Push for ConstraintType { + type Output = ConstraintType; #[inline] fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); + flatbuffers::emplace_scalar::(dst, *self); } } #[allow(non_camel_case_types)] -pub const ENUM_VALUES_CIRCUIT_TYPE:[CircuitType; 2] = [ - CircuitType::R1CS, - CircuitType::FanIn2 +pub const ENUM_VALUES_CONSTRAINT_TYPE:[ConstraintType; 2] = [ + ConstraintType::R1CS, + ConstraintType::FanIn2 ]; #[allow(non_camel_case_types)] -pub const ENUM_NAMES_CIRCUIT_TYPE:[&'static str; 2] = [ +pub const ENUM_NAMES_CONSTRAINT_TYPE:[&'static str; 2] = [ "R1CS", "FanIn2" ]; -pub fn enum_name_circuit_type(e: CircuitType) -> &'static str { +pub fn enum_name_constraint_type(e: ConstraintType) -> &'static str { let index = e as i8; - ENUM_NAMES_CIRCUIT_TYPE[index as usize] + ENUM_NAMES_CONSTRAINT_TYPE[index as usize] } pub enum CircuitOffset {} @@ -174,7 +174,6 @@ 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_circuit_type(args.circuit_type); builder.add_witness_generation(args.witness_generation); builder.add_r1cs_generation(args.r1cs_generation); builder.finish() @@ -185,8 +184,7 @@ impl<'a> Circuit<'a> { 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_CIRCUIT_TYPE: flatbuffers::VOffsetT = 14; - pub const VT_CONFIGURATION: flatbuffers::VOffsetT = 16; + pub const VT_CONFIGURATION: flatbuffers::VOffsetT = 14; /// Variables to use as connections to the sub-circuit. /// @@ -224,13 +222,6 @@ impl<'a> Circuit<'a> { pub fn field_maximum(&self) -> Option<&'a [u8]> { self._tab.get::>>(Circuit::VT_FIELD_MAXIMUM, None).map(|v| v.safe_slice()) } - /// Whether this is an R1CS or fan-in-2 arithmetic circuit. - /// A special case is a boolean circuit with XOR and AND gates, - /// then circuit_type == FanIn2 and field_maximum == 1. - #[inline] - pub fn circuit_type(&self) -> CircuitType { - self._tab.get::(Circuit::VT_CIRCUIT_TYPE, Some(CircuitType::R1CS)).unwrap() - } /// Optional: Any custom parameter that may influence the circuit construction. /// /// Example: function_name, if a gadget supports multiple function variants. @@ -248,7 +239,6 @@ pub struct CircuitArgs<'a> { pub r1cs_generation: bool, pub witness_generation: bool, pub field_maximum: Option>>, - pub circuit_type: CircuitType, pub configuration: Option>>>>, } impl<'a> Default for CircuitArgs<'a> { @@ -260,7 +250,6 @@ impl<'a> Default for CircuitArgs<'a> { r1cs_generation: false, witness_generation: false, field_maximum: None, - circuit_type: CircuitType::R1CS, configuration: None, } } @@ -291,10 +280,6 @@ impl<'a: 'b, 'b> CircuitBuilder<'a, 'b> { self.fbb_.push_slot_always::>(Circuit::VT_FIELD_MAXIMUM, field_maximum); } #[inline] - pub fn add_circuit_type(&mut self, circuit_type: CircuitType) { - self.fbb_.push_slot::(Circuit::VT_CIRCUIT_TYPE, circuit_type, CircuitType::R1CS); - } - #[inline] pub fn add_configuration(&mut self, configuration: flatbuffers::WIPOffset>>>) { self.fbb_.push_slot_always::>(Circuit::VT_CONFIGURATION, configuration); } @@ -347,16 +332,25 @@ impl<'a> ConstraintSystem<'a> { 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.add_constraint_type(args.constraint_type); builder.finish() } pub const VT_CONSTRAINTS: flatbuffers::VOffsetT = 4; - pub const VT_INFO: flatbuffers::VOffsetT = 6; + pub const VT_CONSTRAINT_TYPE: flatbuffers::VOffsetT = 6; + pub const VT_INFO: flatbuffers::VOffsetT = 8; #[inline] pub fn constraints(&self) -> Option>>> { self._tab.get::>>>>(ConstraintSystem::VT_CONSTRAINTS, None) } + /// Whether this is an R1CS or fan-in-2 arithmetic circuit. + /// A special case is a boolean circuit with XOR and AND gates, + /// then constraint_type == FanIn2 and circuit.field_maximum == 1. + #[inline] + pub fn constraint_type(&self) -> ConstraintType { + self._tab.get::(ConstraintSystem::VT_CONSTRAINT_TYPE, Some(ConstraintType::R1CS)).unwrap() + } /// Optional: Any complementary info that may be useful. /// /// Example: human-readable descriptions. @@ -369,6 +363,7 @@ impl<'a> ConstraintSystem<'a> { pub struct ConstraintSystemArgs<'a> { pub constraints: Option>>>>, + pub constraint_type: ConstraintType, pub info: Option>>>>, } impl<'a> Default for ConstraintSystemArgs<'a> { @@ -376,6 +371,7 @@ impl<'a> Default for ConstraintSystemArgs<'a> { fn default() -> Self { ConstraintSystemArgs { constraints: None, + constraint_type: ConstraintType::R1CS, info: None, } } @@ -390,6 +386,10 @@ impl<'a: 'b, 'b> ConstraintSystemBuilder<'a, 'b> { self.fbb_.push_slot_always::>(ConstraintSystem::VT_CONSTRAINTS, constraints); } #[inline] + pub fn add_constraint_type(&mut self, constraint_type: ConstraintType) { + self.fbb_.push_slot::(ConstraintSystem::VT_CONSTRAINT_TYPE, constraint_type, ConstraintType::R1CS); + } + #[inline] pub fn add_info(&mut self, info: flatbuffers::WIPOffset>>>) { self.fbb_.push_slot_always::>(ConstraintSystem::VT_INFO, info); } diff --git a/zkinterface.fbs b/zkinterface.fbs index 413abc0..b2ed108 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -12,9 +12,6 @@ union Message { Witness, } -// A circuit can be R1CS or arithmetic (fan-in 2 multiplications). -enum CircuitType : byte { R1CS = 0, FanIn2 = 1 } - /// 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. @@ -49,11 +46,6 @@ table Circuit { /// See `Variables.values` below. field_maximum :[ubyte]; - /// Whether this is an R1CS or fan-in-2 arithmetic circuit. - /// A special case is a boolean circuit with XOR and AND gates, - /// then circuit_type == FanIn2 and field_maximum == 1. - circuit_type :CircuitType; - /// Optional: Any custom parameter that may influence the circuit construction. /// /// Example: function_name, if a gadget supports multiple function variants. @@ -62,12 +54,20 @@ table Circuit { configuration :[KeyValue]; } +// A circuit can be R1CS or arithmetic (fan-in 2 multiplications). +enum ConstraintType : byte { R1CS = 0, FanIn2 = 1 } + /// ConstraintSystem represents constraints to be added to the constraint system. /// /// Multiple such messages are equivalent to the concatenation of `constraints` arrays. table ConstraintSystem { constraints :[BilinearConstraint]; + /// Whether this is an R1CS or fan-in-2 arithmetic circuit. + /// A special case is a boolean circuit with XOR and AND gates, + /// then constraint_type == FanIn2 and circuit.field_maximum == 1. + constraint_type :ConstraintType; + /// Optional: Any complementary info that may be useful. /// /// Example: human-readable descriptions. From 113938eb120e51c0df986cfb5ab0cb88958bc63c Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 21:51:46 +0200 Subject: [PATCH 12/17] Rename constraint type to arithmetic --- rust/src/lib.rs | 1 + rust/src/owned/constraints.rs | 45 ++++++++++++++++++------------- rust/src/reading.rs | 2 +- rust/src/zkinterface_generated.rs | 14 +++++++--- zkinterface.fbs | 4 +-- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index cebf517..3fe2310 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,6 +1,7 @@ pub extern crate flatbuffers; pub extern crate serde; +#[allow(unused_imports)] pub mod zkinterface_generated; pub mod reading; diff --git a/rust/src/owned/constraints.rs b/rust/src/owned/constraints.rs index 6948157..1d5ec0d 100644 --- a/rust/src/owned/constraints.rs +++ b/rust/src/owned/constraints.rs @@ -1,24 +1,6 @@ use owned::variables::VariablesOwned; use serde::{Deserialize, Serialize}; use zkinterface_generated::zkinterface::{ConstraintSystem, ConstraintType}; -use owned::constraints::ConstraintTypeOwned::R1CS; - -#[allow(non_camel_case_types)] -#[repr(i8)] -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -pub enum ConstraintTypeOwned { - R1CS = 0, - FanIn2 = 1, -} - -impl From for ConstraintTypeOwned { - fn from(ct: ConstraintType) -> Self { - match ct { - ConstraintType::R1CS => ConstraintTypeOwned::R1CS, - ConstraintType::FanIn2 => ConstraintTypeOwned::FanIn2, - } - } -} #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct ConstraintSystemOwned { @@ -55,3 +37,30 @@ impl<'a> From> for ConstraintSystemOwned { owned } } + + +#[allow(non_camel_case_types)] +#[repr(i8)] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub enum ConstraintTypeOwned { + R1CS = 0, + arithmetic = 1, +} + +impl From for ConstraintTypeOwned { + fn from(ct: ConstraintType) -> Self { + match ct { + ConstraintType::R1CS => ConstraintTypeOwned::R1CS, + ConstraintType::arithmetic => ConstraintTypeOwned::arithmetic, + } + } +} + +impl Into for ConstraintTypeOwned { + fn into(self) -> ConstraintType { + match self { + ConstraintTypeOwned::R1CS => ConstraintType::R1CS, + ConstraintTypeOwned::arithmetic => ConstraintType::arithmetic, + } + } +} \ No newline at end of file diff --git a/rust/src/reading.rs b/rust/src/reading.rs index b073e75..471d191 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -305,7 +305,7 @@ impl Messages { match message.message_as_constraint_system() { None => continue, Some(cs) => { - if cs.constraint_type() == ConstraintType::FanIn2 { + if cs.constraint_type() == ConstraintType::arithmetic { let constraints = cs.constraints().unwrap(); for i in 0..constraints.len() { let constraint = constraints.get(i); diff --git a/rust/src/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index faba796..6e76fc8 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -1,6 +1,12 @@ // 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 { @@ -83,7 +89,7 @@ pub struct MessageUnionTableOffset {} #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum ConstraintType { R1CS = 0, - FanIn2 = 1, + arithmetic = 1, } @@ -124,13 +130,13 @@ impl flatbuffers::Push for ConstraintType { #[allow(non_camel_case_types)] pub const ENUM_VALUES_CONSTRAINT_TYPE:[ConstraintType; 2] = [ ConstraintType::R1CS, - ConstraintType::FanIn2 + ConstraintType::arithmetic ]; #[allow(non_camel_case_types)] pub const ENUM_NAMES_CONSTRAINT_TYPE:[&'static str; 2] = [ "R1CS", - "FanIn2" + "arithmetic" ]; pub fn enum_name_constraint_type(e: ConstraintType) -> &'static str { @@ -346,7 +352,7 @@ impl<'a> ConstraintSystem<'a> { } /// Whether this is an R1CS or fan-in-2 arithmetic circuit. /// A special case is a boolean circuit with XOR and AND gates, - /// then constraint_type == FanIn2 and circuit.field_maximum == 1. + /// then constraint_type == arithmetic and circuit.field_maximum == 1. #[inline] pub fn constraint_type(&self) -> ConstraintType { self._tab.get::(ConstraintSystem::VT_CONSTRAINT_TYPE, Some(ConstraintType::R1CS)).unwrap() diff --git a/zkinterface.fbs b/zkinterface.fbs index b2ed108..f22bf99 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -55,7 +55,7 @@ table Circuit { } // A circuit can be R1CS or arithmetic (fan-in 2 multiplications). -enum ConstraintType : byte { R1CS = 0, FanIn2 = 1 } +enum ConstraintType : byte { R1CS = 0, arithmetic = 1 } /// ConstraintSystem represents constraints to be added to the constraint system. /// @@ -65,7 +65,7 @@ table ConstraintSystem { /// Whether this is an R1CS or fan-in-2 arithmetic circuit. /// A special case is a boolean circuit with XOR and AND gates, - /// then constraint_type == FanIn2 and circuit.field_maximum == 1. + /// then constraint_type == arithmetic and circuit.field_maximum == 1. constraint_type :ConstraintType; /// Optional: Any complementary info that may be useful. From b5494b2b80bf379f8becd6bf8075bbe49bf45946 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 22:23:51 +0200 Subject: [PATCH 13/17] Convenience VariablesOwned.get_variables() --- rust/src/owned/variables.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/rust/src/owned/variables.rs b/rust/src/owned/variables.rs index 53c102d..cfc1ef5 100644 --- a/rust/src/owned/variables.rs +++ b/rust/src/owned/variables.rs @@ -5,6 +5,7 @@ use zkinterface_generated::zkinterface::{ Variables, VariablesArgs, }; +use reading::Variable; #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct VariablesOwned { @@ -21,13 +22,34 @@ impl<'a> From> for VariablesOwned { Some(var_ids) => Vec::from(var_ids.safe_slice()), None => vec![], }, - values: variables_ref.values().map(|bytes| - Vec::from(bytes)), + 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, From 0631f74448645b646f19b07cf89b2567b162257d Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 23:41:00 +0200 Subject: [PATCH 14/17] command messages --- rust/Changelog | 7 -- rust/Changelog.md | 12 +++ rust/src/cpp_gadget.rs | 6 +- rust/src/examples.rs | 1 - rust/src/owned/circuit.rs | 8 -- rust/src/owned/message.rs | 1 + rust/src/reading.rs | 37 +++---- rust/src/zkinterface_generated.rs | 173 +++++++++++++++++++++++------- zkinterface.fbs | 38 ++++--- 9 files changed, 198 insertions(+), 85 deletions(-) delete mode 100644 rust/Changelog create mode 100644 rust/Changelog.md diff --git a/rust/Changelog b/rust/Changelog deleted file mode 100644 index 50f4004..0000000 --- a/rust/Changelog +++ /dev/null @@ -1,7 +0,0 @@ -# Version 1.1.0 (2020-06) - -- Added a tool to convert to JSON. -- Added "owned" versions of all message types. - -Breaking changes: -- Moved "writing" helpers to the "owned" modules. diff --git a/rust/Changelog.md b/rust/Changelog.md new file mode 100644 index 0000000..0bafb56 --- /dev/null +++ b/rust/Changelog.md @@ -0,0 +1,12 @@ +# Version 1.1.0 (2020-06) + +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 constraint_type to support for both R1CS and arithmetic circuits. + +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/rust/src/cpp_gadget.rs b/rust/src/cpp_gadget.rs index 5dcd5b4..37dff34 100644 --- a/rust/src/cpp_gadget.rs +++ b/rust/src/cpp_gadget.rs @@ -77,7 +77,7 @@ pub fn call_gadget_wrapper(circuit: &CircuitOwned) -> Result CircuitOwned { values: Some(serialize_small(&[x, y, zz])), }, free_variable_id: 6, - r1cs_generation: true, field_maximum: None, } } diff --git a/rust/src/owned/circuit.rs b/rust/src/owned/circuit.rs index 86db7e8..118d025 100644 --- a/rust/src/owned/circuit.rs +++ b/rust/src/owned/circuit.rs @@ -19,9 +19,6 @@ pub struct CircuitOwned { 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>, @@ -33,7 +30,6 @@ impl<'a> From> for CircuitOwned { CircuitOwned { connections: VariablesOwned::from(circuit_ref.connections().unwrap()), free_variable_id: circuit_ref.free_variable_id(), - r1cs_generation: circuit_ref.r1cs_generation(), field_maximum: None, } } @@ -50,7 +46,6 @@ impl CircuitOwned { values: None, }, free_variable_id: first_local_id, - r1cs_generation: false, field_maximum: None, } } @@ -66,7 +61,6 @@ impl CircuitOwned { values: None, }, free_variable_id: first_local_id + num_locals, - r1cs_generation: false, field_maximum: None, } } @@ -85,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, }); diff --git a/rust/src/owned/message.rs b/rust/src/owned/message.rs index ec22abc..db39b5e 100644 --- a/rust/src/owned/message.rs +++ b/rust/src/owned/message.rs @@ -38,6 +38,7 @@ impl From<&Messages> for MessagesOwned { let witness_ref = msg.message_as_witness().unwrap(); owned.witnesses.push(WitnessOwned::from(witness_ref)); } + Message::Command => {} Message::NONE => {} } } diff --git a/rust/src/reading.rs b/rust/src/reading.rs index 471d191..77358f0 100644 --- a/rust/src/reading.rs +++ b/rust/src/reading.rs @@ -19,18 +19,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)) @@ -82,6 +82,7 @@ impl fmt::Debug for Messages { Circuit => has_circuit = true, Witness => has_witness = true, ConstraintSystem => has_constraints = true, + Command => {} NONE => {} } } @@ -319,12 +320,12 @@ impl Messages { let is_pure_linear = n_a == 0 && n_b == 0; - if ! (is_pure_multiplication || is_pure_linear) { + if !(is_pure_multiplication || is_pure_linear) { return Err("The circuit should be fan-in 2 but constraints are not in the correct format.".to_string()); } } } - }, + } }; } Ok(()) @@ -425,19 +426,19 @@ impl<'a> Variable<'a> { pub fn is_constant_one(&self) -> bool { if self.id != 0 { - return false + return false; } if self.value.len() > 0 { if self.value[0] != 1 { - return false + return false; } for v in self.value[1..].iter() { if *v != 0 { - return false + return false; } } } - return true + return true; } } diff --git a/rust/src/zkinterface_generated.rs b/rust/src/zkinterface_generated.rs index 6e76fc8..ac1511b 100644 --- a/rust/src/zkinterface_generated.rs +++ b/rust/src/zkinterface_generated.rs @@ -25,11 +25,12 @@ pub enum Message { Circuit = 1, ConstraintSystem = 2, Witness = 3, + Command = 4, } pub const ENUM_MIN_MESSAGE: u8 = 0; -pub const ENUM_MAX_MESSAGE: u8 = 3; +pub const ENUM_MAX_MESSAGE: u8 = 4; impl<'a> flatbuffers::Follow<'a> for Message { type Inner = Self; @@ -63,19 +64,21 @@ impl flatbuffers::Push for Message { } #[allow(non_camel_case_types)] -pub const ENUM_VALUES_MESSAGE:[Message; 4] = [ +pub const ENUM_VALUES_MESSAGE:[Message; 5] = [ Message::NONE, Message::Circuit, Message::ConstraintSystem, - Message::Witness + Message::Witness, + Message::Command ]; #[allow(non_camel_case_types)] -pub const ENUM_NAMES_MESSAGE:[&'static str; 4] = [ +pub const ENUM_NAMES_MESSAGE:[&'static str; 5] = [ "NONE", "Circuit", "ConstraintSystem", - "Witness" + "Witness", + "Command" ]; pub fn enum_name_message(e: Message) -> &'static str { @@ -180,17 +183,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. /// @@ -198,7 +197,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) @@ -209,18 +208,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 ConstraintSystem 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. @@ -242,8 +229,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>>>>, } @@ -253,8 +238,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, } @@ -274,14 +257,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); } @@ -495,6 +470,122 @@ 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)] @@ -893,6 +984,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 f22bf99..e33289c 100644 --- a/zkinterface.fbs +++ b/zkinterface.fbs @@ -10,6 +10,7 @@ union Message { Circuit, 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 ConstraintSystem 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. @@ -84,6 +74,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 ==== From 2dd6ead091dd1b682df4c7417eec8f3a429e19c7 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 2 Jun 2020 23:52:30 +0200 Subject: [PATCH 15/17] Add examples --- README.md | 1 + examples/example.json | 136 ++++++++++++++++++++++++++++++++++++++++++ examples/example.zkif | Bin 0 -> 648 bytes rust/Changelog.md | 3 +- 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 examples/example.json create mode 100644 examples/example.zkif diff --git a/README.md b/README.md index f165391..f62c4bd 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,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..f3b1f25 --- /dev/null +++ b/examples/example.json @@ -0,0 +1,136 @@ +{ + "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 + ] + } + } + ], + "constraint_type": "R1CS" + } + ], + "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 0000000000000000000000000000000000000000..ba38a4e8b5c0a6e191f6748b6ffcd3ee96cd3e08 GIT binary patch literal 648 zcmah{$qm9V5ZoLs11Z#Y)Z|GoFpt zzKV#)qBY`Vfp4Q};bP58ooXB8bHyUp>RZ%mEb^-q?^0aA(@J#_XLtuN^j(enmegUV z2CD2w?Wl`AUCP%XgcIU@%AfBLs7Ee)+TuQ1Kf?Jh1qk%y(`M?#Lw8Ci!EytBL}Gmp z8NTUVGPup7`-5xW7PI2CowO*7&;7{kw{yKRIOjv7rrqPzxs7)QSKq_eT~)t#rJO;N QZ-)QEH?_oKkEywT0O6Y|6#xJL literal 0 HcmV?d00001 diff --git a/rust/Changelog.md b/rust/Changelog.md index 0bafb56..46096c9 100644 --- a/rust/Changelog.md +++ b/rust/Changelog.md @@ -1,10 +1,11 @@ -# Version 1.1.0 (2020-06) +# Version 1.1.0, 2020-06, Arithmetic circuits 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 constraint_type to support for both R1CS and arithmetic circuits. +- Added an example file in binary and JSON. Rust: - *(breaking)* Moved "writing" helpers to the "owned" modules. From 2636ac8a9b7de5a15976c1f2a0be93afa4ad61f3 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 16 Jun 2020 13:59:15 +0200 Subject: [PATCH 16/17] Tool to print statistics of a circuit --- rust/src/bin/example.rs | 2 +- rust/src/bin/print.rs | 2 +- rust/src/bin/stats.rs | 71 +++++++++++++++++++++++++++++++++++++++ rust/src/bin/zkif_json.rs | 2 +- 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 rust/src/bin/stats.rs diff --git a/rust/src/bin/example.rs b/rust/src/bin/example.rs index 4d6f394..b4f47ba 100644 --- a/rust/src/bin/example.rs +++ b/rust/src/bin/example.rs @@ -7,7 +7,7 @@ use std::error::Error; // Example: // -// cargo run --bin example > example.zkif +// cargo run --bin example > ../examples/example.zkif // pub fn main() -> Result<(), Box> { diff --git a/rust/src/bin/print.rs b/rust/src/bin/print.rs index 2a3bacb..3749f31 100644 --- a/rust/src/bin/print.rs +++ b/rust/src/bin/print.rs @@ -7,7 +7,7 @@ use std::error::Error; // Example: // -// cargo run --bin print < example.zkif +// cargo run --bin print < ../examples/example.zkif // pub fn main() -> Result<(), Box> { let mut messages = Messages::new(1); 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 index 7189abf..eb67317 100644 --- a/rust/src/bin/zkif_json.rs +++ b/rust/src/bin/zkif_json.rs @@ -9,7 +9,7 @@ use zkinterface::{owned::message::MessagesOwned, reading::Messages}; // Example: // -// cargo run --bin zkif_json < example.zkif +// cargo run --bin zkif_json < ../examples/example.zkif // pub fn main() -> Result<(), Box> { let pretty = true; From 5e153abd753b95b40c2e12922e656fbd3865f100 Mon Sep 17 00:00:00 2001 From: aurel Date: Tue, 16 Jun 2020 22:33:08 +0200 Subject: [PATCH 17/17] Move changelog --- rust/Changelog.md => Changelog.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rust/Changelog.md => Changelog.md (100%) diff --git a/rust/Changelog.md b/Changelog.md similarity index 100% rename from rust/Changelog.md rename to Changelog.md