Add FFT for computing the H query.

This commit is contained in:
Sean Bowe 2016-08-04 21:47:20 -06:00
parent 977a8e8dab
commit 4f85755795
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
6 changed files with 170 additions and 22 deletions

View File

@ -18,6 +18,8 @@ pub use self::g2::G2;
extern "C" {
fn libsnarkwrap_init();
fn libsnarkwrap_pairing(p: *const G1, q: *const G2) -> Gt;
fn libsnarkwrap_getqap(d: *mut libc::uint32_t, omega: *mut Fr);
fn libsnarkwrap_test_compare_tau(i: *const G1, tau: *const Fr, d: libc::uint32_t) -> bool;
}
lazy_static! {
@ -34,6 +36,22 @@ pub fn initialize() {
}
}
/// Get the QAP info for the generation routines
pub fn getqap() -> (usize, Fr) {
let mut d = 0;
let mut o = Fr::zero();
unsafe { libsnarkwrap_getqap(&mut d, &mut o); }
(d as usize, o)
}
/// Check that the lagrange coefficients computed by tau over
/// G1 equal the expected vector.
pub fn compare_tau(v: &[G1], tau: &Fr) -> bool {
unsafe { libsnarkwrap_test_compare_tau(&v[0], tau, v.len() as u32) }
}
pub trait Pairing<Other: Group> {
fn g1<'a>(&'a self, other: &'a Other) -> &'a G1;
fn g2<'a>(&'a self, other: &'a Other) -> &'a G2;

View File

@ -6,6 +6,7 @@
#include "algebra/curves/public_params.hpp"
#include "relations/arithmetic_programs/qap/qap.hpp"
#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
using namespace std;
using namespace libsnark;
@ -168,3 +169,57 @@ extern "C" curve_GT libsnarkwrap_gt_exp(const curve_GT *p, const curve_Fr *s) {
extern "C" curve_GT libsnarkwrap_pairing(const curve_G1 *p, const curve_G2 *q) {
return curve_pp::reduced_pairing(*p, *q);
}
// QAP
qap_instance<curve_Fr> get_qap(
std::shared_ptr<basic_radix2_domain<curve_Fr>> &domain
)
{
// Generate a dummy circuit
auto example = generate_r1cs_example_with_field_input<curve_Fr>(250, 4);
// A/B swap
example.constraint_system.swap_AB_if_beneficial();
// QAP reduction
auto qap = r1cs_to_qap_instance_map(example.constraint_system);
// Degree of the QAP must be a power of 2
assert(qap.degree() == 256);
// Assume radix2 evaluation domain
domain = std::static_pointer_cast<basic_radix2_domain<curve_Fr>>(qap.domain);
return qap;
}
extern "C" void libsnarkwrap_getqap(uint32_t *d, curve_Fr *omega)
{
std::shared_ptr<basic_radix2_domain<curve_Fr>> domain;
auto qap = get_qap(domain);
*omega = domain->omega;
*d = qap.degree();
}
extern "C" bool libsnarkwrap_test_compare_tau(
const curve_G1 *inputs,
const curve_Fr *tau,
uint32_t d
)
{
std::shared_ptr<basic_radix2_domain<curve_Fr>> domain;
auto qap = get_qap(domain);
auto coeffs = domain->lagrange_coeffs(*tau);
assert(coeffs.size() == d);
assert(qap.degree() == d);
bool res = true;
for (size_t i = 0; i < d; i++) {
res &= (coeffs[i] * curve_G1::one()) == inputs[i];
}
return res;
}

70
src/fft.rs Normal file
View File

@ -0,0 +1,70 @@
use snark::{Group, Fr};
pub fn fft<G: Group>(v: &[G], omega: Fr) -> Vec<G>
{
if v.len() == 2 {
vec![
v[0] + v[1] * omega,
v[0] + v[1]
]
} else {
let d2 = v.len() / 2;
let mut evens = Vec::with_capacity(d2);
let mut odds = Vec::with_capacity(d2);
for (i, x) in v.iter().enumerate() {
if i % 2 == 0 {
evens.push(*x);
} else {
odds.push(*x);
}
}
let o2 = omega * omega;
let evens = fft(&evens, o2);
let odds = fft(&odds, o2);
let mut acc = omega;
let mut res = Vec::with_capacity(v.len());
for i in 0..v.len() {
res.push(evens[i%d2] + odds[i%d2] * acc);
acc = acc * omega;
}
res
}
}
#[cfg(test)]
mod test {
use super::fft;
use snark::*;
use util::*;
#[test]
fn compare_to_libsnark() {
initialize();
// Get the QAP degree and omega (for FFT evaluation)
let (d, omega) = getqap();
// Sample a random tau
let tau = Fr::random();
// Generate powers of tau in G1, from 0 to d exclusive of d
let powers_of_tau = TauPowers::new(tau).take(d).map(|e| G1::one() * e).collect::<Vec<_>>();
let overd = Fr::from_str(&format!("{}", d)).inverse();
let lc = fft(&powers_of_tau, omega) // omit tau^d
.into_iter()
.rev() // coefficients are in reverse
.map(|e| e * overd) // divide by d
.collect::<Vec<_>>();
// Compare against libsnark
assert!(compare_tau(&lc, &tau));
// Wrong tau
assert!(!compare_tau(&lc, &Fr::random()));
}
}

View File

@ -2,6 +2,7 @@ extern crate snark;
mod randompowers;
mod util;
mod fft;
use snark::*;

View File

@ -1,5 +1,5 @@
use snark::*;
use util::Sequences;
use util::*;
struct Spair<G: Group> {
p: G,
@ -80,27 +80,6 @@ where Group1: Pairing<Group2>
check(Sequences::new(i), a)
}
struct TauPowers {
acc: Fr,
tau: Fr
}
impl TauPowers {
fn new(tau: Fr) -> TauPowers {
TauPowers { acc: Fr::one(), tau: tau }
}
}
impl Iterator for TauPowers {
type Item = Fr;
fn next(&mut self) -> Option<Fr> {
let tmp = self.acc;
self.acc = tmp * self.tau;
Some(tmp)
}
}
#[test]
fn randompowers_simulation() {
initialize();

View File

@ -1,3 +1,5 @@
use snark::Fr;
pub struct Sequences<'a, T: 'a, I: Iterator<Item=&'a T>> {
v: I,
last: Option<&'a T>
@ -34,3 +36,26 @@ fn test_sequences() {
let expected = vec![(&a[0], &a[1]), (&a[1], &a[2]), (&a[2], &a[3])];
assert_eq!(b, expected);
}
pub struct TauPowers {
acc: Fr,
tau: Fr
}
impl TauPowers {
pub fn new(tau: Fr) -> TauPowers {
TauPowers { acc: Fr::one(), tau: tau }
}
}
impl Iterator for TauPowers {
type Item = Fr;
fn next(&mut self) -> Option<Fr> {
let tmp = self.acc;
self.acc = tmp * self.tau;
Some(tmp)
}
}