mirror of https://github.com/zcash/mpc.git
Add FFT for computing the H query.
This commit is contained in:
parent
977a8e8dab
commit
4f85755795
|
@ -18,6 +18,8 @@ pub use self::g2::G2;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn libsnarkwrap_init();
|
fn libsnarkwrap_init();
|
||||||
fn libsnarkwrap_pairing(p: *const G1, q: *const G2) -> Gt;
|
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! {
|
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> {
|
pub trait Pairing<Other: Group> {
|
||||||
fn g1<'a>(&'a self, other: &'a Other) -> &'a G1;
|
fn g1<'a>(&'a self, other: &'a Other) -> &'a G1;
|
||||||
fn g2<'a>(&'a self, other: &'a Other) -> &'a G2;
|
fn g2<'a>(&'a self, other: &'a Other) -> &'a G2;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "algebra/curves/public_params.hpp"
|
#include "algebra/curves/public_params.hpp"
|
||||||
#include "relations/arithmetic_programs/qap/qap.hpp"
|
#include "relations/arithmetic_programs/qap/qap.hpp"
|
||||||
#include "reductions/r1cs_to_qap/r1cs_to_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 std;
|
||||||
using namespace libsnark;
|
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) {
|
extern "C" curve_GT libsnarkwrap_pairing(const curve_G1 *p, const curve_G2 *q) {
|
||||||
return curve_pp::reduced_pairing(*p, *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;
|
||||||
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ extern crate snark;
|
||||||
|
|
||||||
mod randompowers;
|
mod randompowers;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod fft;
|
||||||
|
|
||||||
use snark::*;
|
use snark::*;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use snark::*;
|
use snark::*;
|
||||||
use util::Sequences;
|
use util::*;
|
||||||
|
|
||||||
struct Spair<G: Group> {
|
struct Spair<G: Group> {
|
||||||
p: G,
|
p: G,
|
||||||
|
@ -80,27 +80,6 @@ where Group1: Pairing<Group2>
|
||||||
check(Sequences::new(i), a)
|
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]
|
#[test]
|
||||||
fn randompowers_simulation() {
|
fn randompowers_simulation() {
|
||||||
initialize();
|
initialize();
|
||||||
|
|
25
src/util.rs
25
src/util.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use snark::Fr;
|
||||||
|
|
||||||
pub struct Sequences<'a, T: 'a, I: Iterator<Item=&'a T>> {
|
pub struct Sequences<'a, T: 'a, I: Iterator<Item=&'a T>> {
|
||||||
v: I,
|
v: I,
|
||||||
last: Option<&'a T>
|
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])];
|
let expected = vec![(&a[0], &a[1]), (&a[1], &a[2]), (&a[2], &a[3])];
|
||||||
assert_eq!(b, expected);
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue