2018-03-06 21:25:15 -08:00
|
|
|
//! Jubjub is a twisted Edwards curve defined over the BLS12-381 scalar
|
|
|
|
//! field, Fr. It takes the form `-x^2 + y^2 = 1 + dx^2y^2` with
|
|
|
|
//! `d = -(10240/10241)`. It is birationally equivalent to a Montgomery
|
|
|
|
//! curve of the form `y^2 = x^3 + Ax^2 + x` with `A = 40962`. This
|
|
|
|
//! value `A` is the smallest integer choice such that:
|
2017-11-22 20:57:00 -08:00
|
|
|
//!
|
|
|
|
//! * `(A - 2) / 4` is a small integer (`10240`).
|
2018-03-08 12:03:07 -08:00
|
|
|
//! * `A^2 - 4` is quadratic nonresidue.
|
2018-03-06 21:25:15 -08:00
|
|
|
//! * The group order of the curve and its quadratic twist has a large
|
|
|
|
//! prime factor.
|
2017-11-22 20:57:00 -08:00
|
|
|
//!
|
|
|
|
//! Jubjub has `s = 0x0e7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7`
|
2018-03-06 21:25:15 -08:00
|
|
|
//! as the prime subgroup order, with cofactor 8. (The twist has
|
|
|
|
//! cofactor 4.)
|
2017-11-22 20:57:00 -08:00
|
|
|
//!
|
2018-03-06 21:25:15 -08:00
|
|
|
//! It is a complete twisted Edwards curve, so the equivalence with
|
|
|
|
//! the Montgomery curve forms a group isomorphism, allowing points
|
|
|
|
//! to be freely converted between the two forms.
|
2017-11-22 20:57:00 -08:00
|
|
|
|
|
|
|
use pairing::{
|
|
|
|
Engine,
|
2017-12-14 10:34:57 -08:00
|
|
|
Field,
|
2017-12-11 22:06:05 -08:00
|
|
|
PrimeField,
|
|
|
|
SqrtField
|
2017-11-22 20:57:00 -08:00
|
|
|
};
|
|
|
|
|
2018-03-07 23:06:53 -08:00
|
|
|
use group_hash::group_hash;
|
|
|
|
|
|
|
|
use constants;
|
2017-12-28 10:06:05 -08:00
|
|
|
|
2017-11-22 20:57:00 -08:00
|
|
|
use pairing::bls12_381::{
|
|
|
|
Bls12,
|
|
|
|
Fr
|
|
|
|
};
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
/// This is an implementation of the twisted Edwards Jubjub curve.
|
2017-11-22 20:57:00 -08:00
|
|
|
pub mod edwards;
|
2018-03-07 23:41:47 -08:00
|
|
|
|
|
|
|
/// This is an implementation of the birationally equivalent
|
|
|
|
/// Montgomery curve.
|
2017-11-22 20:57:00 -08:00
|
|
|
pub mod montgomery;
|
2018-03-07 23:41:47 -08:00
|
|
|
|
|
|
|
/// This is an implementation of the scalar field for Jubjub.
|
2018-03-06 21:25:15 -08:00
|
|
|
pub mod fs;
|
2017-11-22 20:57:00 -08:00
|
|
|
|
2017-12-11 22:06:05 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests;
|
|
|
|
|
2018-03-06 21:25:15 -08:00
|
|
|
/// Point of unknown order.
|
|
|
|
pub enum Unknown { }
|
|
|
|
|
|
|
|
/// Point of prime order.
|
|
|
|
pub enum PrimeOrder { }
|
|
|
|
|
2018-03-05 15:00:04 -08:00
|
|
|
/// Fixed generators of the Jubjub curve of unknown
|
|
|
|
/// exponent.
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub enum FixedGenerators {
|
|
|
|
/// The prover will demonstrate knowledge of discrete log
|
|
|
|
/// with respect to this base when they are constructing
|
|
|
|
/// a proof, in order to authorize proof construction.
|
2018-03-06 08:56:29 -08:00
|
|
|
ProofGenerationKey = 0,
|
2018-03-05 15:00:04 -08:00
|
|
|
|
|
|
|
/// The note commitment is randomized over this generator.
|
|
|
|
NoteCommitmentRandomness = 1,
|
|
|
|
|
|
|
|
/// The node commitment is randomized again by the position
|
|
|
|
/// in order to supply the nullifier computation with a
|
|
|
|
/// unique input w.r.t. the note being spent, to prevent
|
|
|
|
/// Faerie gold attacks.
|
|
|
|
NullifierPosition = 2,
|
|
|
|
|
|
|
|
/// The value commitment is used to check balance between
|
|
|
|
/// inputs and outputs. The value is placed over this
|
|
|
|
/// generator.
|
|
|
|
ValueCommitmentValue = 3,
|
|
|
|
/// The value commitment is randomized over this generator,
|
|
|
|
/// for privacy.
|
|
|
|
ValueCommitmentRandomness = 4,
|
|
|
|
|
|
|
|
/// The spender proves discrete log with respect to this
|
|
|
|
/// base at spend time.
|
|
|
|
SpendingKeyGenerator = 5,
|
|
|
|
|
|
|
|
Max = 6
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This is an extension to the pairing Engine trait which
|
|
|
|
/// offers a scalar field for the embedded curve (Jubjub)
|
|
|
|
/// and some pre-computed parameters.
|
2017-12-11 22:06:05 -08:00
|
|
|
pub trait JubjubEngine: Engine {
|
2018-03-07 23:41:47 -08:00
|
|
|
/// The scalar field of the Jubjub curve
|
2017-12-11 22:06:05 -08:00
|
|
|
type Fs: PrimeField + SqrtField;
|
2018-03-07 23:41:47 -08:00
|
|
|
/// The parameters of Jubjub and the Sapling protocol
|
2017-12-11 22:06:05 -08:00
|
|
|
type Params: JubjubParams<Self>;
|
|
|
|
}
|
2017-11-22 20:57:00 -08:00
|
|
|
|
2018-03-05 15:00:04 -08:00
|
|
|
/// The pre-computed parameters for Jubjub, including curve
|
|
|
|
/// constants and various limits and window tables.
|
2017-12-11 22:06:05 -08:00
|
|
|
pub trait JubjubParams<E: JubjubEngine>: Sized {
|
2018-03-05 15:00:04 -08:00
|
|
|
/// The `d` constant of the twisted Edwards curve.
|
2017-12-11 22:06:05 -08:00
|
|
|
fn edwards_d(&self) -> &E::Fr;
|
2018-03-05 15:00:04 -08:00
|
|
|
/// The `A` constant of the birationally equivalent Montgomery curve.
|
2017-12-11 22:06:05 -08:00
|
|
|
fn montgomery_a(&self) -> &E::Fr;
|
2018-03-05 15:00:04 -08:00
|
|
|
/// The `A` constant, doubled.
|
2017-12-14 10:34:57 -08:00
|
|
|
fn montgomery_2a(&self) -> &E::Fr;
|
2018-03-05 15:00:04 -08:00
|
|
|
/// The scaling factor used for conversion from the Montgomery form.
|
2017-12-11 22:06:05 -08:00
|
|
|
fn scale(&self) -> &E::Fr;
|
2018-03-05 15:00:04 -08:00
|
|
|
/// Returns the generators (for each segment) used in all Pedersen commitments.
|
2017-12-28 10:06:05 -08:00
|
|
|
fn pedersen_hash_generators(&self) -> &[edwards::Point<E, PrimeOrder>];
|
2018-03-05 15:00:04 -08:00
|
|
|
/// Returns the maximum number of chunks per segment of the Pedersen hash.
|
2017-12-28 10:06:05 -08:00
|
|
|
fn pedersen_hash_chunks_per_generator(&self) -> usize;
|
2018-03-05 15:00:04 -08:00
|
|
|
/// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different
|
|
|
|
/// magnitudes of the Pedersen hash segment generators.
|
2017-12-28 10:06:05 -08:00
|
|
|
fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(E::Fr, E::Fr)>>];
|
2018-02-06 10:08:17 -08:00
|
|
|
|
2018-03-05 15:00:04 -08:00
|
|
|
/// Returns the number of chunks needed to represent a full scalar during fixed-base
|
|
|
|
/// exponentiation.
|
2018-02-06 10:08:17 -08:00
|
|
|
fn fixed_base_chunks_per_generator(&self) -> usize;
|
2018-03-05 15:00:04 -08:00
|
|
|
/// Returns a fixed generator.
|
2018-02-07 12:33:09 -08:00
|
|
|
fn generator(&self, base: FixedGenerators) -> &edwards::Point<E, PrimeOrder>;
|
2018-03-16 14:25:36 -07:00
|
|
|
/// Returns a window table [0, 1, ..., 8] for different magnitudes of some
|
2018-03-05 15:00:04 -08:00
|
|
|
/// fixed generator.
|
2018-02-07 12:33:09 -08:00
|
|
|
fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>];
|
2017-11-22 20:57:00 -08:00
|
|
|
}
|
|
|
|
|
2017-12-11 22:06:05 -08:00
|
|
|
impl JubjubEngine for Bls12 {
|
|
|
|
type Fs = self::fs::Fs;
|
|
|
|
type Params = JubjubBls12;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct JubjubBls12 {
|
|
|
|
edwards_d: Fr,
|
|
|
|
montgomery_a: Fr,
|
2017-12-14 10:34:57 -08:00
|
|
|
montgomery_2a: Fr,
|
2017-12-28 10:06:05 -08:00
|
|
|
scale: Fr,
|
2018-02-06 10:08:17 -08:00
|
|
|
|
2017-12-28 10:06:05 -08:00
|
|
|
pedersen_hash_generators: Vec<edwards::Point<Bls12, PrimeOrder>>,
|
2018-02-06 10:08:17 -08:00
|
|
|
pedersen_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
|
|
|
|
|
|
|
|
fixed_base_generators: Vec<edwards::Point<Bls12, PrimeOrder>>,
|
|
|
|
fixed_base_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
|
2017-12-11 22:06:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl JubjubParams<Bls12> for JubjubBls12 {
|
|
|
|
fn edwards_d(&self) -> &Fr { &self.edwards_d }
|
|
|
|
fn montgomery_a(&self) -> &Fr { &self.montgomery_a }
|
2017-12-14 10:34:57 -08:00
|
|
|
fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a }
|
2017-12-11 22:06:05 -08:00
|
|
|
fn scale(&self) -> &Fr { &self.scale }
|
2017-12-28 10:06:05 -08:00
|
|
|
fn pedersen_hash_generators(&self) -> &[edwards::Point<Bls12, PrimeOrder>] {
|
|
|
|
&self.pedersen_hash_generators
|
|
|
|
}
|
|
|
|
fn pedersen_hash_chunks_per_generator(&self) -> usize {
|
2018-02-11 11:59:57 -08:00
|
|
|
63
|
2017-12-28 10:06:05 -08:00
|
|
|
}
|
2018-02-06 10:08:17 -08:00
|
|
|
fn fixed_base_chunks_per_generator(&self) -> usize {
|
|
|
|
84
|
|
|
|
}
|
2017-12-28 10:06:05 -08:00
|
|
|
fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(Fr, Fr)>>] {
|
|
|
|
&self.pedersen_circuit_generators
|
|
|
|
}
|
2018-02-07 12:33:09 -08:00
|
|
|
fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bls12, PrimeOrder>
|
|
|
|
{
|
|
|
|
&self.fixed_base_generators[base as usize]
|
|
|
|
}
|
|
|
|
fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>]
|
|
|
|
{
|
|
|
|
&self.fixed_base_circuit_generators[base as usize][..]
|
|
|
|
}
|
2017-12-11 22:06:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl JubjubBls12 {
|
2017-11-22 20:57:00 -08:00
|
|
|
pub fn new() -> Self {
|
2017-12-14 10:34:57 -08:00
|
|
|
let montgomery_a = Fr::from_str("40962").unwrap();
|
|
|
|
let mut montgomery_2a = montgomery_a;
|
|
|
|
montgomery_2a.double();
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
let mut tmp_params = JubjubBls12 {
|
2017-11-22 20:57:00 -08:00
|
|
|
// d = -(10240/10241)
|
|
|
|
edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(),
|
|
|
|
// A = 40962
|
2017-12-14 10:34:57 -08:00
|
|
|
montgomery_a: montgomery_a,
|
|
|
|
// 2A = 2.A
|
|
|
|
montgomery_2a: montgomery_2a,
|
2017-11-22 20:57:00 -08:00
|
|
|
// scaling factor = sqrt(4 / (a - d))
|
2017-12-28 10:06:05 -08:00
|
|
|
scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(),
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
// We'll initialize these below
|
2017-12-28 10:06:05 -08:00
|
|
|
pedersen_hash_generators: vec![],
|
2018-02-06 10:08:17 -08:00
|
|
|
pedersen_circuit_generators: vec![],
|
|
|
|
fixed_base_generators: vec![],
|
|
|
|
fixed_base_circuit_generators: vec![],
|
2017-12-28 10:06:05 -08:00
|
|
|
};
|
|
|
|
|
2018-02-06 10:08:17 -08:00
|
|
|
// Create the bases for the Pedersen hashes
|
2017-12-28 10:06:05 -08:00
|
|
|
{
|
2018-03-07 23:41:47 -08:00
|
|
|
// TODO: This currently does not match the specification
|
2017-12-28 10:06:05 -08:00
|
|
|
let mut cur = 0;
|
|
|
|
let mut pedersen_hash_generators = vec![];
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
// TODO: This generates more bases for the Pedersen hashes
|
|
|
|
// than necessary, which is just a performance issue in
|
|
|
|
// practice.
|
2018-03-06 08:03:29 -08:00
|
|
|
while pedersen_hash_generators.len() < 5 {
|
2018-03-07 23:41:47 -08:00
|
|
|
let gh = group_hash(&[cur], constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params);
|
2018-01-29 07:56:58 -08:00
|
|
|
// We don't want to overflow and start reusing generators
|
|
|
|
assert!(cur != u8::max_value());
|
2017-12-28 10:06:05 -08:00
|
|
|
cur += 1;
|
|
|
|
|
|
|
|
if let Some(gh) = gh {
|
2018-01-29 07:56:58 -08:00
|
|
|
pedersen_hash_generators.push(gh);
|
2017-12-28 10:06:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
// Check for duplicates, far worse than spec inconsistencies!
|
|
|
|
for (i, p1) in pedersen_hash_generators.iter().enumerate() {
|
|
|
|
if p1 == &edwards::Point::zero() {
|
|
|
|
panic!("Neutral element!");
|
|
|
|
}
|
|
|
|
|
|
|
|
for p2 in pedersen_hash_generators.iter().skip(i+1) {
|
|
|
|
if p1 == p2 {
|
|
|
|
panic!("Duplicate generator!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_params.pedersen_hash_generators = pedersen_hash_generators;
|
2017-11-22 20:57:00 -08:00
|
|
|
}
|
2017-12-28 10:06:05 -08:00
|
|
|
|
2018-02-06 10:08:17 -08:00
|
|
|
// Create the bases for other parts of the protocol
|
|
|
|
{
|
2018-03-06 07:30:28 -08:00
|
|
|
let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];
|
|
|
|
|
|
|
|
{
|
|
|
|
// Each generator is found by invoking the group hash
|
|
|
|
// on tag 0x00, 0x01, ... until we find a valid result.
|
|
|
|
let find_first_gh = |personalization| {
|
2018-03-07 23:41:47 -08:00
|
|
|
let mut cur = 0u8;
|
2018-03-06 07:30:28 -08:00
|
|
|
|
|
|
|
loop {
|
2018-03-07 23:41:47 -08:00
|
|
|
let gh = group_hash::<Bls12>(&[cur], personalization, &tmp_params);
|
2018-03-06 07:30:28 -08:00
|
|
|
// We don't want to overflow.
|
|
|
|
assert!(cur != u8::max_value());
|
|
|
|
cur += 1;
|
|
|
|
|
|
|
|
if let Some(gh) = gh {
|
|
|
|
break gh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Written this way for exhaustion (double entendre). There's no
|
|
|
|
// way to iterate over the variants of an enum, so it's hideous.
|
|
|
|
for c in 0..(FixedGenerators::Max as usize) {
|
|
|
|
let p = match c {
|
2018-03-06 08:56:29 -08:00
|
|
|
c if c == (FixedGenerators::ProofGenerationKey as usize) => {
|
2018-03-07 23:06:53 -08:00
|
|
|
constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION
|
2018-03-06 07:30:28 -08:00
|
|
|
},
|
|
|
|
c if c == (FixedGenerators::NoteCommitmentRandomness as usize) => {
|
2018-03-07 23:06:53 -08:00
|
|
|
constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION
|
2018-03-06 07:30:28 -08:00
|
|
|
},
|
|
|
|
c if c == (FixedGenerators::NullifierPosition as usize) => {
|
2018-03-07 23:06:53 -08:00
|
|
|
constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION
|
2018-03-06 07:30:28 -08:00
|
|
|
},
|
|
|
|
c if c == (FixedGenerators::ValueCommitmentValue as usize) => {
|
2018-03-07 23:06:53 -08:00
|
|
|
constants::VALUE_COMMITMENT_VALUE_GENERATOR_PERSONALIZATION
|
2018-03-06 07:30:28 -08:00
|
|
|
},
|
|
|
|
c if c == (FixedGenerators::ValueCommitmentRandomness as usize) => {
|
2018-03-07 23:06:53 -08:00
|
|
|
constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION
|
2018-03-06 07:30:28 -08:00
|
|
|
},
|
|
|
|
c if c == (FixedGenerators::SpendingKeyGenerator as usize) => {
|
2018-03-07 23:06:53 -08:00
|
|
|
constants::SPENDING_KEY_GENERATOR_PERSONALIZATION
|
2018-03-06 07:30:28 -08:00
|
|
|
},
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
|
|
|
|
fixed_base_generators[c] = find_first_gh(p);
|
|
|
|
}
|
|
|
|
}
|
2018-02-06 10:08:17 -08:00
|
|
|
|
2018-03-06 07:30:28 -08:00
|
|
|
// Check for duplicates, far worse than spec inconsistencies!
|
|
|
|
for (i, p1) in fixed_base_generators.iter().enumerate() {
|
|
|
|
if p1 == &edwards::Point::zero() {
|
|
|
|
panic!("Neutral element!");
|
|
|
|
}
|
2018-02-06 10:08:17 -08:00
|
|
|
|
2018-03-06 07:30:28 -08:00
|
|
|
for p2 in fixed_base_generators.iter().skip(i+1) {
|
|
|
|
if p1 == p2 {
|
|
|
|
panic!("Duplicate generator!");
|
|
|
|
}
|
2018-02-06 10:08:17 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
tmp_params.fixed_base_generators = fixed_base_generators;
|
2018-02-06 10:08:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the 2-bit window table lookups for each 4-bit
|
|
|
|
// "chunk" in each segment of the Pedersen hash
|
2017-12-28 10:06:05 -08:00
|
|
|
{
|
|
|
|
let mut pedersen_circuit_generators = vec![];
|
|
|
|
|
2018-03-06 07:30:28 -08:00
|
|
|
// Process each segment
|
2018-03-07 23:41:47 -08:00
|
|
|
for mut gen in tmp_params.pedersen_hash_generators.iter().cloned() {
|
|
|
|
let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params);
|
2017-12-28 10:06:05 -08:00
|
|
|
let mut windows = vec![];
|
2018-03-07 23:41:47 -08:00
|
|
|
for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() {
|
2018-03-06 07:30:28 -08:00
|
|
|
// Create (x, y) coeffs for this chunk
|
2017-12-28 10:06:05 -08:00
|
|
|
let mut coeffs = vec![];
|
|
|
|
let mut g = gen.clone();
|
2018-03-06 07:30:28 -08:00
|
|
|
|
|
|
|
// coeffs = g, g*2, g*3, g*4
|
2017-12-28 10:06:05 -08:00
|
|
|
for _ in 0..4 {
|
|
|
|
coeffs.push(g.into_xy().expect("cannot produce O"));
|
2018-03-07 23:41:47 -08:00
|
|
|
g = g.add(&gen, &tmp_params);
|
2017-12-28 10:06:05 -08:00
|
|
|
}
|
|
|
|
windows.push(coeffs);
|
|
|
|
|
2018-03-06 07:30:28 -08:00
|
|
|
// Our chunks are separated by 2 bits to prevent overlap.
|
2017-12-28 10:06:05 -08:00
|
|
|
for _ in 0..4 {
|
2018-03-07 23:41:47 -08:00
|
|
|
gen = gen.double(&tmp_params);
|
2017-12-28 10:06:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pedersen_circuit_generators.push(windows);
|
|
|
|
}
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
tmp_params.pedersen_circuit_generators = pedersen_circuit_generators;
|
2017-12-28 10:06:05 -08:00
|
|
|
}
|
|
|
|
|
2018-02-06 10:08:17 -08:00
|
|
|
// Create the 3-bit window table lookups for fixed-base
|
|
|
|
// exp of each base in the protocol.
|
|
|
|
{
|
|
|
|
let mut fixed_base_circuit_generators = vec![];
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
for mut gen in tmp_params.fixed_base_generators.iter().cloned() {
|
2018-02-06 10:08:17 -08:00
|
|
|
let mut windows = vec![];
|
2018-03-07 23:41:47 -08:00
|
|
|
for _ in 0..tmp_params.fixed_base_chunks_per_generator() {
|
2018-02-06 10:08:17 -08:00
|
|
|
let mut coeffs = vec![(Fr::zero(), Fr::one())];
|
|
|
|
let mut g = gen.clone();
|
|
|
|
for _ in 0..7 {
|
|
|
|
coeffs.push(g.into_xy());
|
2018-03-07 23:41:47 -08:00
|
|
|
g = g.add(&gen, &tmp_params);
|
2018-02-06 10:08:17 -08:00
|
|
|
}
|
|
|
|
windows.push(coeffs);
|
|
|
|
|
2018-03-06 07:30:28 -08:00
|
|
|
// gen = gen * 8
|
2018-02-06 10:08:17 -08:00
|
|
|
gen = g;
|
|
|
|
}
|
|
|
|
fixed_base_circuit_generators.push(windows);
|
|
|
|
}
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
tmp_params.fixed_base_circuit_generators = fixed_base_circuit_generators;
|
2018-02-06 10:08:17 -08:00
|
|
|
}
|
|
|
|
|
2018-03-07 23:41:47 -08:00
|
|
|
tmp_params
|
2017-11-22 20:57:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 22:06:05 -08:00
|
|
|
#[test]
|
|
|
|
fn test_jubjub_bls12() {
|
|
|
|
let params = JubjubBls12::new();
|
2017-11-22 20:57:00 -08:00
|
|
|
|
2017-12-11 22:06:05 -08:00
|
|
|
tests::test_suite::<Bls12>(¶ms);
|
2018-02-24 13:11:01 -08:00
|
|
|
|
|
|
|
let test_repr = hex!("b9481dd1103b7d1f8578078eb429d3c476472f53e88c0eaefdf51334c7c8b98c");
|
|
|
|
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
|
|
|
let q = edwards::Point::<Bls12, _>::get_for_y(
|
|
|
|
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
|
|
|
false,
|
|
|
|
¶ms
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert!(p == q);
|
2017-11-22 20:57:00 -08:00
|
|
|
}
|