bn 0.1.0

Pairing cryptography with the Barreto-Naehrig curve
use num::{Num,BigUint};
use fields::Field;
use fields::fp::PrimeFieldParams;
use fields::fp2::Fp2Params;
use fields::fp6::Fp6Params;
use fields::fp12::Fp12Params;
use super::{Fr,Fq,Fq2};
use groups::*;

pub struct FrParams;

impl PrimeFieldParams for FrParams {
    fn modulus() -> BigUint {
        BigUint::from_str_radix("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10).unwrap()
    }
    fn bits() -> usize { 254 }
    fn name() -> &'static str { "Fr" }
}

pub struct FqParams;

impl PrimeFieldParams for FqParams {
    fn modulus() -> BigUint {
        BigUint::from_str_radix("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10).unwrap()
    }
    fn bits() -> usize { 254 }
    fn name() -> &'static str { "Fq" }
}

#[test]
fn test_fr() {
    use fields;

    fields::tests::field_trials::<Fr>();
}

#[test]
fn test_fq() {
    use fields;

    fields::tests::field_trials::<Fq>();
}

pub struct G1Params;

impl GroupParams for G1Params {
    type Base = Fq;

    fn name() -> &'static str {
        "G1"
    }
    fn zero() -> Jacobian<Self> {
        Jacobian::new(Fq::zero(), Fq::one(), Fq::zero()).unwrap()
    }
    fn one() -> Jacobian<Self> {
        Jacobian::new(Fq::from("1"), Fq::from("2"), Fq::one()).unwrap()
    }
    fn coeff_b() -> Self::Base {
        Fq::from("3")
    }
}

#[test]
fn test_g1() {
    use groups;
    use ::G1;

    groups::tests::group_trials::<G1Params>();

    assert_eq!(G1::zero(), G1::one() + (G1::zero() - G1::one()));
    assert_eq!(G1::zero(), G1::one() * Fr::from("21888242871839275222246405745257275088548364400416034343698204186575808495616") + G1::one());
}

#[test]
fn g1_test_vector() {
    use ::G1;
    let a = G1::one() * Fr::from("19797905000333868150253315089095386158892526856493194078073564469188852136946");
    let b = G1::one() * Fr::from("2730506433347642574983433139433778984782882168213690554721050571242082865799");
    let e = &a + &b;

    let expect = G1::new(
        Fq::from("18450621724990678172567114131642278789161361170999664461184794604011563728206"),
        Fq::from("21329688341674583036384007811166435666174342925504675855816423131698588368496"),
        Fq::one()
    ).unwrap();

    assert_eq!(expect, e);
}

pub struct Fq2Params;

impl Fp2Params for Fq2Params {
    fn non_residue() -> Fq {
        Fq::from("21888242871839275222246405745257275088696311157297823662689037894645226208582")
    }
    fn name() -> &'static str {
        "Fq2"
    }
    fn frobenius_coeffs_c1(n: usize) -> Fq {
        match n {
            0 => Fq::from("1"),
            1 => Fq::from("21888242871839275222246405745257275088696311157297823662689037894645226208582"),
            _ => panic!()
        }
    }
}

#[test]
fn test_fq2() {
    use fields;

    fields::tests::field_trials::<Fq2>();
}

pub struct G2Params;

impl G2Params {
    pub fn twist() -> Fq2 {
        Fq2::new(Fq::from("9"), Fq::from("1"))
    }
    pub fn twist_mul_by_q_x() -> Fq2 {
        Fq2::new(Fq::from("21575463638280843010398324269430826099269044274347216827212613867836435027261"),
                 Fq::from("10307601595873709700152284273816112264069230130616436755625194854815875713954"))
    }
    pub fn twist_mul_by_q_y() -> Fq2 {
        Fq2::new(Fq::from("2821565182194536844548159561693502659359617185244120367078079554186484126554"),
                 Fq::from("3505843767911556378687030309984248845540243509899259641013678093033130930403"))
    }
}

impl GroupParams for G2Params {
    type Base = Fq2;

    fn name() -> &'static str {
        "G2"
    }
    fn zero() -> Jacobian<Self> {
        Jacobian::new(Fq2::zero(), Fq2::one(), Fq2::zero()).unwrap()
    }
    fn one() -> Jacobian<Self> {
        Jacobian::new(
            Fq2::new(
                Fq::from("10857046999023057135944570762232829481370756359578518086990519993285655852781"),
                Fq::from("11559732032986387107991004021392285783925812861821192530917403151452391805634")
            ),
            Fq2::new(
                Fq::from("8495653923123431417604973247489272438418190587263600148770280649306958101930"),
                Fq::from("4082367875863433681332203403145435568316851327593401208105741076214120093531")
            ),
            Fq2::one()
        ).unwrap()
    }
    fn coeff_b() -> Self::Base {
        &G2Params::twist().inverse() * &Fq::from("3")
    }
}

#[test]
fn test_g2() {
    use groups;
    use ::G2;

    groups::tests::group_trials::<G2Params>();

    assert_eq!(G2::zero(), G2::one() + (G2::zero() - G2::one()));
    assert_eq!(G2::zero(), G2::one() * Fr::from("21888242871839275222246405745257275088548364400416034343698204186575808495616") + G2::one());
}

#[test]
fn g2_test_vector() {
    use ::G2;
    let a = G2::one() * Fr::from("19797905000333868150253315089095386158892526856493194078073564469188852136946");
    let b = G2::one() * Fr::from("2730506433347642574983433139433778984782882168213690554721050571242082865799");   
    let e = &a + &b;

    let expect = G2::new(
        Fq2::new(
            Fq::from("10805137482603266627116066166226222153808813611856467496561473491230213987197"),
            Fq::from("11018998371825437935082073888099464993330606622517843684670450190973893289235")
        ),
        Fq2::new(
            Fq::from("371699491666579792038680273553261511891341995868329474144713691525212078012"),
            Fq::from("2123259504314265904107110265140842273706723557882599408954283209162529085097")
        ),
        Fq2::one()
    ).unwrap();

    assert_eq!(expect, e);
}

pub struct Fq6Params;

impl Fp6Params for Fq6Params {
    fn non_residue() -> Fq2 {
        Fq2::new(Fq::from("9"), Fq::from("1"))
    }
    fn name() -> &'static str {
        "Fq6"
    }
    fn frobenius_coeffs_c1(n: usize) -> Fq2 {
        match n {
            0 => Fq2::new(
                Fq::from("1"),
                Fq::from("0")
            ),
            1 => Fq2::new(
                Fq::from("21575463638280843010398324269430826099269044274347216827212613867836435027261"),
                Fq::from("10307601595873709700152284273816112264069230130616436755625194854815875713954")
            ),
            2 => Fq2::new(
                Fq::from("21888242871839275220042445260109153167277707414472061641714758635765020556616"),
                Fq::from("0")
            ),
            3 => Fq2::new(
                Fq::from("3772000881919853776433695186713858239009073593817195771773381919316419345261"),
                Fq::from("2236595495967245188281701248203181795121068902605861227855261137820944008926")
            ),
            4 => Fq2::new(
                Fq::from("2203960485148121921418603742825762020974279258880205651966"),
                Fq::from("0")
            ),
            5 => Fq2::new(
                Fq::from("18429021223477853657660792034369865839114504446431234726392080002137598044644"),
                Fq::from("9344045779998320333812420223237981029506012124075525679208581902008406485703")
            ),
            _ => panic!()
        }
    }
    fn frobenius_coeffs_c2(n: usize) -> Fq2 {
        match n {
            0 => Fq2::new(
                Fq::from("1"),
                Fq::from("0")
            ),
            1 => Fq2::new(
                Fq::from("2581911344467009335267311115468803099551665605076196740867805258568234346338"),
                Fq::from("19937756971775647987995932169929341994314640652964949448313374472400716661030")
            ),
            2 => Fq2::new(
                Fq::from("2203960485148121921418603742825762020974279258880205651966"),
                Fq::from("0")
            ),
            3 => Fq2::new(
                Fq::from("5324479202449903542726783395506214481928257762400643279780343368557297135718"),
                Fq::from("16208900380737693084919495127334387981393726419856888799917914180988844123039")
            ),
            4 => Fq2::new(
                Fq::from("21888242871839275220042445260109153167277707414472061641714758635765020556616"),
                Fq::from("0")
            ),
            5 => Fq2::new(
                Fq::from("13981852324922362344252311234282257507216387789820983642040889267519694726527"),
                Fq::from("7629828391165209371577384193250820201684255241773809077146787135900891633097")
            ),
            _ => panic!()
        }
    }
}

#[test]
fn test_fq6() {
    use fields;

    fields::tests::field_trials::<::Fq6>();
}

pub struct Fq12Params;

impl Fp12Params for Fq12Params {
    fn non_residue() -> Fq2 {
        Fq2::new(Fq::from("9"), Fq::from("1"))
    }
    fn name() -> &'static str {
        "Fq12"
    }
    fn frobenius_coeffs_c1(n: usize) -> Fq2 {
        match n {
            0 => Fq2::new(
                Fq::from("1"),
                Fq::from("0")
            ),
            1 => Fq2::new(
                Fq::from("8376118865763821496583973867626364092589906065868298776909617916018768340080"),
                Fq::from("16469823323077808223889137241176536799009286646108169935659301613961712198316")
            ),
            2 => Fq2::new(
                Fq::from("21888242871839275220042445260109153167277707414472061641714758635765020556617"),
                Fq::from("0")
            ),
            3 => Fq2::new(
                Fq::from("11697423496358154304825782922584725312912383441159505038794027105778954184319"),
                Fq::from("303847389135065887422783454877609941456349188919719272345083954437860409601")
            ),
            4 => Fq2::new(
                Fq::from("21888242871839275220042445260109153167277707414472061641714758635765020556616"),
                Fq::from("0")
            ),
            5 => Fq2::new(
                Fq::from("3321304630594332808241809054958361220322477375291206261884409189760185844239"),
                Fq::from("5722266937896532885780051958958348231143373700109372999374820235121374419868")
            ),
            6 => Fq2::new(
                Fq::from("21888242871839275222246405745257275088696311157297823662689037894645226208582"),
                Fq::from("0")
            ),
            7 => Fq2::new(
                Fq::from("13512124006075453725662431877630910996106405091429524885779419978626457868503"),
                Fq::from("5418419548761466998357268504080738289687024511189653727029736280683514010267")
            ),
            8 => Fq2::new(
                Fq::from("2203960485148121921418603742825762020974279258880205651966"),
                Fq::from("0")
            ),
            9 => Fq2::new(
                Fq::from("10190819375481120917420622822672549775783927716138318623895010788866272024264"),
                Fq::from("21584395482704209334823622290379665147239961968378104390343953940207365798982")
            ),
            10 => Fq2::new(
                Fq::from("2203960485148121921418603742825762020974279258880205651967"),
                Fq::from("0")
            ),
            11 => Fq2::new(
                Fq::from("18566938241244942414004596690298913868373833782006617400804628704885040364344"),
                Fq::from("16165975933942742336466353786298926857552937457188450663314217659523851788715")
            ),
            _ => panic!()
        }
    }
}

#[test]
fn test_fq12() {
    use fields;

    fields::tests::field_trials::<::Fq12>();
}

#[test]
fn fq12_test_vector() {
    let start = ::Fq12::new(
        ::Fq6::new(
            Fq2::new(
                Fq::from("19797905000333868150253315089095386158892526856493194078073564469188852136946"),
                Fq::from("10509658143212501778222314067134547632307419253211327938344904628569123178733")
            ),
            Fq2::new(
                Fq::from("208316612133170645758860571704540129781090973693601051684061348604461399206"),
                Fq::from("12617661120538088237397060591907161689901553895660355849494983891299803248390")
            ),
            Fq2::new(
                Fq::from("2897490589776053688661991433341220818937967872052418196321943489809183508515"),
                Fq::from("2730506433347642574983433139433778984782882168213690554721050571242082865799")
            )
        ),
        ::Fq6::new(
            Fq2::new(
                Fq::from("17870056122431653936196746815433147921488990391314067765563891966783088591110"),
                Fq::from("14314041658607615069703576372547568077123863812415914883625850585470406221594")
            ),
            Fq2::new(
                Fq::from("10123533891707846623287020000407963680629966110211808794181173248765209982878"),
                Fq::from("5062091880848845693514855272640141851746424235009114332841857306926659567101")
            ),
            Fq2::new(
                Fq::from("9839781502639936537333620974973645053542086898304697594692219798017709586567"),
                Fq::from("1583892292110602864638265389721494775152090720173641072176370350017825640703")
            )
        )
    );

    // Do a bunch of arbitrary stuff to the element

    let mut next = start.clone();
    for _ in 0..100 {
        next = &next * &start;
    }

    let cpy = next.clone();

    for _ in 0..10 {
        next = next.squared();
    }

    for _ in 0..10 {
        next = &next + &start;
        next = &next - &cpy;
        next = -&next;
    }

    next = next.squared();

    let finally = ::Fq12::new(
        ::Fq6::new(
            Fq2::new(
                Fq::from("18388750939593263065521177085001223024106699964957029146547831509155008229833"),
                Fq::from("18370529854582635460997127698388761779167953912610241447912705473964014492243")
            ),
            Fq2::new(
                Fq::from("3691824277096717481466579496401243638295254271265821828017111951446539785268"),
                Fq::from("20513494218085713799072115076991457239411567892860153903443302793553884247235")
            ),
            Fq2::new(
                Fq::from("12214155472433286415803224222551966441740960297013786627326456052558698216399"),
                Fq::from("10987494248070743195602580056085773610850106455323751205990078881956262496575")
            )
        ),
        ::Fq6::new(
            Fq2::new(
                Fq::from("5134522153456102954632718911439874984161223687865160221119284322136466794876"),
                Fq::from("20119236909927036376726859192821071338930785378711977469360149362002019539920")
            ),
            Fq2::new(
                Fq::from("8839766648621210419302228913265679710586991805716981851373026244791934012854"),
                Fq::from("9103032146464138788288547957401673544458789595252696070370942789051858719203")
            ),
            Fq2::new(
                Fq::from("10378379548636866240502412547812481928323945124508039853766409196375806029865"),
                Fq::from("9021627154807648093720460686924074684389554332435186899318369174351765754041")
            )
        )
    );

    assert_eq!(finally, next);
}

pub fn ate_loop_count() -> Fr {
    Fr::from("29793968203157093288")
}

pub fn final_exponent_z() -> Fr {
    Fr::from("4965661367192848881")
}