From 06085dd661b6a91debc12653d08e45c68a8fe668 Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Mon, 7 Jun 2021 11:15:10 +0200 Subject: [PATCH 1/8] [WIP] R1CS file export --- Cargo.lock | 10 +++++ fawkes-crypto/Cargo.toml | 1 + fawkes-crypto/src/backend/mod.rs | 1 + fawkes-crypto/src/backend/r1cs/mod.rs | 55 +++++++++++++++++++++++++++ fawkes-crypto/tests/r1cs_file.rs | 27 +++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 fawkes-crypto/src/backend/r1cs/mod.rs create mode 100644 fawkes-crypto/tests/r1cs_file.rs diff --git a/Cargo.lock b/Cargo.lock index a7cafc0..0fe4d25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,7 @@ dependencies = [ "impl-trait-for-tuples", "itertools", "linked-list", + "r1cs-file", "rand 0.7.3", "serde", ] @@ -498,6 +499,15 @@ dependencies = [ "proc-macro2 1.0.26", ] +[[package]] +name = "r1cs-file" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608d0571aab9ad5679b5ce9583f72a61b4c6d539f4745fb9dc25fa8c58192cfd" +dependencies = [ + "byteorder", +] + [[package]] name = "rand" version = "0.4.6" diff --git a/fawkes-crypto/Cargo.toml b/fawkes-crypto/Cargo.toml index ed436b6..a0e3ff8 100644 --- a/fawkes-crypto/Cargo.toml +++ b/fawkes-crypto/Cargo.toml @@ -25,6 +25,7 @@ impl-trait-for-tuples = "0.1.3" getrandom = { version = "0.2", optional = true } bit-vec = "0.6.3" itertools = "0.10.0" +r1cs-file = { version = "0.2.1", optional = true } [dependencies.blake2_rfc] version = "0.0.1" diff --git a/fawkes-crypto/src/backend/mod.rs b/fawkes-crypto/src/backend/mod.rs index 996d001..2c4d2ea 100644 --- a/fawkes-crypto/src/backend/mod.rs +++ b/fawkes-crypto/src/backend/mod.rs @@ -1,2 +1,3 @@ #[cfg(feature = "backend_bellman_groth16")] pub mod bellman_groth16; +pub mod r1cs; diff --git a/fawkes-crypto/src/backend/r1cs/mod.rs b/fawkes-crypto/src/backend/r1cs/mod.rs new file mode 100644 index 0000000..eed9770 --- /dev/null +++ b/fawkes-crypto/src/backend/r1cs/mod.rs @@ -0,0 +1,55 @@ +use crate::circuit::lc::Index; +use crate::circuit::cs::Gate; +use crate::ff_uint::{Num, PrimeField, Uint}; + +#[cfg(feature = "r1cs-file")] +pub fn get_r1cs_file(gates: &Vec>) -> r1cs_file::R1csFile { + use r1cs_file::*; + + let mut n_pub_in = 0; + let mut n_prvt_in = 0; + + let constraints = gates.iter().map(|gate| { + let mut map_comb = |(c, i): &(Num, Index)| { + let i = match *i { + Index::Input(i) => { + n_pub_in += 1; + i + }, + Index::Aux(i) => { + n_prvt_in += 1; + i + }, + }; + + + let mut c_bytes = [0; FS]; + c.0.to_uint().put_little_endian(&mut c_bytes); + + (FieldElement::from(c_bytes), i as u32) + }; + + let a = gate.0.iter().map(&mut map_comb).collect(); + let b = gate.1.iter().map(&mut map_comb).collect(); + let c = gate.2.iter().map(&mut map_comb).collect(); + + Constraint(a, b, c) + }).collect(); + + let mut prime_bytes = [0; FS]; + Fr::MODULUS.put_little_endian(&mut prime_bytes); + + R1csFile { + header: Header { + prime: FieldElement::from(prime_bytes), + n_wires: 0, + n_pub_out: 0, + n_pub_in, + n_prvt_in, + n_labels: 0, + n_constraints: gates.len() as u32, + }, + constraints: Constraints(constraints), + map: WireMap(Vec::new()), + } +} \ No newline at end of file diff --git a/fawkes-crypto/tests/r1cs_file.rs b/fawkes-crypto/tests/r1cs_file.rs new file mode 100644 index 0000000..337459b --- /dev/null +++ b/fawkes-crypto/tests/r1cs_file.rs @@ -0,0 +1,27 @@ +use fawkes_crypto::{ + backend::bellman_groth16::{ + engines::Bn256, + setup::setup + }, + circuit::cs::CS, + circuit::num::CNum, + circuit::poseidon::{c_poseidon_merkle_proof_root, CMerkleProof}, + core::signal::Signal, + native::poseidon::{PoseidonParams}, +}; +use fawkes_crypto::backend::r1cs::get_r1cs_file; +use fawkes_crypto::backend::bellman_groth16::engines::Engine; + +#[cfg(feature = "r1cs-file")] +#[test] +fn test_parameters_get_r1cs_file() { + fn circuit(public: CNum, secret: (CNum, CMerkleProof)) { + let poseidon_params = PoseidonParams::::new(3, 8, 53); + let res = c_poseidon_merkle_proof_root(&secret.0, &secret.1, &poseidon_params); + res.assert_eq(&public); + } + let params = setup::(circuit); + let file = get_r1cs_file::<::Fr, 32>(¶ms.1); + + assert!(true) +} \ No newline at end of file From 41e79aa4d001a42f328239ff58bb0540be7dab5d Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Thu, 10 Jun 2021 10:35:09 +0200 Subject: [PATCH 2/8] Re-export r1cs-file --- fawkes-crypto/src/backend/r1cs/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fawkes-crypto/src/backend/r1cs/mod.rs b/fawkes-crypto/src/backend/r1cs/mod.rs index eed9770..5c6f12e 100644 --- a/fawkes-crypto/src/backend/r1cs/mod.rs +++ b/fawkes-crypto/src/backend/r1cs/mod.rs @@ -2,8 +2,10 @@ use crate::circuit::lc::Index; use crate::circuit::cs::Gate; use crate::ff_uint::{Num, PrimeField, Uint}; +pub use r1cs_file::*; + #[cfg(feature = "r1cs-file")] -pub fn get_r1cs_file(gates: &Vec>) -> r1cs_file::R1csFile { +pub fn get_r1cs_file(gates: &Vec>) -> R1csFile { use r1cs_file::*; let mut n_pub_in = 0; From 108fa8916e8896581972efe6d91afa377f99f7b0 Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Thu, 10 Jun 2021 10:35:20 +0200 Subject: [PATCH 3/8] Set n_wires properly --- fawkes-crypto/src/backend/r1cs/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fawkes-crypto/src/backend/r1cs/mod.rs b/fawkes-crypto/src/backend/r1cs/mod.rs index 5c6f12e..8e925e6 100644 --- a/fawkes-crypto/src/backend/r1cs/mod.rs +++ b/fawkes-crypto/src/backend/r1cs/mod.rs @@ -44,7 +44,7 @@ pub fn get_r1cs_file(gates: &Vec>) -> R1csFile { header: Header { prime: FieldElement::from(prime_bytes), - n_wires: 0, + n_wires: n_pub_in + n_prvt_in, n_pub_out: 0, n_pub_in, n_prvt_in, From e45f0ef84c0b3cf3dc264eb631e271e16bad4265 Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Mon, 14 Jun 2021 21:12:04 +0200 Subject: [PATCH 4/8] Implement const tracker serialization --- fawkes-crypto/src/backend/mod.rs | 1 + fawkes-crypto/src/backend/r1cs/mod.rs | 106 +++++++++++++++++++------- 2 files changed, 78 insertions(+), 29 deletions(-) diff --git a/fawkes-crypto/src/backend/mod.rs b/fawkes-crypto/src/backend/mod.rs index 2c4d2ea..8948c66 100644 --- a/fawkes-crypto/src/backend/mod.rs +++ b/fawkes-crypto/src/backend/mod.rs @@ -1,3 +1,4 @@ #[cfg(feature = "backend_bellman_groth16")] pub mod bellman_groth16; +#[cfg(feature = "r1cs-file")] pub mod r1cs; diff --git a/fawkes-crypto/src/backend/r1cs/mod.rs b/fawkes-crypto/src/backend/r1cs/mod.rs index 8e925e6..c3fa4e6 100644 --- a/fawkes-crypto/src/backend/r1cs/mod.rs +++ b/fawkes-crypto/src/backend/r1cs/mod.rs @@ -1,47 +1,91 @@ -use crate::circuit::lc::Index; +use std::io::{self, Read, Write}; + +use bit_vec::BitVec; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +pub use r1cs_file::*; use crate::circuit::cs::Gate; +use crate::circuit::lc::Index; +use crate::core::signal::Signal; use crate::ff_uint::{Num, PrimeField, Uint}; -pub use r1cs_file::*; +// TODO: Separate into multiple modules? + +const C_MAGIC: &[u8; 8] = b"ZPCCONST"; + +pub struct ConstTracker(pub BitVec); + +impl ConstTracker { + pub fn read(mut r: R) -> io::Result { + let mut magic = [u8; 8]; + r.read_exact(&mut magic)?; + + if magic != *C_MAGIC { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid magic sequence", + )); + } + + let len = r.read_u64::()?; + let mut bytes = vec![0; len as usize]; + r.read_exact(&mut bytes); + + Ok(ConstTracker(BitVec::from_bytes(&bytes))) + } + + pub fn write(&self, mut w: W) -> io::Result<()> { + w.write_all(MAGIC)?; + w.write_u64::(bytes.len() as u64)?; + + let bytes = self.0.to_bytes(); + w.write_all(&bytes)?; -#[cfg(feature = "r1cs-file")] -pub fn get_r1cs_file(gates: &Vec>) -> R1csFile { + Ok(()) + } +} + +pub fn get_r1cs_file( + gates: &Vec>, + consts: &BitVec, +) -> (R1csFile, ConstTracker) { use r1cs_file::*; let mut n_pub_in = 0; let mut n_prvt_in = 0; - let constraints = gates.iter().map(|gate| { - let mut map_comb = |(c, i): &(Num, Index)| { - let i = match *i { - Index::Input(i) => { - n_pub_in += 1; - i - }, - Index::Aux(i) => { - n_prvt_in += 1; - i - }, - }; + let constraints = gates + .iter() + .map(|gate| { + let mut map_comb = |(c, i): &(Num, Index)| { + let i = match *i { + Index::Input(i) => { + n_pub_in += 1; + i + } + Index::Aux(i) => { + n_prvt_in += 1; + i + } + }; + let mut c_bytes = [0; FS]; + c.0.to_uint().put_little_endian(&mut c_bytes); - let mut c_bytes = [0; FS]; - c.0.to_uint().put_little_endian(&mut c_bytes); - - (FieldElement::from(c_bytes), i as u32) - }; + (FieldElement::from(c_bytes), i as u32) + }; - let a = gate.0.iter().map(&mut map_comb).collect(); - let b = gate.1.iter().map(&mut map_comb).collect(); - let c = gate.2.iter().map(&mut map_comb).collect(); + let a = gate.0.iter().map(&mut map_comb).collect(); + let b = gate.1.iter().map(&mut map_comb).collect(); + let c = gate.2.iter().map(&mut map_comb).collect(); - Constraint(a, b, c) - }).collect(); + Constraint(a, b, c) + }) + .collect(); let mut prime_bytes = [0; FS]; Fr::MODULUS.put_little_endian(&mut prime_bytes); - R1csFile { + let r1cs_file = R1csFile { header: Header { prime: FieldElement::from(prime_bytes), n_wires: n_pub_in + n_prvt_in, @@ -53,5 +97,9 @@ pub fn get_r1cs_file(gates: &Vec>) -> }, constraints: Constraints(constraints), map: WireMap(Vec::new()), - } -} \ No newline at end of file + }; + + let consts = ConstTracker(consts.clone()); + + (r1cs_file, consts) +} From 1b62030544bd01ab603823c5957d220e9a331c50 Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Mon, 14 Jun 2021 21:12:41 +0200 Subject: [PATCH 5/8] [WIP] Implement witness serialization --- Cargo.lock | 10 ++++++++++ fawkes-crypto/Cargo.toml | 1 + fawkes-crypto/src/backend/r1cs/mod.rs | 22 ++++++++++++++++++++++ fawkes-crypto/tests/r1cs_file.rs | 2 ++ 4 files changed, 35 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 0fe4d25..51dd773 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,6 +180,7 @@ dependencies = [ "r1cs-file", "rand 0.7.3", "serde", + "wtns-file", ] [[package]] @@ -803,3 +804,12 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wtns-file" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68cf676c66595a09765db556e461d390c80d947959ced7b456a0b3163cc465cb" +dependencies = [ + "byteorder", +] diff --git a/fawkes-crypto/Cargo.toml b/fawkes-crypto/Cargo.toml index a0e3ff8..41b81a4 100644 --- a/fawkes-crypto/Cargo.toml +++ b/fawkes-crypto/Cargo.toml @@ -26,6 +26,7 @@ getrandom = { version = "0.2", optional = true } bit-vec = "0.6.3" itertools = "0.10.0" r1cs-file = { version = "0.2.1", optional = true } +wtns-file = { version = "0.1.1", optional = true } [dependencies.blake2_rfc] version = "0.0.1" diff --git a/fawkes-crypto/src/backend/r1cs/mod.rs b/fawkes-crypto/src/backend/r1cs/mod.rs index c3fa4e6..e452330 100644 --- a/fawkes-crypto/src/backend/r1cs/mod.rs +++ b/fawkes-crypto/src/backend/r1cs/mod.rs @@ -3,6 +3,8 @@ use std::io::{self, Read, Write}; use bit_vec::BitVec; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; pub use r1cs_file::*; +pub use wtns_file::WtnsFile; + use crate::circuit::cs::Gate; use crate::circuit::lc::Index; use crate::core::signal::Signal; @@ -103,3 +105,23 @@ pub fn get_r1cs_file( (r1cs_file, consts) } + +#[cfg(feature = "wtns-file")] +pub fn get_witness< + 'a, + Fr: PrimeField, + Pub: Signal>, + Sec: Signal>, + const FS: usize, +>( + gates: &Vec>, + consts: &BitVec, + input_pub: &Pub::Value, + input_sec: &Pub::Value, +) -> WtnsFile { + let cs = WitnessCS::rc_new(gates, consts); + + let signal_pub = Pub::alloc(cs, Some(input_pub)); + signal_pub.inputize(); + let signal_sec = Sec::alloc(cs, Some(input_sec)); +} diff --git a/fawkes-crypto/tests/r1cs_file.rs b/fawkes-crypto/tests/r1cs_file.rs index 337459b..f9915d2 100644 --- a/fawkes-crypto/tests/r1cs_file.rs +++ b/fawkes-crypto/tests/r1cs_file.rs @@ -20,7 +20,9 @@ fn test_parameters_get_r1cs_file() { let res = c_poseidon_merkle_proof_root(&secret.0, &secret.1, &poseidon_params); res.assert_eq(&public); } + let params = setup::(circuit); + let file = get_r1cs_file::<::Fr, 32>(¶ms.1); assert!(true) From 57979dbb8d59e44fffda0d1c466a2d2e358d595d Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Mon, 21 Jun 2021 01:04:15 +0200 Subject: [PATCH 6/8] Refactor r1cs backend, finish wtns file implementation --- Cargo.lock | 4 +- fawkes-crypto/Cargo.toml | 2 +- .../src/backend/r1cs/const_tracker.rs | 78 ++++++++++ fawkes-crypto/src/backend/r1cs/mod.rs | 136 ++---------------- fawkes-crypto/src/backend/r1cs/r1cs_file.rs | 98 +++++++++++++ fawkes-crypto/src/backend/r1cs/wtns_file.rs | 43 ++++++ 6 files changed, 233 insertions(+), 128 deletions(-) create mode 100644 fawkes-crypto/src/backend/r1cs/const_tracker.rs create mode 100644 fawkes-crypto/src/backend/r1cs/r1cs_file.rs create mode 100644 fawkes-crypto/src/backend/r1cs/wtns_file.rs diff --git a/Cargo.lock b/Cargo.lock index 51dd773..bc8a78f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -807,9 +807,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wtns-file" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cf676c66595a09765db556e461d390c80d947959ced7b456a0b3163cc465cb" +checksum = "97af06ea70a8f40f1c0e3db66fbae790455197bb3b9df3396329cdb0ccd22793" dependencies = [ "byteorder", ] diff --git a/fawkes-crypto/Cargo.toml b/fawkes-crypto/Cargo.toml index 41b81a4..dd886be 100644 --- a/fawkes-crypto/Cargo.toml +++ b/fawkes-crypto/Cargo.toml @@ -26,7 +26,7 @@ getrandom = { version = "0.2", optional = true } bit-vec = "0.6.3" itertools = "0.10.0" r1cs-file = { version = "0.2.1", optional = true } -wtns-file = { version = "0.1.1", optional = true } +wtns-file = { version = "0.1.2", optional = true } [dependencies.blake2_rfc] version = "0.0.1" diff --git a/fawkes-crypto/src/backend/r1cs/const_tracker.rs b/fawkes-crypto/src/backend/r1cs/const_tracker.rs new file mode 100644 index 0000000..ff7d99e --- /dev/null +++ b/fawkes-crypto/src/backend/r1cs/const_tracker.rs @@ -0,0 +1,78 @@ +use std::io::{self, Read, Write}; + +use bit_vec::BitVec; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +const MAGIC: &[u8; 4] = b"ZPCT"; + +pub struct ConstTrackerFile(pub BitVec); + +impl ConstTrackerFile { + pub fn read(mut r: R) -> io::Result { + let mut magic = [0; MAGIC.len()]; + r.read_exact(&mut magic)?; + + if magic != *MAGIC { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid magic sequence", + )); + } + + let len = r.read_u64::()?; + let mut bytes = vec![0; div_ceil(len as usize, 8)]; + r.read_exact(&mut bytes)?; + + Ok(ConstTrackerFile(BitVec::from_bytes(&bytes))) + } + + pub fn write(&self, mut w: W) -> io::Result<()> { + w.write_all(MAGIC)?; + w.write_u64::(self.0.len() as u64)?; // Number of bits + + let bytes = self.0.to_bytes(); + w.write_all(&bytes)?; + + Ok(()) + } +} + +#[inline] +fn div_ceil(a: usize, b: usize) -> usize { + let (q, r) = (a / b, a % b); + if r == 0 { + q + } else { + q + 1 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const REFERENCE: &[u8] = &[ + b'Z', b'P', b'C', b'T', // magic + 0x0F,0,0,0,0,0,0,0, // length - 15 bits + 0b10100000, 0b00010010, // bits + ]; + + #[test] + fn test_const_tracker_file_read() { + let ct = ConstTrackerFile::read(REFERENCE).unwrap(); + + let bytes = ct.0.to_bytes(); + assert_eq!(&bytes, &[0b10100000, 0b00010010]); + } + + #[test] + fn test_const_tracker_file_write() { + let mut ct = ConstTrackerFile(BitVec::from_bytes(&[0b10100000, 0b00010010])); + ct.0.pop(); + + let mut buf = Vec::new(); + ct.write(&mut buf); + + assert_eq!(&buf, REFERENCE); + } +} \ No newline at end of file diff --git a/fawkes-crypto/src/backend/r1cs/mod.rs b/fawkes-crypto/src/backend/r1cs/mod.rs index e452330..050c5c0 100644 --- a/fawkes-crypto/src/backend/r1cs/mod.rs +++ b/fawkes-crypto/src/backend/r1cs/mod.rs @@ -1,127 +1,13 @@ -use std::io::{self, Read, Write}; - -use bit_vec::BitVec; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -pub use r1cs_file::*; -pub use wtns_file::WtnsFile; - -use crate::circuit::cs::Gate; -use crate::circuit::lc::Index; -use crate::core::signal::Signal; -use crate::ff_uint::{Num, PrimeField, Uint}; - -// TODO: Separate into multiple modules? - -const C_MAGIC: &[u8; 8] = b"ZPCCONST"; - -pub struct ConstTracker(pub BitVec); - -impl ConstTracker { - pub fn read(mut r: R) -> io::Result { - let mut magic = [u8; 8]; - r.read_exact(&mut magic)?; - - if magic != *C_MAGIC { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid magic sequence", - )); - } - - let len = r.read_u64::()?; - let mut bytes = vec![0; len as usize]; - r.read_exact(&mut bytes); - - Ok(ConstTracker(BitVec::from_bytes(&bytes))) - } - - pub fn write(&self, mut w: W) -> io::Result<()> { - w.write_all(MAGIC)?; - w.write_u64::(bytes.len() as u64)?; - - let bytes = self.0.to_bytes(); - w.write_all(&bytes)?; - - Ok(()) - } -} - -pub fn get_r1cs_file( - gates: &Vec>, - consts: &BitVec, -) -> (R1csFile, ConstTracker) { - use r1cs_file::*; - - let mut n_pub_in = 0; - let mut n_prvt_in = 0; - - let constraints = gates - .iter() - .map(|gate| { - let mut map_comb = |(c, i): &(Num, Index)| { - let i = match *i { - Index::Input(i) => { - n_pub_in += 1; - i - } - Index::Aux(i) => { - n_prvt_in += 1; - i - } - }; - - let mut c_bytes = [0; FS]; - c.0.to_uint().put_little_endian(&mut c_bytes); - - (FieldElement::from(c_bytes), i as u32) - }; - - let a = gate.0.iter().map(&mut map_comb).collect(); - let b = gate.1.iter().map(&mut map_comb).collect(); - let c = gate.2.iter().map(&mut map_comb).collect(); - - Constraint(a, b, c) - }) - .collect(); - - let mut prime_bytes = [0; FS]; - Fr::MODULUS.put_little_endian(&mut prime_bytes); - - let r1cs_file = R1csFile { - header: Header { - prime: FieldElement::from(prime_bytes), - n_wires: n_pub_in + n_prvt_in, - n_pub_out: 0, - n_pub_in, - n_prvt_in, - n_labels: 0, - n_constraints: gates.len() as u32, - }, - constraints: Constraints(constraints), - map: WireMap(Vec::new()), - }; - - let consts = ConstTracker(consts.clone()); - - (r1cs_file, consts) -} - +#[cfg(feature = "r1cs-file")] +pub use self::const_tracker::*; +#[cfg(feature = "r1cs-file")] +pub use self::r1cs_file::*; #[cfg(feature = "wtns-file")] -pub fn get_witness< - 'a, - Fr: PrimeField, - Pub: Signal>, - Sec: Signal>, - const FS: usize, ->( - gates: &Vec>, - consts: &BitVec, - input_pub: &Pub::Value, - input_sec: &Pub::Value, -) -> WtnsFile { - let cs = WitnessCS::rc_new(gates, consts); +pub use self::wtns_file::*; - let signal_pub = Pub::alloc(cs, Some(input_pub)); - signal_pub.inputize(); - let signal_sec = Sec::alloc(cs, Some(input_sec)); -} +#[cfg(feature = "r1cs-file")] +mod const_tracker; +#[cfg(feature = "r1cs-file")] +mod r1cs_file; +#[cfg(feature = "wtns-file")] +mod wtns_file; \ No newline at end of file diff --git a/fawkes-crypto/src/backend/r1cs/r1cs_file.rs b/fawkes-crypto/src/backend/r1cs/r1cs_file.rs new file mode 100644 index 0000000..7833969 --- /dev/null +++ b/fawkes-crypto/src/backend/r1cs/r1cs_file.rs @@ -0,0 +1,98 @@ +use bit_vec::BitVec; +pub use r1cs_file::*; + +use crate::circuit::cs::Gate; +use crate::circuit::lc::Index; +use crate::ff_uint::{Num, PrimeField, Uint}; +use crate::backend::r1cs::ConstTrackerFile; + +pub fn get_r1cs_file( + gates: &Vec>, + consts: &BitVec, +) -> (R1csFile, ConstTrackerFile) { + use r1cs_file::*; + + let mut n_pub_in = 0; + let mut n_prvt_in = 0; + + let constraints = gates + .iter() + .map(|gate| { + let mut map_comb = |(c, i): &(Num, Index)| { + let i = match *i { + Index::Input(i) => { + n_pub_in += 1; + i + } + Index::Aux(i) => { + n_prvt_in += 1; + i + } + }; + + let mut c_bytes = [0; FS]; + c.0.to_uint().put_little_endian(&mut c_bytes); + + (FieldElement::from(c_bytes), i as u32) + }; + + let a = gate.0.iter().map(&mut map_comb).collect(); + let b = gate.1.iter().map(&mut map_comb).collect(); + let c = gate.2.iter().map(&mut map_comb).collect(); + + Constraint(a, b, c) + }) + .collect(); + + let mut prime_bytes = [0; FS]; + Fr::MODULUS.put_little_endian(&mut prime_bytes); + + let r1cs_file = R1csFile { + header: Header { + prime: FieldElement::from(prime_bytes), + n_wires: n_pub_in + n_prvt_in, + n_pub_out: 0, + n_pub_in, + n_prvt_in, + n_labels: 0, + n_constraints: gates.len() as u32, + }, + constraints: Constraints(constraints), + map: WireMap(Vec::new()), + }; + + let consts = ConstTrackerFile(consts.clone()); + + (r1cs_file, consts) +} + +#[cfg(test)] +mod tests { + use crate::{ + backend::bellman_groth16::{ + engines::Bn256, + setup::setup + }, + circuit::cs::CS, + circuit::num::CNum, + circuit::poseidon::{c_poseidon_merkle_proof_root, CMerkleProof}, + core::signal::Signal, + native::poseidon::{PoseidonParams}, + }; + use crate::backend::r1cs::get_r1cs_file; + use crate::backend::bellman_groth16::engines::Engine; + + #[test] + fn test_parameters_get_r1cs_file() { + fn circuit(public: CNum, secret: (CNum, CMerkleProof)) { + let poseidon_params = PoseidonParams::::new(3, 8, 53); + let res = c_poseidon_merkle_proof_root(&secret.0, &secret.1, &poseidon_params); + res.assert_eq(&public); + } + + let params = setup::(circuit); + let file = get_r1cs_file::<::Fr, 32>(¶ms.1, ¶ms.2); + + assert!(true) + } +} \ No newline at end of file diff --git a/fawkes-crypto/src/backend/r1cs/wtns_file.rs b/fawkes-crypto/src/backend/r1cs/wtns_file.rs new file mode 100644 index 0000000..2618c2a --- /dev/null +++ b/fawkes-crypto/src/backend/r1cs/wtns_file.rs @@ -0,0 +1,43 @@ +use bit_vec::BitVec; +use wtns_file::{WtnsFile, FieldElement}; + +use crate::ff_uint::{Uint, PrimeField}; +use crate::core::signal::Signal; +use crate::circuit::cs::{WitnessCS, Gate, CS}; +use crate::circuit::lc::Index; + +pub fn get_witness< + 'a, + Fr: PrimeField, + Pub: Signal>, + Sec: Signal>, + const FS: usize, +>( + gates: &'a Vec>, + consts: &'a BitVec, + input_pub: &'a Pub::Value, + input_sec: &'a Sec::Value, +) -> WtnsFile { + let cs = WitnessCS::rc_new(gates, consts); + + let mut prime_bytes = [0; FS]; + Fr::MODULUS.put_little_endian(&mut prime_bytes); + + let signal_pub = Pub::alloc(&cs, Some(input_pub)); + signal_pub.inputize(); + let _signal_sec = Sec::alloc(&cs, Some(input_sec)); + + let cs = cs.borrow_mut(); + let mut witness = Vec::with_capacity(cs.num_aux()); + + for i in (cs.num_input() + 1)..cs.num_aux() { + let num = cs.get_value(Index::Aux(i)).unwrap(); + let mut bytes = [0; FS]; + num.0.to_uint().put_little_endian(&mut bytes); + let fe = FieldElement::from(bytes); + + witness.push(fe); + } + + WtnsFile::from_vec(witness, FieldElement::from(prime_bytes)) +} From a0ef316f0ade09ed4a9da147999ecd1fb5f0f270 Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Thu, 24 Jun 2021 18:13:00 +0200 Subject: [PATCH 7/8] Attempt to fix r1cs and wtns file generation --- Cargo.lock | 4 +-- fawkes-crypto/Cargo.toml | 2 +- fawkes-crypto/src/backend/r1cs/r1cs_file.rs | 14 +++++++++-- fawkes-crypto/src/backend/r1cs/wtns_file.rs | 27 ++++++++++++--------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc8a78f..9ecfc6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -807,9 +807,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wtns-file" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97af06ea70a8f40f1c0e3db66fbae790455197bb3b9df3396329cdb0ccd22793" +checksum = "3d3b856452298f68a5879e3901918bac5d753ca9fa4be8a983a37a3d25dabf0a" dependencies = [ "byteorder", ] diff --git a/fawkes-crypto/Cargo.toml b/fawkes-crypto/Cargo.toml index dd886be..efa7a29 100644 --- a/fawkes-crypto/Cargo.toml +++ b/fawkes-crypto/Cargo.toml @@ -26,7 +26,7 @@ getrandom = { version = "0.2", optional = true } bit-vec = "0.6.3" itertools = "0.10.0" r1cs-file = { version = "0.2.1", optional = true } -wtns-file = { version = "0.1.2", optional = true } +wtns-file = { version = "0.1.5", optional = true } [dependencies.blake2_rfc] version = "0.0.1" diff --git a/fawkes-crypto/src/backend/r1cs/r1cs_file.rs b/fawkes-crypto/src/backend/r1cs/r1cs_file.rs index 7833969..639222e 100644 --- a/fawkes-crypto/src/backend/r1cs/r1cs_file.rs +++ b/fawkes-crypto/src/backend/r1cs/r1cs_file.rs @@ -5,6 +5,7 @@ use crate::circuit::cs::Gate; use crate::circuit::lc::Index; use crate::ff_uint::{Num, PrimeField, Uint}; use crate::backend::r1cs::ConstTrackerFile; +use std::collections::HashSet; pub fn get_r1cs_file( gates: &Vec>, @@ -15,17 +16,26 @@ pub fn get_r1cs_file( let mut n_pub_in = 0; let mut n_prvt_in = 0; + let mut pub_inputs = HashSet::new(); + let mut prvt_inputs = HashSet::new(); + let constraints = gates .iter() .map(|gate| { let mut map_comb = |(c, i): &(Num, Index)| { let i = match *i { Index::Input(i) => { - n_pub_in += 1; + if pub_inputs.insert(i) { + n_pub_in += 1; + } + i } Index::Aux(i) => { - n_prvt_in += 1; + if prvt_inputs.insert(i) { + n_prvt_in += 1; + } + i } }; diff --git a/fawkes-crypto/src/backend/r1cs/wtns_file.rs b/fawkes-crypto/src/backend/r1cs/wtns_file.rs index 2618c2a..650b03f 100644 --- a/fawkes-crypto/src/backend/r1cs/wtns_file.rs +++ b/fawkes-crypto/src/backend/r1cs/wtns_file.rs @@ -3,20 +3,21 @@ use wtns_file::{WtnsFile, FieldElement}; use crate::ff_uint::{Uint, PrimeField}; use crate::core::signal::Signal; -use crate::circuit::cs::{WitnessCS, Gate, CS}; -use crate::circuit::lc::Index; +use crate::circuit::cs::{WitnessCS, Gate}; pub fn get_witness< 'a, Fr: PrimeField, Pub: Signal>, Sec: Signal>, + C: Fn(Pub, Sec), const FS: usize, >( gates: &'a Vec>, consts: &'a BitVec, input_pub: &'a Pub::Value, input_sec: &'a Sec::Value, + circuit: C, ) -> WtnsFile { let cs = WitnessCS::rc_new(gates, consts); @@ -25,19 +26,21 @@ pub fn get_witness< let signal_pub = Pub::alloc(&cs, Some(input_pub)); signal_pub.inputize(); - let _signal_sec = Sec::alloc(&cs, Some(input_sec)); + let signal_sec = Sec::alloc(&cs, Some(input_sec)); - let cs = cs.borrow_mut(); - let mut witness = Vec::with_capacity(cs.num_aux()); + circuit(signal_pub, signal_sec); - for i in (cs.num_input() + 1)..cs.num_aux() { - let num = cs.get_value(Index::Aux(i)).unwrap(); - let mut bytes = [0; FS]; - num.0.to_uint().put_little_endian(&mut bytes); - let fe = FieldElement::from(bytes); + let cs = cs.borrow(); - witness.push(fe); - } + let witness = cs.values_input + .iter() + .chain(cs.values_aux.iter()) + .map(|num| { + let mut bytes = [0; FS]; + num.0.to_uint().put_little_endian(&mut bytes); + FieldElement::from(bytes) + }) + .collect(); WtnsFile::from_vec(witness, FieldElement::from(prime_bytes)) } From 4537fd5355d98082f73ff7a607bfe75b62dbe36e Mon Sep 17 00:00:00 2001 From: Dmitry Vdovin Date: Thu, 24 Jun 2021 20:02:25 +0200 Subject: [PATCH 8/8] Remove unneeded r1cs_file test --- fawkes-crypto/tests/r1cs_file.rs | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 fawkes-crypto/tests/r1cs_file.rs diff --git a/fawkes-crypto/tests/r1cs_file.rs b/fawkes-crypto/tests/r1cs_file.rs deleted file mode 100644 index f9915d2..0000000 --- a/fawkes-crypto/tests/r1cs_file.rs +++ /dev/null @@ -1,29 +0,0 @@ -use fawkes_crypto::{ - backend::bellman_groth16::{ - engines::Bn256, - setup::setup - }, - circuit::cs::CS, - circuit::num::CNum, - circuit::poseidon::{c_poseidon_merkle_proof_root, CMerkleProof}, - core::signal::Signal, - native::poseidon::{PoseidonParams}, -}; -use fawkes_crypto::backend::r1cs::get_r1cs_file; -use fawkes_crypto::backend::bellman_groth16::engines::Engine; - -#[cfg(feature = "r1cs-file")] -#[test] -fn test_parameters_get_r1cs_file() { - fn circuit(public: CNum, secret: (CNum, CMerkleProof)) { - let poseidon_params = PoseidonParams::::new(3, 8, 53); - let res = c_poseidon_merkle_proof_root(&secret.0, &secret.1, &poseidon_params); - res.assert_eq(&public); - } - - let params = setup::(circuit); - - let file = get_r1cs_file::<::Fr, 32>(¶ms.1); - - assert!(true) -} \ No newline at end of file