initial commit
diff --git a/BenchtestALL.rs b/BenchtestALL.rs
new file mode 100644
index 0000000..55961be
--- /dev/null
+++ b/BenchtestALL.rs
@@ -0,0 +1,957 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+#![allow(non_snake_case)]
+extern crate amcl;
+
+//use std::str;
+//use std::io;
+
+use amcl::arch;
+use amcl::rand::RAND;
+use amcl::types::{CurveType, CurvePairingType, ModType};
+
+use std::time::Instant;
+
+const MIN_ITERS: isize = 10;
+const MIN_TIME: isize = 10;
+
+fn ed25519(mut rng: &mut RAND) {
+ //use amcl::ed25519;
+ use amcl::ed25519::big;
+ use amcl::ed25519::ecp;
+ use amcl::ed25519::fp;
+ use amcl::ed25519::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing ed25519 ECC");
+
+ if ecp::CURVETYPE == CurveType::WEIERSTRASS {
+ println!("Weierstrass parameterization");
+ }
+ if ecp::CURVETYPE == CurveType::EDWARDS {
+ println!("Edwards parameterization");
+ }
+ if ecp::CURVETYPE == CurveType::MONTGOMERY {
+ println!("Montgomery parameterization");
+ }
+
+ if fp::MODTYPE == ModType::PSEUDO_MERSENNE {
+ println!("Pseudo-Mersenne Modulus");
+ }
+ if fp::MODTYPE == ModType::MONTGOMERY_FRIENDLY {
+ println!("Montgomery friendly Modulus");
+ }
+ if fp::MODTYPE == ModType::GENERALISED_MERSENNE {
+ println!("Generalised-Mersenne Modulus");
+ }
+ if fp::MODTYPE == ModType::NOT_SPECIAL {
+ println!("Not special Modulus");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let P = G.mul(&mut r);
+ if !P.is_infinity() {
+ println!("FAILURE - rG!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = G.mul(&mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("EC mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn nist256(mut rng: &mut RAND) {
+ //use amcl::nist256;
+ use amcl::nist256::big;
+ use amcl::nist256::ecp;
+ use amcl::nist256::fp;
+ use amcl::nist256::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing nist256 ECC");
+
+ if ecp::CURVETYPE == CurveType::WEIERSTRASS {
+ println!("Weierstrass parameterization");
+ }
+ if ecp::CURVETYPE == CurveType::EDWARDS {
+ println!("Edwards parameterization");
+ }
+ if ecp::CURVETYPE == CurveType::MONTGOMERY {
+ println!("Montgomery parameterization");
+ }
+
+ if fp::MODTYPE == ModType::PSEUDO_MERSENNE {
+ println!("Pseudo-Mersenne Modulus");
+ }
+ if fp::MODTYPE == ModType::MONTGOMERY_FRIENDLY {
+ println!("Montgomery friendly Modulus");
+ }
+ if fp::MODTYPE == ModType::GENERALISED_MERSENNE {
+ println!("Generalised-Mersenne Modulus");
+ }
+ if fp::MODTYPE == ModType::NOT_SPECIAL {
+ println!("Not special Modulus");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let P = G.mul(&mut r);
+ if !P.is_infinity() {
+ println!("FAILURE - rG!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = G.mul(&mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("EC mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn goldilocks(mut rng: &mut RAND) {
+ //use amcl::goldilocks;
+ use amcl::goldilocks::big;
+ use amcl::goldilocks::ecp;
+ use amcl::goldilocks::fp;
+ use amcl::goldilocks::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing goldilocks ECC");
+
+ if ecp::CURVETYPE == CurveType::WEIERSTRASS {
+ println!("Weierstrass parameterization");
+ }
+ if ecp::CURVETYPE == CurveType::EDWARDS {
+ println!("Edwards parameterization");
+ }
+ if ecp::CURVETYPE == CurveType::MONTGOMERY {
+ println!("Montgomery parameterization");
+ }
+
+ if fp::MODTYPE == ModType::PSEUDO_MERSENNE {
+ println!("Pseudo-Mersenne Modulus");
+ }
+ if fp::MODTYPE == ModType::MONTGOMERY_FRIENDLY {
+ println!("Montgomery friendly Modulus");
+ }
+ if fp::MODTYPE == ModType::GENERALISED_MERSENNE {
+ println!("Generalised-Mersenne Modulus");
+ }
+ if fp::MODTYPE == ModType::NOT_SPECIAL {
+ println!("Not special Modulus");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let P = G.mul(&mut r);
+ if !P.is_infinity() {
+ println!("FAILURE - rG!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = G.mul(&mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("EC mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn bn254(mut rng: &mut RAND) {
+ //use amcl::bn254;
+ use amcl::bn254::big;
+ use amcl::bn254::ecp;
+ use amcl::bn254::ecp2;
+ use amcl::bn254::fp;
+ use amcl::bn254::pair;
+ use amcl::bn254::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing BN254 Pairings");
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ println!("BN Pairing-Friendly Curve");
+ }
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BLS {
+ println!("BLS Pairing-Friendly Curve");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let mut G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let mut P = pair::g1mul(&mut G, &mut r);
+
+ if !P.is_infinity() {
+ println!("FAILURE - rP!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ P = pair::g1mul(&mut G, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G1 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut Q = ecp2::ECP2::generator();
+ let mut W = pair::g2mul(&mut Q, &mut r);
+
+ if !W.is_infinity() {
+ println!("FAILURE - rQ!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ W = pair::g2mul(&mut Q, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G2 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut w = pair::ate(&mut Q, &mut P);
+ w = pair::fexp(&w);
+
+ let mut g = pair::gtpow(&mut w, &mut r);
+
+ if !g.isunity() {
+ println!("FAILURE - g^r!=1");
+ return;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair::gtpow(&mut w, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = w.compow(&s, &mut r);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow (compressed) - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ w = pair::ate(&mut Q, &mut P);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing ATE - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair::fexp(&w);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing FEXP - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ P.copy(&G);
+ Q.copy(&W);
+
+ P = pair::g1mul(&mut P, &mut s);
+ g = pair::ate(&mut Q, &mut P);
+ g = pair::fexp(&g);
+
+ P.copy(&G);
+ Q = pair::g2mul(&mut Q, &mut s);
+ w = pair::ate(&mut Q, &mut P);
+ w = pair::fexp(&w);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,sP) ");
+ fail = true;
+ }
+
+ Q.copy(&W);
+ g = pair::ate(&mut Q, &mut P);
+ g = pair::fexp(&g);
+ g = pair::gtpow(&mut g, &mut s);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,P)^s ");
+ fail = true;
+ }
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn bls383(mut rng: &mut RAND) {
+ //use amcl::bls383;
+ use amcl::bls383::big;
+ use amcl::bls383::ecp;
+ use amcl::bls383::ecp2;
+ use amcl::bls383::fp;
+ use amcl::bls383::pair;
+ use amcl::bls383::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing BLS383 Pairings");
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ println!("BN Pairing-Friendly Curve");
+ }
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BLS {
+ println!("BLS Pairing-Friendly Curve");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let mut G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let mut P = pair::g1mul(&mut G, &mut r);
+
+ if !P.is_infinity() {
+ println!("FAILURE - rP!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ P = pair::g1mul(&mut G, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G1 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut Q = ecp2::ECP2::generator();
+ let mut W = pair::g2mul(&mut Q, &mut r);
+
+ if !W.is_infinity() {
+ println!("FAILURE - rQ!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ W = pair::g2mul(&mut Q, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G2 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut w = pair::ate(&mut Q, &mut P);
+ w = pair::fexp(&w);
+
+ let mut g = pair::gtpow(&mut w, &mut r);
+
+ if !g.isunity() {
+ println!("FAILURE - g^r!=1");
+ return;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair::gtpow(&mut w, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = w.compow(&s, &mut r);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow (compressed) - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ w = pair::ate(&mut Q, &mut P);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing ATE - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair::fexp(&w);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing FEXP - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ P.copy(&G);
+ Q.copy(&W);
+
+ P = pair::g1mul(&mut P, &mut s);
+ g = pair::ate(&mut Q, &mut P);
+ g = pair::fexp(&g);
+
+ P.copy(&G);
+ Q = pair::g2mul(&mut Q, &mut s);
+ w = pair::ate(&mut Q, &mut P);
+ w = pair::fexp(&w);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,sP) ");
+ fail = true;
+ }
+
+ Q.copy(&W);
+ g = pair::ate(&mut Q, &mut P);
+ g = pair::fexp(&g);
+ g = pair::gtpow(&mut g, &mut s);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,P)^s ");
+ fail = true;
+ }
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn bls24(mut rng: &mut RAND) {
+ //use amcl::bls24;
+ use amcl::bls24::big;
+ use amcl::bls24::ecp;
+ use amcl::bls24::ecp4;
+ use amcl::bls24::fp;
+ use amcl::bls24::pair192;
+ use amcl::bls24::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing BLS24 Pairings");
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ println!("BN Pairing-Friendly Curve");
+ }
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BLS {
+ println!("BLS24 Pairing-Friendly Curve");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let mut G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let mut P = pair192::g1mul(&mut G, &mut r);
+
+ if !P.is_infinity() {
+ println!("FAILURE - rP!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ P = pair192::g1mul(&mut G, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G1 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut Q = ecp4::ECP4::generator();
+ let mut W = pair192::g2mul(&mut Q, &mut r);
+
+ if !W.is_infinity() {
+ println!("FAILURE - rQ!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ W = pair192::g2mul(&mut Q, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G2 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut w = pair192::ate(&mut Q, &mut P);
+ w = pair192::fexp(&w);
+
+ let mut g = pair192::gtpow(&mut w, &mut r);
+
+ if !g.isunity() {
+ println!("FAILURE - g^r!=1");
+ return;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair192::gtpow(&mut w, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = w.compow(&s, &mut r);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow (compressed) - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ w = pair192::ate(&mut Q, &mut P);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing ATE - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair192::fexp(&w);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing FEXP - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ P.copy(&G);
+ Q.copy(&W);
+
+ P = pair192::g1mul(&mut P, &mut s);
+ g = pair192::ate(&mut Q, &mut P);
+ g = pair192::fexp(&g);
+
+ P.copy(&G);
+ Q = pair192::g2mul(&mut Q, &mut s);
+ w = pair192::ate(&mut Q, &mut P);
+ w = pair192::fexp(&w);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,sP) ");
+ fail = true;
+ }
+
+ Q.copy(&W);
+ g = pair192::ate(&mut Q, &mut P);
+ g = pair192::fexp(&g);
+ g = pair192::gtpow(&mut g, &mut s);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,P)^s ");
+ fail = true;
+ }
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn bls48(mut rng: &mut RAND) {
+ //use amcl::bls48;
+ use amcl::bls48::big;
+ use amcl::bls48::ecp;
+ use amcl::bls48::ecp8;
+ use amcl::bls48::fp;
+ use amcl::bls48::pair256;
+ use amcl::bls48::rom;
+ let mut fail = false;
+ println!("\nTesting/Timing BLS48 Pairings");
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ println!("BN Pairing-Friendly Curve");
+ }
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BLS {
+ println!("BLS48 Pairing-Friendly Curve");
+ }
+
+ println!("Modulus size {:} bits", fp::MODBITS);
+ println!("{:} bit build", arch::CHUNK);
+
+ let mut G = ecp::ECP::generator();
+
+ let mut r = big::BIG::new_ints(&rom::CURVE_ORDER);
+ let mut s = big::BIG::randomnum(&r, &mut rng);
+
+ let mut P = pair256::g1mul(&mut G, &mut r);
+
+ if !P.is_infinity() {
+ println!("FAILURE - rP!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ P = pair256::g1mul(&mut G, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G1 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut Q = ecp8::ECP8::generator();
+ let mut W = pair256::g2mul(&mut Q, &mut r);
+
+ if !W.is_infinity() {
+ println!("FAILURE - rQ!=O");
+ fail = true;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ W = pair256::g2mul(&mut Q, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("G2 mul - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut w = pair256::ate(&mut Q, &mut P);
+ w = pair256::fexp(&w);
+
+ let mut g = pair256::gtpow(&mut w, &mut r);
+
+ if !g.isunity() {
+ println!("FAILURE - g^r!=1");
+ return;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair256::gtpow(&mut w, &mut s);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = w.compow(&s, &mut r);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("GT pow (compressed) - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ w = pair256::ate(&mut Q, &mut P);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing ATE - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ let _ = pair256::fexp(&w);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("PAIRing FEXP - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ P.copy(&G);
+ Q.copy(&W);
+
+ P = pair256::g1mul(&mut P, &mut s);
+ g = pair256::ate(&mut Q, &mut P);
+ g = pair256::fexp(&g);
+
+ P.copy(&G);
+ Q = pair256::g2mul(&mut Q, &mut s);
+ w = pair256::ate(&mut Q, &mut P);
+ w = pair256::fexp(&w);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,sP) ");
+ fail = true;
+ }
+
+ Q.copy(&W);
+ g = pair256::ate(&mut Q, &mut P);
+ g = pair256::fexp(&g);
+ g = pair256::gtpow(&mut g, &mut s);
+
+ if !g.equals(&mut w) {
+ println!("FAILURE - e(sQ,p)!=e(Q,P)^s ");
+ fail = true;
+ }
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+fn rsa2048(mut rng: &mut RAND) {
+ use amcl::rsa2048::ff;
+ use amcl::rsa2048::rsa;
+ let mut pbc = rsa::new_public_key(ff::FFLEN);
+ let mut prv = rsa::new_private_key(ff::HFLEN);
+ let mut c: [u8; rsa::RFS] = [0; rsa::RFS];
+ let mut m: [u8; rsa::RFS] = [0; rsa::RFS];
+ let mut p: [u8; rsa::RFS] = [0; rsa::RFS];
+
+ let mut fail = false;
+ println!("\nTesting/Timing 2048-bit RSA");
+ println!("Generating 2048 -bit RSA public/private key pair");
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ rsa::key_pair(&mut rng, 65537, &mut prv, &mut pbc);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("RSA gen - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ for i in 0..rsa::RFS {
+ m[i] = (i % 128) as u8;
+ }
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ rsa::encrypt(&pbc, &m, &mut c);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("RSA enc - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let start = Instant::now();
+ let mut iterations = 0;
+ let mut dur = 0 as u64;
+ while dur < (MIN_TIME as u64) * 1000 || iterations < MIN_ITERS {
+ rsa::decrypt(&prv, &c, &mut p);
+ iterations += 1;
+ let elapsed = start.elapsed();
+ dur = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
+ }
+ let duration = (dur as f64) / (iterations as f64);
+ print!("RSA dec - {:} iterations ", iterations);
+ println!(" {:0.2} ms per iteration", duration);
+
+ let mut cmp = true;
+ for i in 0..rsa::RFS {
+ if p[i] != m[i] {
+ cmp = false;
+ }
+ }
+
+ if !cmp {
+ println!("FAILURE - RSA decryption");
+ fail = true;
+ }
+
+ if !fail {
+ println!("All tests pass");
+ }
+}
+
+#[allow(non_snake_case)]
+//#[test]
+fn main() {
+ let mut raw: [u8; 100] = [0; 100];
+
+ let mut rng = RAND::new();
+ rng.clean();
+ for i in 0..100 {
+ raw[i] = i as u8
+ }
+
+ rng.seed(100, &raw);
+
+ ed25519(&mut rng);
+ nist256(&mut rng);
+ goldilocks(&mut rng);
+ bn254(&mut rng);
+ bls383(&mut rng);
+ bls24(&mut rng);
+ bls48(&mut rng);
+ rsa2048(&mut rng);
+}
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..ccba62a
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "amcl"
+version = "0.2.0"
+
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..b3a8fa8
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,46 @@
+[package]
+name = "amcl"
+version = "0.2.0"
+authors = ["Nikita Khateev <nikita.khateev@dsr-corporation.com>"]
+
+description = "The Apache Milagro Cryptographic Library (version 3)"
+license = "Apache-2.0"
+repository = "https://github.com/milagro-crypto/amcl"
+
+[dependencies]
+
+[lib]
+name = "amcl"
+path = "src/lib.rs"
+
+[features]
+default = ["bn254"]
+bn254 = []
+bn254cx = []
+ansii = []
+bls24 = []
+bls48 = []
+bls381 = []
+bls383 = []
+bls461 = []
+brainpool = []
+c25519 = []
+c41417 = []
+ed25519 = []
+fp256Bn = []
+fp512BN = []
+goldilocks = []
+hifive = []
+nist256 = []
+nist384 = []
+nist521 = []
+nums256e = []
+nums256w = []
+nums384e = []
+nums384w = []
+nums512e = []
+nums512w = []
+secp256k1 = []
+rsa2048 = []
+rsa3072 = []
+rsa4096 = []
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/TestALL.rs b/TestALL.rs
new file mode 100644
index 0000000..2dbf276
--- /dev/null
+++ b/TestALL.rs
@@ -0,0 +1,1459 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+extern crate amcl;
+
+use std::io;
+use std::str;
+
+use amcl::rand::RAND;
+use amcl::types::CurveType;
+
+pub fn printbinary(array: &[u8]) {
+ for i in 0..array.len() {
+ print!("{:02X}", array[i])
+ }
+ println!("")
+}
+
+fn ecdh_ed25519(mut rng: &mut RAND) {
+ //use amcl::ed25519;
+ use amcl::ed25519::ecdh;
+ use amcl::ed25519::ecp;
+
+ let pw = "M0ng00se";
+ let pp: &[u8] = b"M0ng00se";
+ const EFS: usize = ecdh::EFS;
+ const EGS: usize = ecdh::EGS;
+ const EAS: usize = ecp::AESKEY;
+
+ let sha = ecp::HASH_TYPE;
+ let mut salt: [u8; 8] = [0; 8];
+ let mut s1: [u8; EGS] = [0; EGS];
+ let mut w0: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut w1: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut z0: [u8; EFS] = [0; EFS];
+ let mut z1: [u8; EFS] = [0; EFS];
+ let mut key: [u8; EAS] = [0; EAS];
+ let mut cs: [u8; EGS] = [0; EGS];
+ let mut ds: [u8; EGS] = [0; EGS];
+ let mut m: Vec<u8> = vec![0; 32]; // array that could be of any length. So use heap.
+ let mut p1: [u8; 3] = [0; 3];
+ let mut p2: [u8; 4] = [0; 4];
+ let mut v: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut t: [u8; 12] = [0; 12];
+
+ for i in 0..8 {
+ salt[i] = (i + 1) as u8
+ } // set Salt
+
+ println!("\nTesting ECDH/ECDSA/ECIES");
+ println!("Alice's Passphrase= {}", pw);
+
+ let mut s0: [u8; EFS] = [0; EGS];
+ ecdh::pbkdf2(sha, pp, &salt, 1000, EGS, &mut s0);
+
+ print!("Alice's private key= 0x");
+ printbinary(&s0);
+
+ /* Generate Key pair S/W */
+ ecdh::key_pair_generate(None, &mut s0, &mut w0);
+
+ print!("Alice's public key= 0x");
+ printbinary(&w0);
+
+ let mut res = ecdh::public_key_validate(&w0);
+ if res != 0 {
+ println!("ECP Public Key is invalid!");
+ return;
+ }
+
+ /* Random private key for other party */
+ ecdh::key_pair_generate(Some(&mut rng), &mut s1, &mut w1);
+
+ print!("Servers private key= 0x");
+ printbinary(&s1);
+
+ print!("Servers public key= 0x");
+ printbinary(&w1);
+
+ res = ecdh::public_key_validate(&w1);
+ if res != 0 {
+ println!("ECP Public Key is invalid!");
+ return;
+ }
+ /* Calculate common key using DH - IEEE 1363 method */
+
+ ecdh::ecpsvdp_dh(&s0, &w1, &mut z0);
+ ecdh::ecpsvdp_dh(&s1, &w0, &mut z1);
+
+ let mut same = true;
+ for i in 0..EFS {
+ if z0[i] != z1[i] {
+ same = false
+ }
+ }
+
+ if !same {
+ println!("*** ECPSVDP-DH Failed");
+ return;
+ }
+
+ ecdh::kdf2(sha, &z0, None, EAS, &mut key);
+
+ print!("Alice's DH Key= 0x");
+ printbinary(&key);
+ print!("Servers DH Key= 0x");
+ printbinary(&key);
+
+ if ecp::CURVETYPE != CurveType::MONTGOMERY {
+ for i in 0..17 {
+ m[i] = i as u8
+ }
+
+ println!("Testing ECIES");
+
+ p1[0] = 0x0;
+ p1[1] = 0x1;
+ p1[2] = 0x2;
+ p2[0] = 0x0;
+ p2[1] = 0x1;
+ p2[2] = 0x2;
+ p2[3] = 0x3;
+
+ let cc = ecdh::ecies_encrypt(sha, &p1, &p2, &mut rng, &w1, &m[0..17], &mut v, &mut t);
+
+ if let Some(mut c) = cc {
+ println!("Ciphertext= ");
+ print!("V= 0x");
+ printbinary(&v);
+ print!("C= 0x");
+ printbinary(&c);
+ print!("T= 0x");
+ printbinary(&t);
+
+ let mm = ecdh::ecies_decrypt(sha, &p1, &p2, &v, &mut c, &t, &s1);
+ if let Some(rm) = mm {
+ println!("Decryption succeeded");
+ print!("Message is 0x");
+ printbinary(&rm);
+ } else {
+ println!("*** ECIES Decryption Failed");
+ return;
+ }
+ } else {
+ println!("*** ECIES Encryption Failed");
+ return;
+ }
+
+ println!("Testing ECDSA");
+
+ if ecdh::ecpsp_dsa(sha, &mut rng, &s0, &m[0..17], &mut cs, &mut ds) != 0 {
+ println!("***ECDSA Signature Failed");
+ return;
+ }
+ println!("Signature= ");
+ print!("C= 0x");
+ printbinary(&cs);
+ print!("D= 0x");
+ printbinary(&ds);
+
+ if ecdh::ecpvp_dsa(sha, &w0, &m[0..17], &cs, &ds) != 0 {
+ println!("***ECDSA Verification Failed");
+ return;
+ } else {
+ println!("ECDSA Signature/Verification succeeded ")
+ }
+ }
+}
+
+fn ecdh_nist256(mut rng: &mut RAND) {
+ //use amcl::nist256;
+ use amcl::nist256::ecdh;
+ use amcl::nist256::ecp;
+
+ let pw = "M0ng00se";
+ let pp: &[u8] = b"M0ng00se";
+ const EFS: usize = ecdh::EFS;
+ const EGS: usize = ecdh::EGS;
+ const EAS: usize = ecp::AESKEY;
+
+ let sha = ecp::HASH_TYPE;
+ let mut salt: [u8; 8] = [0; 8];
+ let mut s1: [u8; EGS] = [0; EGS];
+ let mut w0: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut w1: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut z0: [u8; EFS] = [0; EFS];
+ let mut z1: [u8; EFS] = [0; EFS];
+ let mut key: [u8; EAS] = [0; EAS];
+ let mut cs: [u8; EGS] = [0; EGS];
+ let mut ds: [u8; EGS] = [0; EGS];
+ let mut m: Vec<u8> = vec![0; 32]; // array that could be of any length. So use heap.
+ let mut p1: [u8; 3] = [0; 3];
+ let mut p2: [u8; 4] = [0; 4];
+ let mut v: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut t: [u8; 12] = [0; 12];
+
+ for i in 0..8 {
+ salt[i] = (i + 1) as u8
+ } // set Salt
+
+ println!("\nTesting ECDH/ECDSA/ECIES");
+ println!("Alice's Passphrase= {}", pw);
+
+ let mut s0: [u8; EFS] = [0; EGS];
+ ecdh::pbkdf2(sha, pp, &salt, 1000, EGS, &mut s0);
+
+ print!("Alice's private key= 0x");
+ printbinary(&s0);
+
+ /* Generate Key pair S/W */
+ ecdh::key_pair_generate(None, &mut s0, &mut w0);
+
+ print!("Alice's public key= 0x");
+ printbinary(&w0);
+
+ let mut res = ecdh::public_key_validate(&w0);
+ if res != 0 {
+ println!("ECP Public Key is invalid!");
+ return;
+ }
+
+ /* Random private key for other party */
+ ecdh::key_pair_generate(Some(&mut rng), &mut s1, &mut w1);
+
+ print!("Servers private key= 0x");
+ printbinary(&s1);
+
+ print!("Servers public key= 0x");
+ printbinary(&w1);
+
+ res = ecdh::public_key_validate(&w1);
+ if res != 0 {
+ println!("ECP Public Key is invalid!");
+ return;
+ }
+ /* Calculate common key using DH - IEEE 1363 method */
+
+ ecdh::ecpsvdp_dh(&s0, &w1, &mut z0);
+ ecdh::ecpsvdp_dh(&s1, &w0, &mut z1);
+
+ let mut same = true;
+ for i in 0..EFS {
+ if z0[i] != z1[i] {
+ same = false
+ }
+ }
+
+ if !same {
+ println!("*** ECPSVDP-DH Failed");
+ return;
+ }
+
+ ecdh::kdf2(sha, &z0, None, EAS, &mut key);
+
+ print!("Alice's DH Key= 0x");
+ printbinary(&key);
+ print!("Servers DH Key= 0x");
+ printbinary(&key);
+
+ if ecp::CURVETYPE != CurveType::MONTGOMERY {
+ for i in 0..17 {
+ m[i] = i as u8
+ }
+
+ println!("Testing ECIES");
+
+ p1[0] = 0x0;
+ p1[1] = 0x1;
+ p1[2] = 0x2;
+ p2[0] = 0x0;
+ p2[1] = 0x1;
+ p2[2] = 0x2;
+ p2[3] = 0x3;
+
+ let cc = ecdh::ecies_encrypt(sha, &p1, &p2, &mut rng, &w1, &m[0..17], &mut v, &mut t);
+
+ if let Some(mut c) = cc {
+ println!("Ciphertext= ");
+ print!("V= 0x");
+ printbinary(&v);
+ print!("C= 0x");
+ printbinary(&c);
+ print!("T= 0x");
+ printbinary(&t);
+
+ let mm = ecdh::ecies_decrypt(sha, &p1, &p2, &v, &mut c, &t, &s1);
+ if let Some(rm) = mm {
+ println!("Decryption succeeded");
+ print!("Message is 0x");
+ printbinary(&rm);
+ } else {
+ println!("*** ECIES Decryption Failed");
+ return;
+ }
+ } else {
+ println!("*** ECIES Encryption Failed");
+ return;
+ }
+
+ println!("Testing ECDSA");
+
+ if ecdh::ecpsp_dsa(sha, &mut rng, &s0, &m[0..17], &mut cs, &mut ds) != 0 {
+ println!("***ECDSA Signature Failed");
+ return;
+ }
+ println!("Signature= ");
+ print!("C= 0x");
+ printbinary(&cs);
+ print!("D= 0x");
+ printbinary(&ds);
+
+ if ecdh::ecpvp_dsa(sha, &w0, &m[0..17], &cs, &ds) != 0 {
+ println!("***ECDSA Verification Failed");
+ return;
+ } else {
+ println!("ECDSA Signature/Verification succeeded ")
+ }
+ }
+}
+
+fn ecdh_goldilocks(mut rng: &mut RAND) {
+ //use amcl::goldilocks;
+ use amcl::goldilocks::ecdh;
+ use amcl::goldilocks::ecp;
+
+ let pw = "M0ng00se";
+ let pp: &[u8] = b"M0ng00se";
+ const EFS: usize = ecdh::EFS;
+ const EGS: usize = ecdh::EGS;
+ const EAS: usize = ecp::AESKEY;
+
+ let sha = ecp::HASH_TYPE;
+ let mut salt: [u8; 8] = [0; 8];
+ let mut s1: [u8; EGS] = [0; EGS];
+ let mut w0: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut w1: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut z0: [u8; EFS] = [0; EFS];
+ let mut z1: [u8; EFS] = [0; EFS];
+ let mut key: [u8; EAS] = [0; EAS];
+ let mut cs: [u8; EGS] = [0; EGS];
+ let mut ds: [u8; EGS] = [0; EGS];
+ let mut m: Vec<u8> = vec![0; 32]; // array that could be of any length. So use heap.
+ let mut p1: [u8; 3] = [0; 3];
+ let mut p2: [u8; 4] = [0; 4];
+ let mut v: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+ let mut t: [u8; 12] = [0; 12];
+
+ for i in 0..8 {
+ salt[i] = (i + 1) as u8
+ } // set Salt
+
+ println!("\nTesting ECDH/ECDSA/ECIES");
+ println!("Alice's Passphrase= {}", pw);
+
+ let mut s0: [u8; EFS] = [0; EGS];
+ ecdh::pbkdf2(sha, pp, &salt, 1000, EGS, &mut s0);
+
+ print!("Alice's private key= 0x");
+ printbinary(&s0);
+
+ /* Generate Key pair S/W */
+ ecdh::key_pair_generate(None, &mut s0, &mut w0);
+
+ print!("Alice's public key= 0x");
+ printbinary(&w0);
+
+ let mut res = ecdh::public_key_validate(&w0);
+ if res != 0 {
+ println!("ECP Public Key is invalid!");
+ return;
+ }
+
+ /* Random private key for other party */
+ ecdh::key_pair_generate(Some(&mut rng), &mut s1, &mut w1);
+
+ print!("Servers private key= 0x");
+ printbinary(&s1);
+
+ print!("Servers public key= 0x");
+ printbinary(&w1);
+
+ res = ecdh::public_key_validate(&w1);
+ if res != 0 {
+ println!("ECP Public Key is invalid!");
+ return;
+ }
+ /* Calculate common key using DH - IEEE 1363 method */
+
+ ecdh::ecpsvdp_dh(&s0, &w1, &mut z0);
+ ecdh::ecpsvdp_dh(&s1, &w0, &mut z1);
+
+ let mut same = true;
+ for i in 0..EFS {
+ if z0[i] != z1[i] {
+ same = false
+ }
+ }
+
+ if !same {
+ println!("*** ECPSVDP-DH Failed");
+ return;
+ }
+
+ ecdh::kdf2(sha, &z0, None, EAS, &mut key);
+
+ print!("Alice's DH Key= 0x");
+ printbinary(&key);
+ print!("Servers DH Key= 0x");
+ printbinary(&key);
+
+ if ecp::CURVETYPE != CurveType::MONTGOMERY {
+ for i in 0..17 {
+ m[i] = i as u8
+ }
+
+ println!("Testing ECIES");
+
+ p1[0] = 0x0;
+ p1[1] = 0x1;
+ p1[2] = 0x2;
+ p2[0] = 0x0;
+ p2[1] = 0x1;
+ p2[2] = 0x2;
+ p2[3] = 0x3;
+
+ let cc = ecdh::ecies_encrypt(sha, &p1, &p2, &mut rng, &w1, &m[0..17], &mut v, &mut t);
+
+ if let Some(mut c) = cc {
+ println!("Ciphertext= ");
+ print!("V= 0x");
+ printbinary(&v);
+ print!("C= 0x");
+ printbinary(&c);
+ print!("T= 0x");
+ printbinary(&t);
+
+ let mm = ecdh::ecies_decrypt(sha, &p1, &p2, &v, &mut c, &t, &s1);
+ if let Some(rm) = mm {
+ println!("Decryption succeeded");
+ print!("Message is 0x");
+ printbinary(&rm);
+ } else {
+ println!("*** ECIES Decryption Failed");
+ return;
+ }
+ } else {
+ println!("*** ECIES Encryption Failed");
+ return;
+ }
+
+ println!("Testing ECDSA");
+
+ if ecdh::ecpsp_dsa(sha, &mut rng, &s0, &m[0..17], &mut cs, &mut ds) != 0 {
+ println!("***ECDSA Signature Failed");
+ return;
+ }
+ println!("Signature= ");
+ print!("C= 0x");
+ printbinary(&cs);
+ print!("D= 0x");
+ printbinary(&ds);
+
+ if ecdh::ecpvp_dsa(sha, &w0, &m[0..17], &cs, &ds) != 0 {
+ println!("***ECDSA Verification Failed");
+ return;
+ } else {
+ println!("ECDSA Signature/Verification succeeded ")
+ }
+ }
+}
+
+fn mpin_bn254(mut rng: &mut RAND) {
+ //use amcl::bn254;
+ use amcl::bn254::ecp;
+ use amcl::bn254::mpin;
+ pub const PERMITS: bool = true;
+ pub const PINERROR: bool = true;
+ pub const FULL: bool = true;
+ //pub const SINGLE_PASS:bool=false;
+
+ const EFS: usize = mpin::EFS;
+ const EGS: usize = mpin::EGS;
+
+ let mut s: [u8; EGS] = [0; EGS];
+ const RM: usize = EFS as usize;
+ let mut hcid: [u8; RM] = [0; RM];
+ let mut hsid: [u8; RM] = [0; RM];
+
+ const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+ const G2S: usize = 4 * EFS; /* Group 2 Size */
+ const EAS: usize = ecp::AESKEY;
+
+ let mut sst: [u8; G2S] = [0; G2S];
+ let mut token: [u8; G1S] = [0; G1S];
+ let mut permit: [u8; G1S] = [0; G1S];
+ let mut g1: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut g2: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut xid: [u8; G1S] = [0; G1S];
+ let mut xcid: [u8; G1S] = [0; G1S];
+ let mut x: [u8; EGS] = [0; EGS];
+ let mut y: [u8; EGS] = [0; EGS];
+ let mut sec: [u8; G1S] = [0; G1S];
+ let mut r: [u8; EGS] = [0; EGS];
+ let mut z: [u8; G1S] = [0; G1S];
+ let mut hid: [u8; G1S] = [0; G1S];
+ let mut htid: [u8; G1S] = [0; G1S];
+ let mut rhid: [u8; G1S] = [0; G1S];
+ let mut w: [u8; EGS] = [0; EGS];
+ let mut t: [u8; G1S] = [0; G1S];
+ let mut e: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut f: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut h: [u8; RM] = [0; RM];
+ let mut ck: [u8; EAS] = [0; EAS];
+ let mut sk: [u8; EAS] = [0; EAS];
+
+ let sha = ecp::HASH_TYPE;
+
+ println!("\nTesting MPIN - PIN is 1234");
+ /* Trusted Authority set-up */
+
+ mpin::random_generate(&mut rng, &mut s);
+ print!("Master Secret s: 0x");
+ printbinary(&s);
+
+ /* Create Client Identity */
+ let name = "testUser@miracl.com";
+ let client_id = name.as_bytes();
+
+ print!("Client ID= ");
+ printbinary(&client_id);
+
+ mpin::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+ /* Client and Server are issued secrets by DTA */
+ mpin::get_server_secret(&s, &mut sst);
+ print!("Server Secret SS: 0x");
+ printbinary(&sst);
+
+ mpin::get_client_secret(&mut s, &hcid, &mut token);
+ print!("Client Secret CS: 0x");
+ printbinary(&token);
+
+ /* Client extracts PIN from secret to create Token */
+ let pin: i32 = 1234;
+ println!("Client extracts PIN= {}", pin);
+ let mut rtn = mpin::extract_pin(sha, &client_id, pin, &mut token);
+ if rtn != 0 {
+ println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+ }
+
+ print!("Client Token TK: 0x");
+ printbinary(&token);
+
+ if FULL {
+ mpin::precompute(&token, &hcid, &mut g1, &mut g2);
+ }
+
+ let mut date = 0;
+ if PERMITS {
+ date = mpin::today();
+ /* Client gets "Time Token" permit from DTA */
+
+ mpin::get_client_permit(sha, date, &s, &hcid, &mut permit);
+ print!("Time Permit TP: 0x");
+ printbinary(&permit);
+
+ /* This encoding makes Time permit look random - Elligator squared */
+ mpin::encoding(&mut rng, &mut permit);
+ print!("Encoded Time Permit TP: 0x");
+ printbinary(&permit);
+ mpin::decoding(&mut permit);
+ print!("Decoded Time Permit TP: 0x");
+ printbinary(&permit);
+ }
+
+ print!("\nPIN= ");
+ let _ = io::Write::flush(&mut io::stdout());
+ let mut input_text = String::new();
+ let _ = io::stdin().read_line(&mut input_text);
+
+ let pin = input_text.trim().parse::<usize>().unwrap();
+
+ println!("MPIN Multi Pass");
+ /* Send U=x.ID to server, and recreate secret from token and pin */
+ rtn = mpin::client_1(
+ sha,
+ date,
+ &client_id,
+ Some(&mut rng),
+ &mut x,
+ pin,
+ &token,
+ &mut sec,
+ Some(&mut xid[..]),
+ Some(&mut xcid[..]),
+ Some(&permit[..]),
+ );
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+ }
+
+ if FULL {
+ mpin::hash_id(sha, &client_id, &mut hcid);
+ mpin::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+ }
+
+ /* Server calculates H(ID) and H(T|H(ID)) (if time mpin::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+ mpin::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+ if date != 0 {
+ rhid.clone_from_slice(&htid[..]);
+ } else {
+ rhid.clone_from_slice(&hid[..]);
+ }
+
+ /* Server generates Random number Y and sends it to Client */
+ mpin::random_generate(&mut rng, &mut y);
+
+ if FULL {
+ mpin::hash_id(sha, &client_id, &mut hsid);
+ mpin::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut t); /* Also send T=w.ID to client, remember random w */
+ }
+
+ /* Client Second Pass: Inputs Client secret SEC, x and y. Outputs -(x+y)*SEC */
+ rtn = mpin::client_2(&x, &y, &mut sec);
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+ }
+
+ /* Server Second pass. Inputs hashed client id, random Y, -(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find error. */
+ /* If PIN error not required, set E and F = null */
+
+ if !PINERROR {
+ rtn = mpin::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ None,
+ None,
+ );
+ } else {
+ rtn = mpin::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ Some(&mut e),
+ Some(&mut f),
+ );
+ }
+
+ if rtn == mpin::BAD_PIN {
+ println!("Server says - Bad Pin. I don't know you. Feck off.");
+ if PINERROR {
+ let err = mpin::kangaroo(&e, &f);
+ if err != 0 {
+ println!("(Client PIN is out by {})", err)
+ }
+ }
+ return;
+ } else {
+ println!("Server says - PIN is good! You really are {}", name);
+ }
+
+ if FULL {
+ let mut pxcid = None;
+ if PERMITS {
+ pxcid = Some(&xcid[..])
+ };
+
+ mpin::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+ print!("Client Key = 0x");
+ printbinary(&ck);
+
+ mpin::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+ print!("Server Key = 0x");
+ printbinary(&sk);
+ }
+}
+
+fn mpin_bls383(mut rng: &mut RAND) {
+ //use amcl::bls383;
+ use amcl::bls383::ecp;
+ use amcl::bls383::mpin;
+ pub const PERMITS: bool = true;
+ pub const PINERROR: bool = true;
+ pub const FULL: bool = true;
+ //pub const SINGLE_PASS:bool=false;
+
+ const EFS: usize = mpin::EFS;
+ const EGS: usize = mpin::EGS;
+
+ let mut s: [u8; EGS] = [0; EGS];
+ const RM: usize = EFS as usize;
+ let mut hcid: [u8; RM] = [0; RM];
+ let mut hsid: [u8; RM] = [0; RM];
+
+ const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+ const G2S: usize = 4 * EFS; /* Group 2 Size */
+ const EAS: usize = ecp::AESKEY;
+
+ let mut sst: [u8; G2S] = [0; G2S];
+ let mut token: [u8; G1S] = [0; G1S];
+ let mut permit: [u8; G1S] = [0; G1S];
+ let mut g1: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut g2: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut xid: [u8; G1S] = [0; G1S];
+ let mut xcid: [u8; G1S] = [0; G1S];
+ let mut x: [u8; EGS] = [0; EGS];
+ let mut y: [u8; EGS] = [0; EGS];
+ let mut sec: [u8; G1S] = [0; G1S];
+ let mut r: [u8; EGS] = [0; EGS];
+ let mut z: [u8; G1S] = [0; G1S];
+ let mut hid: [u8; G1S] = [0; G1S];
+ let mut htid: [u8; G1S] = [0; G1S];
+ let mut rhid: [u8; G1S] = [0; G1S];
+ let mut w: [u8; EGS] = [0; EGS];
+ let mut t: [u8; G1S] = [0; G1S];
+ let mut e: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut f: [u8; 12 * EFS] = [0; 12 * EFS];
+ let mut h: [u8; RM] = [0; RM];
+ let mut ck: [u8; EAS] = [0; EAS];
+ let mut sk: [u8; EAS] = [0; EAS];
+
+ let sha = ecp::HASH_TYPE;
+
+ println!("\nTesting MPIN - PIN is 1234");
+ /* Trusted Authority set-up */
+
+ mpin::random_generate(&mut rng, &mut s);
+ print!("Master Secret s: 0x");
+ printbinary(&s);
+
+ /* Create Client Identity */
+ let name = "testUser@miracl.com";
+ let client_id = name.as_bytes();
+
+ print!("Client ID= ");
+ printbinary(&client_id);
+
+ mpin::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+ /* Client and Server are issued secrets by DTA */
+ mpin::get_server_secret(&s, &mut sst);
+ print!("Server Secret SS: 0x");
+ printbinary(&sst);
+
+ mpin::get_client_secret(&mut s, &hcid, &mut token);
+ print!("Client Secret CS: 0x");
+ printbinary(&token);
+
+ /* Client extracts PIN from secret to create Token */
+ let pin: i32 = 1234;
+ println!("Client extracts PIN= {}", pin);
+ let mut rtn = mpin::extract_pin(sha, &client_id, pin, &mut token);
+ if rtn != 0 {
+ println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+ }
+
+ print!("Client Token TK: 0x");
+ printbinary(&token);
+
+ if FULL {
+ mpin::precompute(&token, &hcid, &mut g1, &mut g2);
+ }
+
+ let mut date = 0;
+ if PERMITS {
+ date = mpin::today();
+ /* Client gets "Time Token" permit from DTA */
+
+ mpin::get_client_permit(sha, date, &s, &hcid, &mut permit);
+ print!("Time Permit TP: 0x");
+ printbinary(&permit);
+
+ /* This encoding makes Time permit look random - Elligator squared */
+ mpin::encoding(&mut rng, &mut permit);
+ print!("Encoded Time Permit TP: 0x");
+ printbinary(&permit);
+ mpin::decoding(&mut permit);
+ print!("Decoded Time Permit TP: 0x");
+ printbinary(&permit);
+ }
+
+ print!("\nPIN= ");
+ let _ = io::Write::flush(&mut io::stdout());
+ let mut input_text = String::new();
+ let _ = io::stdin().read_line(&mut input_text);
+
+ let pin = input_text.trim().parse::<usize>().unwrap();
+
+ println!("MPIN Multi Pass");
+ /* Send U=x.ID to server, and recreate secret from token and pin */
+ rtn = mpin::client_1(
+ sha,
+ date,
+ &client_id,
+ Some(&mut rng),
+ &mut x,
+ pin,
+ &token,
+ &mut sec,
+ Some(&mut xid[..]),
+ Some(&mut xcid[..]),
+ Some(&permit[..]),
+ );
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+ }
+
+ if FULL {
+ mpin::hash_id(sha, &client_id, &mut hcid);
+ mpin::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+ }
+
+ /* Server calculates H(ID) and H(T|H(ID)) (if time mpin::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+ mpin::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+ if date != 0 {
+ rhid.clone_from_slice(&htid[..]);
+ } else {
+ rhid.clone_from_slice(&hid[..]);
+ }
+
+ /* Server generates Random number Y and sends it to Client */
+ mpin::random_generate(&mut rng, &mut y);
+
+ if FULL {
+ mpin::hash_id(sha, &client_id, &mut hsid);
+ mpin::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut t); /* Also send T=w.ID to client, remember random w */
+ }
+
+ /* Client Second Pass: Inputs Client secret SEC, x and y. Outputs -(x+y)*SEC */
+ rtn = mpin::client_2(&x, &y, &mut sec);
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+ }
+
+ /* Server Second pass. Inputs hashed client id, random Y, -(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find error. */
+ /* If PIN error not required, set E and F = null */
+
+ if !PINERROR {
+ rtn = mpin::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ None,
+ None,
+ );
+ } else {
+ rtn = mpin::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ Some(&mut e),
+ Some(&mut f),
+ );
+ }
+
+ if rtn == mpin::BAD_PIN {
+ println!("Server says - Bad Pin. I don't know you. Feck off.");
+ if PINERROR {
+ let err = mpin::kangaroo(&e, &f);
+ if err != 0 {
+ println!("(Client PIN is out by {})", err)
+ }
+ }
+ return;
+ } else {
+ println!("Server says - PIN is good! You really are {}", name);
+ }
+
+ if FULL {
+ let mut pxcid = None;
+ if PERMITS {
+ pxcid = Some(&xcid[..])
+ };
+
+ mpin::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+ print!("Client Key = 0x");
+ printbinary(&ck);
+
+ mpin::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+ print!("Server Key = 0x");
+ printbinary(&sk);
+ }
+}
+
+fn mpin_bls24(mut rng: &mut RAND) {
+ //use amcl::bls24;
+ use amcl::bls24::ecp;
+ use amcl::bls24::mpin192;
+
+ pub const PERMITS: bool = true;
+ pub const PINERROR: bool = true;
+ pub const FULL: bool = true;
+ //pub const SINGLE_PASS:bool=false;
+
+ const EFS: usize = mpin192::EFS;
+ const EGS: usize = mpin192::EGS;
+
+ let mut s: [u8; EGS] = [0; EGS];
+ const RM: usize = EFS as usize;
+ let mut hcid: [u8; RM] = [0; RM];
+ let mut hsid: [u8; RM] = [0; RM];
+
+ const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+ const G2S: usize = 8 * EFS; /* Group 2 Size */
+ const EAS: usize = ecp::AESKEY;
+
+ let mut sst: [u8; G2S] = [0; G2S];
+ let mut token: [u8; G1S] = [0; G1S];
+ let mut permit: [u8; G1S] = [0; G1S];
+ let mut g1: [u8; 24 * EFS] = [0; 24 * EFS];
+ let mut g2: [u8; 24 * EFS] = [0; 24 * EFS];
+ let mut xid: [u8; G1S] = [0; G1S];
+ let mut xcid: [u8; G1S] = [0; G1S];
+ let mut x: [u8; EGS] = [0; EGS];
+ let mut y: [u8; EGS] = [0; EGS];
+ let mut sec: [u8; G1S] = [0; G1S];
+ let mut r: [u8; EGS] = [0; EGS];
+ let mut z: [u8; G1S] = [0; G1S];
+ let mut hid: [u8; G1S] = [0; G1S];
+ let mut htid: [u8; G1S] = [0; G1S];
+ let mut rhid: [u8; G1S] = [0; G1S];
+ let mut w: [u8; EGS] = [0; EGS];
+ let mut t: [u8; G1S] = [0; G1S];
+ let mut e: [u8; 24 * EFS] = [0; 24 * EFS];
+ let mut f: [u8; 24 * EFS] = [0; 24 * EFS];
+ let mut h: [u8; RM] = [0; RM];
+ let mut ck: [u8; EAS] = [0; EAS];
+ let mut sk: [u8; EAS] = [0; EAS];
+
+ let sha = ecp::HASH_TYPE;
+
+ println!("\nTesting MPIN - PIN is 1234");
+ /* Trusted Authority set-up */
+
+ mpin192::random_generate(&mut rng, &mut s);
+ print!("Master Secret s: 0x");
+ printbinary(&s);
+
+ /* Create Client Identity */
+ let name = "testUser@miracl.com";
+ let client_id = name.as_bytes();
+
+ print!("Client ID= ");
+ printbinary(&client_id);
+
+ mpin192::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+ /* Client and Server are issued secrets by DTA */
+ mpin192::get_server_secret(&s, &mut sst);
+ print!("Server Secret SS: 0x");
+ printbinary(&sst);
+
+ mpin192::get_client_secret(&mut s, &hcid, &mut token);
+ print!("Client Secret CS: 0x");
+ printbinary(&token);
+
+ /* Client extracts PIN from secret to create Token */
+ let pin: i32 = 1234;
+ println!("Client extracts PIN= {}", pin);
+ let mut rtn = mpin192::extract_pin(sha, &client_id, pin, &mut token);
+ if rtn != 0 {
+ println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+ }
+
+ print!("Client Token TK: 0x");
+ printbinary(&token);
+
+ if FULL {
+ mpin192::precompute(&token, &hcid, &mut g1, &mut g2);
+ }
+
+ let mut date = 0;
+ if PERMITS {
+ date = mpin192::today();
+ /* Client gets "Time Token" permit from DTA */
+
+ mpin192::get_client_permit(sha, date, &s, &hcid, &mut permit);
+ print!("Time Permit TP: 0x");
+ printbinary(&permit);
+
+ /* This encoding makes Time permit look random - Elligator squared */
+ mpin192::encoding(&mut rng, &mut permit);
+ print!("Encoded Time Permit TP: 0x");
+ printbinary(&permit);
+ mpin192::decoding(&mut permit);
+ print!("Decoded Time Permit TP: 0x");
+ printbinary(&permit);
+ }
+
+ print!("\nPIN= ");
+ let _ = io::Write::flush(&mut io::stdout());
+ let mut input_text = String::new();
+ let _ = io::stdin().read_line(&mut input_text);
+
+ let pin = input_text.trim().parse::<usize>().unwrap();
+
+ println!("MPIN Multi Pass");
+ /* Send U=x.ID to server, and recreate secret from token and pin */
+ rtn = mpin192::client_1(
+ sha,
+ date,
+ &client_id,
+ Some(&mut rng),
+ &mut x,
+ pin,
+ &token,
+ &mut sec,
+ Some(&mut xid[..]),
+ Some(&mut xcid[..]),
+ Some(&permit[..]),
+ );
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+ }
+
+ if FULL {
+ mpin192::hash_id(sha, &client_id, &mut hcid);
+ mpin192::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+ }
+
+ /* Server calculates H(ID) and H(T|H(ID)) (if time mpin192::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+ mpin192::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+ if date != 0 {
+ rhid.clone_from_slice(&htid[..]);
+ } else {
+ rhid.clone_from_slice(&hid[..]);
+ }
+
+ /* Server generates Random number Y and sends it to Client */
+ mpin192::random_generate(&mut rng, &mut y);
+
+ if FULL {
+ mpin192::hash_id(sha, &client_id, &mut hsid);
+ mpin192::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut t); /* Also send T=w.ID to client, remember random w */
+ }
+
+ /* Client Second Pass: Inputs Client secret SEC, x and y. Outputs -(x+y)*SEC */
+ rtn = mpin192::client_2(&x, &y, &mut sec);
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+ }
+
+ /* Server Second pass. Inputs hashed client id, random Y, -(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find error. */
+ /* If PIN error not required, set E and F = null */
+
+ if !PINERROR {
+ rtn = mpin192::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ None,
+ None,
+ );
+ } else {
+ rtn = mpin192::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ Some(&mut e),
+ Some(&mut f),
+ );
+ }
+
+ if rtn == mpin192::BAD_PIN {
+ println!("Server says - Bad Pin. I don't know you. Feck off.");
+ if PINERROR {
+ let err = mpin192::kangaroo(&e, &f);
+ if err != 0 {
+ println!("(Client PIN is out by {})", err)
+ }
+ }
+ return;
+ } else {
+ println!("Server says - PIN is good! You really are {}", name);
+ }
+
+ if FULL {
+ let mut pxcid = None;
+ if PERMITS {
+ pxcid = Some(&xcid[..])
+ };
+
+ mpin192::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin192::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+ print!("Client Key = 0x");
+ printbinary(&ck);
+
+ mpin192::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin192::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+ print!("Server Key = 0x");
+ printbinary(&sk);
+ }
+}
+
+fn mpin_bls48(mut rng: &mut RAND) {
+ //use amcl::bls48;
+ use amcl::bls48::ecp;
+ use amcl::bls48::mpin256;
+
+ pub const PERMITS: bool = true;
+ pub const PINERROR: bool = true;
+ pub const FULL: bool = true;
+ //pub const SINGLE_PASS:bool=false;
+
+ const EFS: usize = mpin256::EFS;
+ const EGS: usize = mpin256::EGS;
+
+ let mut s: [u8; EGS] = [0; EGS];
+ const RM: usize = EFS as usize;
+ let mut hcid: [u8; RM] = [0; RM];
+ let mut hsid: [u8; RM] = [0; RM];
+
+ const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+ const G2S: usize = 16 * EFS; /* Group 2 Size */
+ const EAS: usize = ecp::AESKEY;
+
+ let mut sst: [u8; G2S] = [0; G2S];
+ let mut token: [u8; G1S] = [0; G1S];
+ let mut permit: [u8; G1S] = [0; G1S];
+ let mut g1: [u8; 48 * EFS] = [0; 48 * EFS];
+ let mut g2: [u8; 48 * EFS] = [0; 48 * EFS];
+ let mut xid: [u8; G1S] = [0; G1S];
+ let mut xcid: [u8; G1S] = [0; G1S];
+ let mut x: [u8; EGS] = [0; EGS];
+ let mut y: [u8; EGS] = [0; EGS];
+ let mut sec: [u8; G1S] = [0; G1S];
+ let mut r: [u8; EGS] = [0; EGS];
+ let mut z: [u8; G1S] = [0; G1S];
+ let mut hid: [u8; G1S] = [0; G1S];
+ let mut htid: [u8; G1S] = [0; G1S];
+ let mut rhid: [u8; G1S] = [0; G1S];
+ let mut w: [u8; EGS] = [0; EGS];
+ let mut t: [u8; G1S] = [0; G1S];
+ let mut e: [u8; 48 * EFS] = [0; 48 * EFS];
+ let mut f: [u8; 48 * EFS] = [0; 48 * EFS];
+ let mut h: [u8; RM] = [0; RM];
+ let mut ck: [u8; EAS] = [0; EAS];
+ let mut sk: [u8; EAS] = [0; EAS];
+
+ let sha = ecp::HASH_TYPE;
+
+ println!("\nTesting MPIN - PIN is 1234");
+ /* Trusted Authority set-up */
+
+ mpin256::random_generate(&mut rng, &mut s);
+ print!("Master Secret s: 0x");
+ printbinary(&s);
+
+ /* Create Client Identity */
+ let name = "testUser@miracl.com";
+ let client_id = name.as_bytes();
+
+ print!("Client ID= ");
+ printbinary(&client_id);
+
+ mpin256::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+ /* Client and Server are issued secrets by DTA */
+ mpin256::get_server_secret(&s, &mut sst);
+ print!("Server Secret SS: 0x");
+ printbinary(&sst);
+
+ mpin256::get_client_secret(&mut s, &hcid, &mut token);
+ print!("Client Secret CS: 0x");
+ printbinary(&token);
+
+ /* Client extracts PIN from secret to create Token */
+ let pin: i32 = 1234;
+ println!("Client extracts PIN= {}", pin);
+ let mut rtn = mpin256::extract_pin(sha, &client_id, pin, &mut token);
+ if rtn != 0 {
+ println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+ }
+
+ print!("Client Token TK: 0x");
+ printbinary(&token);
+
+ if FULL {
+ mpin256::precompute(&token, &hcid, &mut g1, &mut g2);
+ }
+
+ let mut date = 0;
+ if PERMITS {
+ date = mpin256::today();
+ /* Client gets "Time Token" permit from DTA */
+
+ mpin256::get_client_permit(sha, date, &s, &hcid, &mut permit);
+ print!("Time Permit TP: 0x");
+ printbinary(&permit);
+
+ /* This encoding makes Time permit look random - Elligator squared */
+ mpin256::encoding(&mut rng, &mut permit);
+ print!("Encoded Time Permit TP: 0x");
+ printbinary(&permit);
+ mpin256::decoding(&mut permit);
+ print!("Decoded Time Permit TP: 0x");
+ printbinary(&permit);
+ }
+
+ print!("\nPIN= ");
+ let _ = io::Write::flush(&mut io::stdout());
+ let mut input_text = String::new();
+ let _ = io::stdin().read_line(&mut input_text);
+
+ let pin = input_text.trim().parse::<usize>().unwrap();
+
+ println!("MPIN Multi Pass");
+ /* Send U=x.ID to server, and recreate secret from token and pin */
+ rtn = mpin256::client_1(
+ sha,
+ date,
+ &client_id,
+ Some(&mut rng),
+ &mut x,
+ pin,
+ &token,
+ &mut sec,
+ Some(&mut xid[..]),
+ Some(&mut xcid[..]),
+ Some(&permit[..]),
+ );
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+ }
+
+ if FULL {
+ mpin256::hash_id(sha, &client_id, &mut hcid);
+ mpin256::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+ }
+
+ /* Server calculates H(ID) and H(T|H(ID)) (if time mpin256::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+ mpin256::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+ if date != 0 {
+ rhid.clone_from_slice(&htid[..]);
+ } else {
+ rhid.clone_from_slice(&hid[..]);
+ }
+
+ /* Server generates Random number Y and sends it to Client */
+ mpin256::random_generate(&mut rng, &mut y);
+
+ if FULL {
+ mpin256::hash_id(sha, &client_id, &mut hsid);
+ mpin256::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut t); /* Also send T=w.ID to client, remember random w */
+ }
+
+ /* Client Second Pass: Inputs Client secret SEC, x and y. Outputs -(x+y)*SEC */
+ rtn = mpin256::client_2(&x, &y, &mut sec);
+ if rtn != 0 {
+ println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+ }
+
+ /* Server Second pass. Inputs hashed client id, random Y, -(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find error. */
+ /* If PIN error not required, set E and F = null */
+
+ if !PINERROR {
+ rtn = mpin256::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ None,
+ None,
+ );
+ } else {
+ rtn = mpin256::server_2(
+ date,
+ &hid,
+ Some(&htid[..]),
+ &y,
+ &sst,
+ Some(&xid[..]),
+ Some(&xcid[..]),
+ &sec,
+ Some(&mut e),
+ Some(&mut f),
+ );
+ }
+
+ if rtn == mpin256::BAD_PIN {
+ println!("Server says - Bad Pin. I don't know you. Feck off.");
+ if PINERROR {
+ let err = mpin256::kangaroo(&e, &f);
+ if err != 0 {
+ println!("(Client PIN is out by {})", err)
+ }
+ }
+ return;
+ } else {
+ println!("Server says - PIN is good! You really are {}", name);
+ }
+
+ if FULL {
+ let mut pxcid = None;
+ if PERMITS {
+ pxcid = Some(&xcid[..])
+ };
+
+ mpin256::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin256::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+ print!("Client Key = 0x");
+ printbinary(&ck);
+
+ mpin256::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+ mpin256::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+ print!("Server Key = 0x");
+ printbinary(&sk);
+ }
+}
+
+fn rsa_2048(mut rng: &mut RAND) {
+ //use amcl::rsa2048;
+ use amcl::rsa2048::ff;
+ use amcl::rsa2048::rsa;
+
+ let sha = rsa::HASH_TYPE;
+ let message: &[u8] = b"Hello World\n";
+ const RFS: usize = rsa::RFS;
+
+ let mut pbc = rsa::new_public_key(ff::FFLEN);
+ let mut prv = rsa::new_private_key(ff::HFLEN);
+
+ let mut ml: [u8; RFS] = [0; RFS];
+ let mut ms: [u8; RFS] = [0; RFS];
+ let mut c: [u8; RFS] = [0; RFS];
+ let mut s: [u8; RFS] = [0; RFS];
+ let mut e: [u8; RFS] = [0; RFS];
+
+ println!("\nTesting RSA");
+ println!("Generating public/private key pair");
+ rsa::key_pair(&mut rng, 65537, &mut prv, &mut pbc);
+
+ println!("Encrypting test string\n");
+ rsa::oaep_encode(sha, &message, &mut rng, None, &mut e); /* OAEP encode message M to E */
+
+ rsa::encrypt(&pbc, &e, &mut c); /* encrypt encoded message */
+ print!("Ciphertext= 0x");
+ printbinary(&c);
+
+ println!("Decrypting test string");
+ rsa::decrypt(&prv, &c, &mut ml);
+ let mlen = rsa::oaep_decode(sha, None, &mut ml); /* OAEP decode message */
+
+ let mess = str::from_utf8(&ml[0..mlen]).unwrap();
+ print!("{}", &mess);
+
+ println!("Signing message");
+ rsa::pkcs15(sha, message, &mut c);
+
+ rsa::decrypt(&prv, &c, &mut s); /* create signature in S */
+
+ print!("Signature= 0x");
+ printbinary(&s);
+
+ rsa::encrypt(&pbc, &s, &mut ms);
+
+ let mut cmp = true;
+ if c.len() != ms.len() {
+ cmp = false;
+ } else {
+ for j in 0..c.len() {
+ if c[j] != ms[j] {
+ cmp = false
+ }
+ }
+ }
+ if cmp {
+ println!("Signature is valid");
+ } else {
+ println!("Signature is INVALID");
+ }
+
+ rsa::private_key_kill(&mut prv);
+}
+
+//#[test]
+fn main() {
+ let mut raw: [u8; 100] = [0; 100];
+
+ let mut rng = RAND::new();
+ rng.clean();
+ for i in 0..100 {
+ raw[i] = i as u8
+ }
+
+ rng.seed(100, &raw);
+
+ ecdh_ed25519(&mut rng);
+ ecdh_nist256(&mut rng);
+ ecdh_goldilocks(&mut rng);
+ mpin_bn254(&mut rng);
+ mpin_bls383(&mut rng);
+ mpin_bls24(&mut rng);
+ mpin_bls48(&mut rng);
+ rsa_2048(&mut rng);
+}
diff --git a/TestBLS.rs b/TestBLS.rs
new file mode 100644
index 0000000..1a54ee4
--- /dev/null
+++ b/TestBLS.rs
@@ -0,0 +1,190 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+extern crate amcl;
+
+use amcl::rand::RAND;
+
+pub fn printbinary(array: &[u8]) {
+ for i in 0..array.len() {
+ print!("{:02X}", array[i])
+ }
+ println!("")
+}
+
+fn bls_bn254(mut rng: &mut RAND) {
+ use amcl::bn254::bls;
+
+ const BFS: usize = bls::BFS;
+ const BGS: usize = bls::BGS;
+
+ let mut s: [u8; BGS] = [0; BGS];
+
+ const G1S: usize = BFS + 1; /* Group 1 Size */
+ const G2S: usize = 4 * BFS; /* Group 2 Size */
+
+ let mut w: [u8; G2S] = [0; G2S];
+ let mut sig: [u8; G1S] = [0; G1S];
+
+ let m = String::from("This is a test message");
+
+ bls::key_pair_generate(&mut rng, &mut s, &mut w);
+ print!("Private key : 0x");
+ printbinary(&s);
+ print!("Public key : 0x");
+ printbinary(&w);
+
+ bls::sign(&mut sig, &m, &s);
+ print!("Signature : 0x");
+ printbinary(&sig);
+
+ let res = bls::verify(&sig, &m, &w);
+ if res == 0 {
+ println!("Signature is OK");
+ } else {
+ println!("Signature is *NOT* OK");
+ }
+}
+
+fn bls_bls383(mut rng: &mut RAND) {
+ use amcl::bls383::bls;
+
+ const BFS: usize = bls::BFS;
+ const BGS: usize = bls::BGS;
+
+ let mut s: [u8; BGS] = [0; BGS];
+
+ const G1S: usize = BFS + 1; /* Group 1 Size */
+ const G2S: usize = 4 * BFS; /* Group 2 Size */
+
+ let mut w: [u8; G2S] = [0; G2S];
+ let mut sig: [u8; G1S] = [0; G1S];
+
+ let m = String::from("This is a test message");
+
+ bls::key_pair_generate(&mut rng, &mut s, &mut w);
+ print!("Private key : 0x");
+ printbinary(&s);
+ print!("Public key : 0x");
+ printbinary(&w);
+
+ bls::sign(&mut sig, &m, &s);
+ print!("Signature : 0x");
+ printbinary(&sig);
+
+ let res = bls::verify(&sig, &m, &w);
+ if res == 0 {
+ println!("Signature is OK");
+ } else {
+ println!("Signature is *NOT* OK");
+ }
+}
+
+fn bls_bls24(mut rng: &mut RAND) {
+ use amcl::bls24::bls192;
+
+ const BFS: usize = bls192::BFS;
+ const BGS: usize = bls192::BGS;
+
+ let mut s: [u8; BGS] = [0; BGS];
+
+ const G1S: usize = BFS + 1; /* Group 1 Size */
+ const G2S: usize = 8 * BFS; /* Group 2 Size */
+
+ let mut w: [u8; G2S] = [0; G2S];
+ let mut sig: [u8; G1S] = [0; G1S];
+
+ let m = String::from("This is a test message");
+
+ bls192::key_pair_generate(&mut rng, &mut s, &mut w);
+ print!("Private key : 0x");
+ printbinary(&s);
+ print!("Public key : 0x");
+ printbinary(&w);
+
+ bls192::sign(&mut sig, &m, &s);
+ print!("Signature : 0x");
+ printbinary(&sig);
+
+ let res = bls192::verify(&sig, &m, &w);
+ if res == 0 {
+ println!("Signature is OK");
+ } else {
+ println!("Signature is *NOT* OK");
+ }
+}
+
+fn bls_bls48(mut rng: &mut RAND) {
+ use amcl::bls48::bls256;
+
+ const BFS: usize = bls256::BFS;
+ const BGS: usize = bls256::BGS;
+
+ let mut s: [u8; BGS] = [0; BGS];
+
+ const G1S: usize = BFS + 1; /* Group 1 Size */
+ const G2S: usize = 16 * BFS; /* Group 2 Size */
+
+ let mut w: [u8; G2S] = [0; G2S];
+ let mut sig: [u8; G1S] = [0; G1S];
+
+ let m = String::from("This is a test message");
+
+ bls256::key_pair_generate(&mut rng, &mut s, &mut w);
+ print!("Private key : 0x");
+ printbinary(&s);
+ print!("Public key : 0x");
+ printbinary(&w);
+
+ bls256::sign(&mut sig, &m, &s);
+ print!("Signature : 0x");
+ printbinary(&sig);
+
+ let res = bls256::verify(&sig, &m, &w);
+ if res == 0 {
+ println!("Signature is OK");
+ } else {
+ println!("Signature is *NOT* OK");
+ }
+}
+
+fn main() {
+ use amcl::arch;
+
+ let mut raw: [u8; 100] = [0; 100];
+
+ let mut rng = RAND::new();
+ rng.clean();
+ for i in 0..100 {
+ raw[i] = i as u8
+ }
+
+ rng.seed(100, &raw);
+
+ println!("{} bit build", arch::CHUNK);
+
+ println!("Testing BLS signature for curve BN254");
+ bls_bn254(&mut rng);
+ println!("\nTesting BLS signature for curve BLS383");
+ bls_bls383(&mut rng);
+ println!("\nTesting BLS signature for curve BLS24");
+ bls_bls24(&mut rng);
+ println!("\nTesting BLS signature for curve BLS48");
+ bls_bls48(&mut rng);
+}
diff --git a/TestNHS.rs b/TestNHS.rs
new file mode 100644
index 0000000..4e7ed02
--- /dev/null
+++ b/TestNHS.rs
@@ -0,0 +1,77 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+// TestNHS.rs - Tests NewHope Simple API
+
+// See https://eprint.iacr.org/2016/1157 (Alkim, Ducas, Popplemann and Schwabe)
+
+// rustc TestNHS.rs --extern amcl=libamcl.rlib
+
+extern crate amcl;
+
+//use std::str;
+//use std::io;
+
+use amcl::rand::RAND;
+//use amcl::aes;
+use amcl::nhs;
+
+//#[test]
+fn main()
+{
+ let mut raw:[u8;100]=[0;100];
+
+ let mut srng=RAND::new();
+ srng.clean();
+ for i in 0..100 {raw[i]=(i+1) as u8}
+
+ srng.seed(100,&raw);
+
+
+ let mut crng=RAND::new();
+ crng.clean();
+ for i in 0..100 {raw[i]=(i+2) as u8}
+
+ crng.seed(100,&raw);
+
+
+ let mut ss:[u8;1792]=[0;1792];
+ let mut sb:[u8;1824]=[0;1824];
+ let mut uc:[u8;2176]=[0;2176];
+
+ let mut keya:[u8;32]=[0;32];
+ let mut keyb:[u8;32]=[0;32];
+
+ nhs::server_1(&mut srng,&mut sb,&mut ss);
+
+ nhs::client(&mut crng,&sb,&mut uc,&mut keyb);
+
+ nhs::server_2(&ss,&uc,&mut keya);
+
+ for i in 0..keya.len() {
+ print!("{:02X}", keya[i]);
+ }
+ println!("");
+
+ for i in 0..keyb.len() {
+ print!("{:02X}", keyb[i]);
+ }
+ println!("");
+
+}
\ No newline at end of file
diff --git a/deploy.token b/deploy.token
new file mode 100644
index 0000000..32b7050
--- /dev/null
+++ b/deploy.token
@@ -0,0 +1 @@
+1YhwbnDDEE2ZdX8P7g4U9WY3uzKTZHvIk5qKEivXYQbQwtLsugOlh8plPhFuL9M6lQeiHX7GeuQkevsymgXHrXVV5QFB7JtsJmh4tJcIiJ8z+9YWchHmCLRkXWoWgoXxwEGIne48KT3At43gCKJGNFGmYAl00XtgiQ1SAfop0LmImrWWHyDIAxeou6GBSg+S2Gz5+AePf3HDnXCfgX2f+tw/SGlEi6LDAtyoU7+yF584g9d5PK6Ctm7GMCdS4M65mqhcqUkrqy4jGomAkf57/j4zauj2ISmyHcmfkKNFvK2qFlf/vy65hacFV3+nIUYvcAv8aasT5Qx895LsQ3xXmCIJnorqd1c7xeafjQudLwpDlyJs5j82NZUIQn+mMkCuSj5g686gpfuKMNs0Gthl2Z7IzmQWiP5PgDZd/QEx/4Q4jUoy8CtrZu6BCxAK7muLLWaI91gWpducaJKZ6dVHZ5tBz7XHG7NFpqRssCUfIMhganVHQ6HRzeADqYXswkH005uexmKRKBvXFZjvbz3e21uSY4HTWZwmcQH+BWEDjfIqY4g0BOUukZH/bOsHYIcKsRT6eanHCsiDKpGbcRB+s6qSquFgtRohUbncUTU1UpaGGPqRiT21WzkbGhVS/oA9uS+NDgB824f9aNShZ0havjCUEpbIfWV+gQdl/j66aUo=
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..da805e0
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,83 @@
+NOTE: Updated to Rust 2018
+
+NOTE: This version of the library requires Version 1.31+ of Rust for 64-bit
+integer support and for Rust 2018.
+
+Now AMCL version 3 is distributed as a cargo crate.
+
+Namespaces are used to separate different curves.
+
+To build the library and see it in action, copy all of the files in this
+directory and its subdirectories to a fresh root directory.
+
+Then for example execute
+
+cargo rustc --release --features "bn254 bls383 bls24 bls48 ed25519 nist256 goldilocks rsa2048"
+
+This will create a build of the library for the current default target (be it 32 or 64 bits).
+
+(To test a 32-bit environment you can follow the Web Assembly (wasm) readme instructions for rust)
+
+Next copy the library from target/release/libamcl.rlib into the root
+directory and execute
+
+rustc TestALL.rs --extern amcl=libamcl.rlib
+
+rustc TestBLS.rs --extern amcl=libamcl.rlib
+
+rustc BenchtestALL.rs --extern amcl=libamcl.rlib
+
+rustc TestNHS.rs --extern amcl=libamcl.rlib
+
+Finally execute these programs.
+
+To add amcl functionality to your own programs, add a dependency to your
+Cargo.toml file. For example to use the curve bls48, add this dependency
+
+[dependencies]
+
+amcl = { version = "0.2.0", optional = true, default-features = false, features = ["bls48"]}
+
+if published to crates.io, or
+
+amcl = { version = "0.2.0", optional = true, default-features = false, features = ["bls48"], path="your_amcl_location" }
+
+And to use primitives of the needed curve in your source code:
+
+use amcl::bls48::{ECP, ECP8}; //any primitive you need
+
+Full list of features:
+
+* Elliptic Curves
+ * ed25519
+ * c25519
+ * nist256
+ * brainpool
+ * anssi
+ * hifive
+ * goldilocks
+ * nist384
+ * c41417
+ * nist521
+ * nums256w
+ * nums256e
+ * nums384w
+ * nums384e
+ * nums512w
+ * nums512e
+ * secp256k1
+* Pairing-Friendly Elliptic Curves
+ * bn254
+ * bn254CX
+ * bls383
+ * bls381
+ * fp256BN
+ * fp512BN
+ * bls461
+ * bls24
+ * bls48
+
+* RSA
+ * rsa2048
+ * rsa3072
+ * rsa4096
diff --git a/src/aes.rs b/src/aes.rs
new file mode 100644
index 0000000..eedea79
--- /dev/null
+++ b/src/aes.rs
@@ -0,0 +1,772 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+pub const ECB: usize = 0;
+pub const CBC: usize = 1;
+pub const CFB1: usize = 2;
+pub const CFB2: usize = 3;
+pub const CFB4: usize = 5;
+pub const OFB1: usize = 14;
+pub const OFB2: usize = 15;
+pub const OFB4: usize = 17;
+pub const OFB8: usize = 21;
+pub const OFB16: usize = 29;
+pub const CTR1: usize = 30;
+pub const CTR2: usize = 31;
+pub const CTR4: usize = 33;
+pub const CTR8: usize = 37;
+pub const CTR16: usize = 45;
+
+const INCO: [u8; 4] = [0xB, 0xD, 0x9, 0xE]; /* Inverse Coefficients */
+
+const PTAB: [u8; 256] = [
+ 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216, 115,
+ 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217,
+ 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
+ 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, 131, 158, 185, 208,
+ 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240,
+ 11, 29, 39, 105, 187, 214, 97, 163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174,
+ 233, 32, 96, 160, 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195,
+ 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172,
+ 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101, 175,
+ 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176,
+ 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18, 54,
+ 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, 57, 75, 221, 124, 132, 151,
+ 162, 253, 28, 36, 108, 180, 199, 82, 246, 1,
+];
+
+const LTAB: [u8; 256] = [
+ 0, 255, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, 100, 4, 224, 14, 52, 141,
+ 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39, 106, 77, 228,
+ 166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218,
+ 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, 102, 221, 253,
+ 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, 126, 110, 72, 195, 163, 182, 30, 66,
+ 58, 107, 40, 84, 250, 133, 61, 186, 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243,
+ 115, 167, 87, 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, 44,
+ 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23,
+ 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96, 177, 134, 59, 82,
+ 161, 108, 170, 85, 41, 157, 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63,
+ 91, 209, 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, 68, 17, 146,
+ 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, 103, 74, 237, 222, 197, 49, 254,
+ 24, 13, 99, 140, 128, 192, 247, 112, 7,
+];
+
+const FBSUB: [u8; 256] = [
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125,
+ 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235,
+ 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0,
+ 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16,
+ 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129,
+ 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234,
+ 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105,
+ 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65,
+ 153, 45, 15, 176, 84, 187, 22,
+];
+
+const RBSUB: [u8; 256] = [
+ 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130,
+ 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109,
+ 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108,
+ 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140,
+ 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175,
+ 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230,
+ 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26,
+ 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39,
+ 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160,
+ 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119,
+ 214, 38, 225, 105, 20, 99, 85, 33, 12, 125,
+];
+
+const RCO: [u8; 16] = [
+ 1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47,
+];
+
+const FTABLE: [u32; 256] = [
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0xdf2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
+ 0x50303060, 0x3010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
+ 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0xbf0f0fb,
+ 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
+ 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x2f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x8f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+ 0xc040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0xf05050a, 0xb59a9a2f,
+ 0x907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
+ 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+ 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x0, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
+ 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+ 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
+ 0xcf45458a, 0x10f9f9e9, 0x6020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
+ 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x4f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0xef3f3fd, 0x6dd2d2bf,
+ 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
+ 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+ 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
+ 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0xa06060c, 0x6c242448, 0xe45c5cb8,
+ 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
+ 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
+ 0xb46c6cd8, 0xfa5656ac, 0x7f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+ 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
+ 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x5030306, 0x1f6f6f7, 0x120e0e1c,
+ 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
+ 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
+ 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
+ 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c,
+];
+
+const RTABLE: [u32; 256] = [
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b,
+ 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5,
+ 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x2752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b,
+ 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e,
+ 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9,
+ 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566,
+ 0x728ebb2, 0x3c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed,
+ 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4,
+ 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x69f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x55dc471, 0x6fd40604, 0xff155060,
+ 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879,
+ 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x0, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c,
+ 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624,
+ 0xb1670a0c, 0xfe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0xaba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0xb0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14,
+ 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b,
+ 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684,
+ 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177,
+ 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f,
+ 0xe49d3a2c, 0xd927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382,
+ 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb,
+ 0x97826cd, 0xf418596e, 0x1b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x8cfbc21, 0xe6e815ef,
+ 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0xe50cd7f, 0x2ff69117,
+ 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546,
+ 0x4ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d,
+ 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a,
+ 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0xc25e2bc, 0x8b493c28, 0x41950dff,
+ 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0,
+];
+
+pub struct AES {
+ nk: usize,
+ nr: usize,
+ mode: usize,
+ fkey: [u32; 60],
+ rkey: [u32; 60],
+ pub f: [u8; 16],
+}
+
+impl AES {
+ fn rotl8(x: u32) -> u32 {
+ return ((x) << 8) | ((x) >> 24);
+ }
+
+ fn rotl16(x: u32) -> u32 {
+ return ((x) << 16) | ((x) >> 16);
+ }
+
+ fn rotl24(x: u32) -> u32 {
+ return ((x) << 24) | ((x) >> 8);
+ }
+
+ fn pack(b: [u8; 4]) -> u32 {
+ /* pack bytes into a 32-bit Word */
+ return ((((b[3]) & 0xff) as u32) << 24)
+ | ((((b[2]) & 0xff) as u32) << 16)
+ | ((((b[1]) & 0xff) as u32) << 8)
+ | (((b[0]) & 0xff) as u32);
+ }
+
+ fn unpack(a: u32) -> [u8; 4] {
+ /* unpack bytes from a word */
+ let b: [u8; 4] = [
+ (a & 0xff) as u8,
+ ((a >> 8) & 0xff) as u8,
+ ((a >> 16) & 0xff) as u8,
+ ((a >> 24) & 0xff) as u8,
+ ];
+ return b;
+ }
+
+ fn bmul(x: u8, y: u8) -> u8 {
+ /* x.y= AntiLog(Log(x) + Log(y)) */
+ let ix = (x as usize) & 0xff;
+ let iy = (y as usize) & 0xff;
+ let lx = (LTAB[ix] as usize) & 0xff;
+ let ly = (LTAB[iy] as usize) & 0xff;
+
+ if x != 0 && y != 0 {
+ return PTAB[(lx + ly) % 255];
+ } else {
+ return 0;
+ }
+ }
+
+ fn subbyte(a: u32) -> u32 {
+ let mut b = AES::unpack(a);
+ b[0] = FBSUB[b[0] as usize];
+ b[1] = FBSUB[b[1] as usize];
+ b[2] = FBSUB[b[2] as usize];
+ b[3] = FBSUB[b[3] as usize];
+ return AES::pack(b);
+ }
+
+ fn product(x: u32, y: u32) -> u8 {
+ /* dot product of two 4-byte arrays */
+ let xb = AES::unpack(x);
+ let yb = AES::unpack(y);
+
+ return AES::bmul(xb[0], yb[0])
+ ^ AES::bmul(xb[1], yb[1])
+ ^ AES::bmul(xb[2], yb[2])
+ ^ AES::bmul(xb[3], yb[3]);
+ }
+
+ fn invmixcol(x: u32) -> u32 {
+ /* matrix Multiplication */
+ let mut b: [u8; 4] = [0; 4];
+ let mut m = AES::pack(INCO);
+ b[3] = AES::product(m, x);
+ m = AES::rotl24(m);
+ b[2] = AES::product(m, x);
+ m = AES::rotl24(m);
+ b[1] = AES::product(m, x);
+ m = AES::rotl24(m);
+ b[0] = AES::product(m, x);
+ let y = AES::pack(b);
+ return y;
+ }
+
+ fn increment(f: &mut [u8; 16]) {
+ for i in 0..16 {
+ f[i] += 1;
+ if f[i] != 0 {
+ break;
+ }
+ }
+ }
+
+ pub fn new() -> AES {
+ AES {
+ nk: 0,
+ nr: 0,
+ mode: 0,
+ fkey: [0; 60],
+ rkey: [0; 60],
+ f: [0; 16],
+ }
+ }
+
+ /* reset cipher */
+ pub fn reset(&mut self, m: usize, iv: Option<[u8; 16]>) {
+ /* reset mode, or reset iv */
+ self.mode = m;
+ for i in 0..16 {
+ self.f[i] = 0
+ }
+ if self.mode != ECB {
+ if let Some(x) = iv {
+ for i in 0..16 {
+ self.f[i] = x[i]
+ }
+ }
+ }
+ }
+
+ pub fn init(&mut self, m: usize, nkey: usize, key: &[u8], iv: Option<[u8; 16]>) -> bool {
+ /* Key Scheduler. Create expanded encryption key */
+ let mut cipherkey: [u32; 8] = [0; 8];
+ let mut b: [u8; 4] = [0; 4];
+ let nk = nkey / 4;
+ if nk != 4 && nk != 6 && nk != 8 {
+ return false;
+ }
+ let nr = 6 + nk;
+ self.nk = nk;
+ self.nr = nr;
+ self.reset(m, iv);
+ let n = 4 * (nr + 1);
+
+ let mut j = 0;
+ for i in 0..nk {
+ for k in 0..4 {
+ b[k] = key[j + k]
+ }
+ cipherkey[i] = AES::pack(b);
+ j += 4;
+ }
+
+ for i in 0..nk {
+ self.fkey[i] = cipherkey[i]
+ }
+
+ j = nk;
+ let mut k = 0;
+ while j < n {
+ self.fkey[j] =
+ self.fkey[j - nk] ^ AES::subbyte(AES::rotl24(self.fkey[j - 1])) ^ (RCO[k] as u32);
+ if nk<=6 {
+ for i in 1..nk {
+ if (i + j) >= n {
+ break;
+ }
+ self.fkey[i + j] = self.fkey[i + j - nk] ^ self.fkey[i + j - 1];
+ }
+ } else {
+ for i in 1..4 {
+ if (i + j) >= n {
+ break;
+ }
+ self.fkey[i + j] = self.fkey[i + j - nk] ^ self.fkey[i + j - 1];
+ }
+
+ if (j + 4) < n {
+ self.fkey[j + 4] = self.fkey[j + 4 - nk] ^ AES::subbyte(self.fkey[j + 3]);
+ }
+ for i in 5..nk {
+ if (i + j) >= n {
+ break;
+ }
+ self.fkey[i + j] = self.fkey[i + j - nk] ^ self.fkey[i + j - 1];
+ }
+ }
+ j += nk;
+ k += 1;
+ }
+
+ /* now for the expanded decrypt key in reverse order */
+
+ for j in 0..4 {
+ self.rkey[j + n - 4] = self.fkey[j]
+ }
+ let mut i = 4;
+ while i < n - 4 {
+ let k = n - 4 - i;
+ for j in 0..4 {
+ self.rkey[k + j] = AES::invmixcol(self.fkey[i + j])
+ }
+ i += 4;
+ }
+ for j in n - 4..n {
+ self.rkey[j + 4 - n] = self.fkey[j]
+ }
+ return true;
+ }
+
+ pub fn getreg(&mut self) -> [u8; 16] {
+ let mut ir: [u8; 16] = [0; 16];
+ for i in 0..16 {
+ ir[i] = self.f[i]
+ }
+ return ir;
+ }
+
+ /* Encrypt a single block */
+ pub fn ecb_encrypt(&mut self, buff: &mut [u8; 16]) {
+ let mut b: [u8; 4] = [0; 4];
+ let mut p: [u32; 4] = [0; 4];
+ let mut q: [u32; 4] = [0; 4];
+
+ let mut j = 0;
+ for i in 0..4 {
+ for k in 0..4 {
+ b[k] = buff[j + k]
+ }
+ p[i] = AES::pack(b);
+ p[i] ^= self.fkey[i];
+ j += 4;
+ }
+
+ let mut k = 4;
+
+ /* State alternates between p and q */
+ for _ in 1..self.nr {
+ q[0] = self.fkey[k]
+ ^ FTABLE[(p[0] & 0xff) as usize]
+ ^ AES::rotl8(FTABLE[((p[1] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(FTABLE[((p[2] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(FTABLE[((p[3] >> 24) & 0xff) as usize]);
+
+ q[1] = self.fkey[k + 1]
+ ^ FTABLE[(p[1] & 0xff) as usize]
+ ^ AES::rotl8(FTABLE[((p[2] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(FTABLE[((p[3] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(FTABLE[((p[0] >> 24) & 0xff) as usize]);
+
+ q[2] = self.fkey[k + 2]
+ ^ FTABLE[(p[2] & 0xff) as usize]
+ ^ AES::rotl8(FTABLE[((p[3] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(FTABLE[((p[0] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(FTABLE[((p[1] >> 24) & 0xff) as usize]);
+
+ q[3] = self.fkey[k + 3]
+ ^ FTABLE[(p[3] & 0xff) as usize]
+ ^ AES::rotl8(FTABLE[((p[0] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(FTABLE[((p[1] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(FTABLE[((p[2] >> 24) & 0xff) as usize]);
+
+ k += 4;
+ for j in 0..4 {
+ let t = p[j];
+ p[j] = q[j];
+ q[j] = t;
+ }
+ }
+
+ /* Last Round */
+
+ q[0] = self.fkey[k]
+ ^ (FBSUB[(p[0] & 0xff) as usize] as u32)
+ ^ AES::rotl8((FBSUB[((p[1] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((FBSUB[((p[2] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((FBSUB[((p[3] >> 24) & 0xff) as usize]) as u32);
+
+ q[1] = self.fkey[k + 1]
+ ^ (FBSUB[(p[1] & 0xff) as usize] as u32)
+ ^ AES::rotl8((FBSUB[((p[2] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((FBSUB[((p[3] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((FBSUB[((p[0] >> 24) & 0xff) as usize]) as u32);
+
+ q[2] = self.fkey[k + 2]
+ ^ (FBSUB[(p[2] & 0xff) as usize] as u32)
+ ^ AES::rotl8((FBSUB[((p[3] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((FBSUB[((p[0] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((FBSUB[((p[1] >> 24) & 0xff) as usize]) as u32);
+
+ q[3] = self.fkey[k + 3]
+ ^ (FBSUB[(p[3] & 0xff) as usize] as u32)
+ ^ AES::rotl8((FBSUB[((p[0] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((FBSUB[((p[1] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((FBSUB[((p[2] >> 24) & 0xff) as usize]) as u32);
+
+ j = 0;
+ for i in 0..4 {
+ b = AES::unpack(q[i]);
+ for k in 0..4 {
+ buff[j + k] = b[k]
+ }
+ j += 4;
+ }
+ }
+
+ /* Decrypt a single block */
+ pub fn ecb_decrypt(&mut self, buff: &mut [u8; 16]) {
+ let mut b: [u8; 4] = [0; 4];
+ let mut p: [u32; 4] = [0; 4];
+ let mut q: [u32; 4] = [0; 4];
+
+ let mut j = 0;
+ for i in 0..4 {
+ for k in 0..4 {
+ b[k] = buff[j + k]
+ }
+ p[i] = AES::pack(b);
+ p[i] ^= self.rkey[i];
+ j += 4;
+ }
+
+ let mut k = 4;
+
+ /* State alternates between p and q */
+ for _ in 1..self.nr {
+ q[0] = self.rkey[k]
+ ^ RTABLE[(p[0] & 0xff) as usize]
+ ^ AES::rotl8(RTABLE[((p[3] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(RTABLE[((p[2] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(RTABLE[((p[1] >> 24) & 0xff) as usize]);
+
+ q[1] = self.rkey[k + 1]
+ ^ RTABLE[(p[1] & 0xff) as usize]
+ ^ AES::rotl8(RTABLE[((p[0] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(RTABLE[((p[3] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(RTABLE[((p[2] >> 24) & 0xff) as usize]);
+
+ q[2] = self.rkey[k + 2]
+ ^ RTABLE[(p[2] & 0xff) as usize]
+ ^ AES::rotl8(RTABLE[((p[1] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(RTABLE[((p[0] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(RTABLE[((p[3] >> 24) & 0xff) as usize]);
+
+ q[3] = self.rkey[k + 3]
+ ^ RTABLE[(p[3] & 0xff) as usize]
+ ^ AES::rotl8(RTABLE[((p[2] >> 8) & 0xff) as usize])
+ ^ AES::rotl16(RTABLE[((p[1] >> 16) & 0xff) as usize])
+ ^ AES::rotl24(RTABLE[((p[0] >> 24) & 0xff) as usize]);
+
+ k += 4;
+ for j in 0..4 {
+ let t = p[j];
+ p[j] = q[j];
+ q[j] = t;
+ }
+ }
+
+ /* Last Round */
+
+ q[0] = self.rkey[k]
+ ^ (RBSUB[(p[0] & 0xff) as usize] as u32)
+ ^ AES::rotl8((RBSUB[((p[3] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((RBSUB[((p[2] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((RBSUB[((p[1] >> 24) & 0xff) as usize]) as u32);
+
+ q[1] = self.rkey[k + 1]
+ ^ (RBSUB[(p[1] & 0xff) as usize] as u32)
+ ^ AES::rotl8((RBSUB[((p[0] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((RBSUB[((p[3] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((RBSUB[((p[2] >> 24) & 0xff) as usize]) as u32);
+
+ q[2] = self.rkey[k + 2]
+ ^ (RBSUB[(p[2] & 0xff) as usize] as u32)
+ ^ AES::rotl8((RBSUB[((p[1] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((RBSUB[((p[0] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((RBSUB[((p[3] >> 24) & 0xff) as usize]) as u32);
+
+ q[3] = self.rkey[k + 3]
+ ^ (RBSUB[((p[3]) & 0xff) as usize] as u32)
+ ^ AES::rotl8((RBSUB[((p[2] >> 8) & 0xff) as usize]) as u32)
+ ^ AES::rotl16((RBSUB[((p[1] >> 16) & 0xff) as usize]) as u32)
+ ^ AES::rotl24((RBSUB[((p[0] >> 24) & 0xff) as usize]) as u32);
+
+ j = 0;
+ for i in 0..4 {
+ b = AES::unpack(q[i]);
+ for k in 0..4 {
+ buff[j + k] = b[k]
+ }
+ j += 4;
+ }
+ }
+
+ /* Encrypt using selected mode of operation */
+ pub fn encrypt(&mut self, buff: &mut [u8; 16]) -> u32 {
+ let mut st: [u8; 16] = [0; 16];
+
+ // Supported Modes of Operation
+
+ let mut fell_off: u32 = 0;
+
+ match self.mode {
+ ECB => {
+ self.ecb_encrypt(buff);
+ return 0;
+ }
+ CBC => {
+ for j in 0..16 {
+ buff[j] ^= self.f[j]
+ }
+ self.ecb_encrypt(buff);
+ for j in 0..16 {
+ self.f[j] = buff[j]
+ }
+ return 0;
+ }
+
+ CFB1 | CFB2 | CFB4 => {
+ let bytes = self.mode - CFB1 + 1;
+ for j in 0..bytes {
+ fell_off = (fell_off << 8) | (self.f[j] as u32)
+ }
+ for j in 0..16 {
+ st[j] = self.f[j]
+ }
+ for j in bytes..16 {
+ self.f[j - bytes] = self.f[j]
+ }
+ self.ecb_encrypt(&mut st);
+ for j in 0..bytes {
+ buff[j] ^= st[j];
+ self.f[16 - bytes + j] = buff[j];
+ }
+ return fell_off;
+ }
+
+ OFB1 | OFB2 | OFB4 | OFB8 | OFB16 => {
+ let bytes = self.mode - OFB1 + 1;
+ for j in 0..16 {
+ st[j] = self.f[j]
+ }
+ self.ecb_encrypt(&mut st);
+ for j in 0..bytes {
+ buff[j] ^= st[j]
+ }
+ for j in 0..16 {
+ self.f[j] = st[j]
+ }
+
+ //self.ecb_encrypt(&mut (self.f));
+ //for j in 0..bytes {buff[j]^=self.f[j]}
+ return 0;
+ }
+
+ CTR1 | CTR2 | CTR4 | CTR8 | CTR16 => {
+ let bytes = self.mode - CTR1 + 1;
+ for j in 0..16 {
+ st[j] = self.f[j]
+ }
+ self.ecb_encrypt(&mut st);
+ for j in 0..bytes {
+ buff[j] ^= st[j]
+ }
+ AES::increment(&mut (self.f));
+ return 0;
+ }
+
+ _ => {
+ return 0;
+ }
+ }
+ }
+
+ /* Decrypt using selected mode of operation */
+ pub fn decrypt(&mut self, buff: &mut [u8; 16]) -> u32 {
+ let mut st: [u8; 16] = [0; 16];
+
+ // Supported Modes of Operation
+
+ let mut fell_off: u32 = 0;
+
+ match self.mode {
+ ECB => {
+ self.ecb_decrypt(buff);
+ return 0;
+ }
+ CBC => {
+ for j in 0..16 {
+ st[j] = self.f[j];
+ self.f[j] = buff[j];
+ }
+ self.ecb_decrypt(buff);
+ for j in 0..16 {
+ buff[j] ^= st[j];
+ st[j] = 0;
+ }
+ return 0;
+ }
+ CFB1 | CFB2 | CFB4 => {
+ let bytes = self.mode - CFB1 + 1;
+ for j in 0..bytes {
+ fell_off = (fell_off << 8) | (self.f[j] as u32)
+ }
+ for j in 0..16 {
+ st[j] = self.f[j]
+ }
+ for j in bytes..16 {
+ self.f[j - bytes] = self.f[j]
+ }
+ self.ecb_encrypt(&mut st);
+ for j in 0..bytes {
+ self.f[16 - bytes + j] = buff[j];
+ buff[j] ^= st[j];
+ }
+ return fell_off;
+ }
+ OFB1 | OFB2 | OFB4 | OFB8 | OFB16 => {
+ let bytes = self.mode - OFB1 + 1;
+ for j in 0..16 {
+ st[j] = self.f[j]
+ }
+ self.ecb_encrypt(&mut st);
+ for j in 0..bytes {
+ buff[j] ^= st[j]
+ }
+ for j in 0..16 {
+ self.f[j] = st[j]
+ }
+ // self.ecb_encrypt(A.f[:]);
+ // for j in 0..bytes {buff[j]^=self.f[j]}
+ return 0;
+ }
+
+ CTR1 | CTR2 | CTR4 | CTR8 | CTR16 => {
+ let bytes = self.mode - CTR1 + 1;
+ for j in 0..16 {
+ st[j] = self.f[j]
+ }
+ self.ecb_encrypt(&mut st);
+ for j in 0..bytes {
+ buff[j] ^= st[j]
+ }
+ AES::increment(&mut (self.f));
+ return 0;
+ }
+
+ _ => {
+ return 0;
+ }
+ }
+ }
+
+ /* Clean up and delete left-overs */
+ pub fn end(&mut self) {
+ // clean up
+ for i in 0..4 * (self.nr + 1) {
+ self.fkey[i] = 0;
+ self.rkey[i] = 0
+ }
+ for i in 0..16 {
+ self.f[i] = 0
+ }
+ }
+}
+
+/*
+fn main()
+{
+ let mut key:[u8;32]=[0;32];
+ let mut block:[u8;16]=[0;16];
+ let mut iv: [u8;16] = [0;16];
+
+ for i in 0..32 {key[i]=0}
+ key[0]=1;
+ for i in 0..16 {iv[i]=i as u8}
+ for i in 0..16 {block[i]=i as u8}
+
+ let mut aes=AES::new();
+ aes.init(CTR16,32,&key,Some(iv));
+
+ println!("Plain= ");
+ for i in 0..16 {print!("{:02x} ",block[i])}
+ println!("");
+
+ aes.encrypt(&mut block);
+
+ println!("Encrypt= ");
+ for i in 0..16 {print!("{:02x} ",block[i])}
+ println!("");
+
+ aes.reset(CTR16,Some(iv));
+ aes.decrypt(&mut block);
+
+ println!("Decrypt= ");
+ for i in 0..16 {print!("{:02x} ",block[i])}
+ println!("");
+
+ aes.end();
+}
+*/
diff --git a/src/arch/arch32.rs b/src/arch/arch32.rs
new file mode 100644
index 0000000..2df2c97
--- /dev/null
+++ b/src/arch/arch32.rs
@@ -0,0 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+pub type Chunk = i32;
+pub type DChunk = i64;
+pub const CHUNK: usize = 32;
diff --git a/src/arch/arch64.rs b/src/arch/arch64.rs
new file mode 100644
index 0000000..76b95d9
--- /dev/null
+++ b/src/arch/arch64.rs
@@ -0,0 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+pub type Chunk = i64;
+pub type DChunk = i128;
+pub const CHUNK: usize = 64;
diff --git a/src/big.rs b/src/big.rs
new file mode 100644
index 0000000..7267ad4
--- /dev/null
+++ b/src/big.rs
@@ -0,0 +1,1070 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::super::arch;
+use super::super::arch::Chunk;
+
+use super::super::arch::DChunk;
+
+use super::dbig::DBIG;
+use rand::RAND;
+
+pub use super::rom::MODBYTES;
+pub use super::rom::BASEBITS;
+use std::cmp::Ordering;
+use std::fmt;
+
+pub const NLEN: usize = (1 + ((8 * MODBYTES - 1) / BASEBITS));
+pub const DNLEN: usize = 2 * NLEN;
+pub const BMASK: Chunk = ((1 << BASEBITS) - 1);
+pub const HBITS: usize = (BASEBITS / 2);
+pub const HMASK: Chunk = ((1 << HBITS) - 1);
+pub const NEXCESS: isize = (1 << ((arch::CHUNK) - BASEBITS - 1));
+pub const BIGBITS: usize = (MODBYTES * 8);
+
+#[derive(Copy)]
+pub struct BIG {
+ pub w: [Chunk; NLEN],
+}
+
+impl Clone for BIG {
+ fn clone(&self) -> BIG { *self }
+}
+
+impl fmt::Display for BIG {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut big = self.clone();
+ write!(f, "BIG: [ {} ]", big.tostring())
+ }
+}
+
+impl fmt::Debug for BIG {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut big = self.clone();
+ write!(f, "BIG: [ {} ]", big.tostring())
+ }
+}
+
+impl PartialEq for BIG {
+ fn eq(&self, other: &BIG) -> bool {
+ if BIG::comp(self,other)==0 {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+impl Ord for BIG {
+ fn cmp(&self, other: &BIG) -> Ordering {
+ let r = BIG::comp(self, other);
+ if r > 0 {
+ return Ordering::Greater;
+ }
+ if r < 0 {
+ return Ordering::Less;
+ }
+ return Ordering::Equal;
+ }
+}
+
+impl Eq for BIG { }
+
+impl PartialOrd for BIG {
+ fn partial_cmp(&self, other: &BIG) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl BIG {
+ pub fn new() -> BIG {
+ BIG { w: [0; NLEN] }
+ }
+
+ pub fn new_int(x: isize) -> BIG {
+ let mut s = BIG::new();
+ s.w[0] = x as Chunk;
+ return s;
+ }
+
+ pub fn new_ints(a: &[Chunk]) -> BIG {
+ let mut s = BIG::new();
+ for i in 0..NLEN {
+ s.w[i] = a[i]
+ }
+ return s;
+ }
+
+ pub fn new_copy(y: &BIG) -> BIG {
+ let mut s = BIG::new();
+ for i in 0..NLEN {
+ s.w[i] = y.w[i]
+ }
+ return s;
+ }
+
+ pub fn new_big(y: &BIG) -> BIG {
+ let mut s = BIG::new();
+ for i in 0..NLEN {
+ s.w[i] = y.w[i]
+ }
+ return s;
+ }
+
+ pub fn new_dcopy(y: &DBIG) -> BIG {
+ let mut s = BIG::new();
+ for i in 0..NLEN {
+ s.w[i] = y.w[i]
+ }
+ return s;
+ }
+
+ pub fn get(&self, i: usize) -> Chunk {
+ return self.w[i];
+ }
+
+ pub fn set(&mut self, i: usize, x: Chunk) {
+ self.w[i] = x;
+ }
+
+ pub fn xortop(&mut self, x: Chunk) {
+ self.w[NLEN - 1] ^= x;
+ }
+
+ pub fn ortop(&mut self, x: Chunk) {
+ self.w[NLEN - 1] |= x;
+ }
+
+ /* test for zero */
+ pub fn iszilch(&self) -> bool {
+ for i in 0..NLEN {
+ if self.w[i] != 0 {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* set to zero */
+ pub fn zero(&mut self) {
+ for i in 0..NLEN {
+ self.w[i] = 0
+ }
+ }
+
+ /* Test for equal to one */
+ pub fn isunity(&self) -> bool {
+ for i in 1..NLEN {
+ if self.w[i] != 0 {
+ return false;
+ }
+ }
+ if self.w[0] != 1 {
+ return false;
+ }
+ return true;
+ }
+
+ /* set to one */
+ pub fn one(&mut self) {
+ self.w[0] = 1;
+ for i in 1..NLEN {
+ self.w[i] = 0;
+ }
+ }
+
+ /* Copy from another BIG */
+ pub fn copy(&mut self, x: &BIG) {
+ for i in 0..NLEN {
+ self.w[i] = x.w[i]
+ }
+ }
+
+ pub fn dcopy(&mut self, x: &DBIG) {
+ for i in 0..NLEN {
+ self.w[i] = x.w[i]
+ }
+ }
+
+ /* Get top and bottom half of =x*y+c+r */
+ pub fn muladd(a: Chunk, b: Chunk, c: Chunk, r: Chunk) -> (Chunk, Chunk) {
+ let prod: DChunk = (a as DChunk) * (b as DChunk) + (c as DChunk) + (r as DChunk);
+ let bot = (prod & (BMASK as DChunk)) as Chunk;
+ let top = (prod >> BASEBITS) as Chunk;
+ return (top, bot);
+ }
+
+ /* normalise BIG - force all digits < 2^BASEBITS */
+ pub fn norm(&mut self) -> Chunk {
+ let mut carry = 0 as Chunk;
+ for i in 0..NLEN - 1 {
+ let d = self.w[i] + carry;
+ self.w[i] = d & BMASK;
+ carry = d >> BASEBITS;
+ }
+ self.w[NLEN - 1] += carry;
+ return (self.w[NLEN - 1] >> ((8 * MODBYTES) % BASEBITS)) as Chunk;
+ }
+
+ /* Conditional swap of two bigs depending on d using XOR - no branches */
+ pub fn cswap(&mut self, b: &mut BIG, d: isize) {
+ let mut c = d as Chunk;
+ c = !(c - 1);
+ for i in 0..NLEN {
+ let t = c & (self.w[i] ^ b.w[i]);
+ self.w[i] ^= t;
+ b.w[i] ^= t;
+ }
+ }
+
+ pub fn cmove(&mut self, g: &BIG, d: isize) {
+ let b = -d as Chunk;
+ for i in 0..NLEN {
+ self.w[i] ^= (self.w[i] ^ g.w[i]) & b;
+ }
+ }
+
+ /* Shift right by less than a word */
+ pub fn fshr(&mut self, k: usize) -> isize {
+ let n = k;
+ let w = self.w[0] & ((1 << n) - 1); /* shifted out part */
+ for i in 0..NLEN - 1 {
+ self.w[i] = (self.w[i] >> k) | ((self.w[i + 1] << (BASEBITS - n)) & BMASK);
+ }
+ self.w[NLEN - 1] = self.w[NLEN - 1] >> k;
+ return w as isize;
+ }
+
+ /* general shift right */
+ pub fn shr(&mut self, k: usize) {
+ let n = k % BASEBITS;
+ let m = k / BASEBITS;
+ for i in 0..NLEN - m - 1 {
+ self.w[i] = (self.w[m + i] >> n) | ((self.w[m + i + 1] << (BASEBITS - n)) & BMASK)
+ }
+ self.w[NLEN - m - 1] = self.w[NLEN - 1] >> n;
+ for i in NLEN - m..NLEN {
+ self.w[i] = 0
+ }
+ }
+
+ /* Shift right by less than a word */
+ pub fn fshl(&mut self, k: usize) -> isize {
+ let n = k;
+ self.w[NLEN - 1] = (self.w[NLEN - 1] << n) | (self.w[NLEN - 2] >> (BASEBITS - n));
+ for i in (1..NLEN - 1).rev() {
+ self.w[i] = ((self.w[i] << k) & BMASK) | (self.w[i - 1] >> (BASEBITS - n));
+ }
+ self.w[0] = (self.w[0] << n) & BMASK;
+ return (self.w[NLEN - 1] >> ((8 * MODBYTES) % BASEBITS)) as isize; /* return excess - only used in ff.c */
+ }
+
+ /* general shift left */
+ pub fn shl(&mut self, k: usize) {
+ let n = k % BASEBITS;
+ let m = k / BASEBITS;
+
+ self.w[NLEN - 1] = self.w[NLEN - 1 - m] << n;
+ if NLEN >= m + 2 {
+ self.w[NLEN - 1] |= self.w[NLEN - m - 2] >> (BASEBITS - n)
+ }
+ for i in (m + 1..NLEN - 1).rev() {
+ self.w[i] = ((self.w[i - m] << n) & BMASK) | (self.w[i - m - 1] >> (BASEBITS - n));
+ }
+ self.w[m] = (self.w[0] << n) & BMASK;
+ for i in 0..m {
+ self.w[i] = 0
+ }
+ }
+
+ /* return number of bits */
+ pub fn nbits(&self) -> usize {
+ let mut k = NLEN - 1;
+ let mut s = BIG::new_copy(&self);
+ s.norm();
+ while (k as isize) >= 0 && s.w[k] == 0 {
+ k = k.wrapping_sub(1)
+ }
+ if (k as isize) < 0 {
+ return 0;
+ }
+ let mut bts = BASEBITS * k;
+ let mut c = s.w[k];
+ while c != 0 {
+ c /= 2;
+ bts += 1;
+ }
+ return bts;
+ }
+
+ /* Convert to Hex String */
+ pub fn tostring(&mut self) -> String {
+ let mut s = String::new();
+ let mut len = self.nbits();
+
+ if len % 4 == 0 {
+ len /= 4;
+ } else {
+ len /= 4;
+ len += 1;
+ }
+ let mb = (MODBYTES * 2) as usize;
+ if len < mb {
+ len = mb
+ }
+
+ for i in (0..len).rev() {
+ let mut b = BIG::new_copy(&self);
+ b.shr(i * 4);
+ s = s + &format!("{:X}", b.w[0] & 15);
+ }
+ return s;
+ }
+
+ pub fn fromstring(val: String) -> BIG {
+ let mut res = BIG::new();
+ let len = val.len();
+ let op = &val[0..1];
+ let n = u8::from_str_radix(op, 16).unwrap();
+ res.w[0] += n as Chunk;
+ for i in 1..len {
+ res.shl(4);
+ let op = &val[i..i+1];
+ let n = u8::from_str_radix(op, 16).unwrap();
+ res.w[0] += n as Chunk;
+ }
+ return res;
+ }
+
+ pub fn from_hex(val: String) -> BIG {
+ BIG::fromstring(val)
+ }
+
+ pub fn to_hex(&mut self) -> String {
+ self.tostring()
+ }
+
+ pub fn add(&mut self, r: &BIG) {
+ for i in 0..NLEN {
+ self.w[i] += r.w[i]
+ }
+ }
+
+ pub fn or(&mut self, r: &BIG) {
+ for i in 0..NLEN {
+ self.w[i] |= r.w[i]
+ }
+ }
+
+ pub fn dbl(&mut self) {
+ for i in 0..NLEN {
+ self.w[i] += self.w[i]
+ }
+ }
+
+ /* return this+x */
+ pub fn plus(&self, x: &BIG) -> BIG {
+ let mut s = BIG::new();
+ for i in 0..NLEN {
+ s.w[i] = self.w[i] + x.w[i];
+ }
+ return s;
+ }
+
+ pub fn inc(&mut self, x: isize) {
+ self.norm();
+ self.w[0] += x as Chunk;
+ }
+
+ /* return self-x */
+ pub fn minus(&self, x: &BIG) -> BIG {
+ let mut d = BIG::new();
+ for i in 0..NLEN {
+ d.w[i] = self.w[i] - x.w[i];
+ }
+ return d;
+ }
+
+ /* self-=x */
+ pub fn sub(&mut self, x: &BIG) {
+ for i in 0..NLEN {
+ self.w[i] -= x.w[i];
+ }
+ }
+
+ /* reverse subtract this=x-this */
+
+ pub fn rsub(&mut self, x: &BIG) {
+ for i in 0..NLEN {
+ self.w[i] = x.w[i] - self.w[i]
+ }
+ }
+
+ /* self-=x, where x is int */
+ pub fn dec(&mut self, x: isize) {
+ self.norm();
+ self.w[0] -= x as Chunk;
+ }
+
+ /* self*=x, where x is small int<NEXCESS */
+ pub fn imul(&mut self, c: isize) {
+ for i in 0..NLEN {
+ self.w[i] *= c as Chunk;
+ }
+ }
+
+ /* convert this BIG to byte array */
+ pub fn tobytearray(&mut self, b: &mut [u8], n: usize) {
+ let mut c = BIG::new_copy(self);
+ c.norm();
+
+ for i in (0..(MODBYTES as usize)).rev() {
+ b[i + n] = (c.w[0] & 0xff) as u8;
+ c.fshr(8);
+ }
+ }
+
+ /* convert from byte array to BIG */
+ pub fn frombytearray(b: &[u8], n: usize) -> BIG {
+ let mut m = BIG::new();
+ for i in 0..(MODBYTES as usize) {
+ m.fshl(8);
+ m.w[0] += (b[i + n] & 0xff) as Chunk;
+ }
+ return m;
+ }
+
+ pub fn tobytes(&mut self, b: &mut [u8]) {
+ self.tobytearray(b, 0)
+ }
+
+ pub fn frombytes(b: &[u8]) -> BIG {
+ return BIG::frombytearray(b, 0);
+ }
+
+ /* self*=x, where x is >NEXCESS */
+ pub fn pmul(&mut self, c: isize) -> Chunk {
+ let mut carry = 0 as Chunk;
+ for i in 0..NLEN {
+ let ak = self.w[i];
+ let tuple = BIG::muladd(ak, c as Chunk, carry, 0 as Chunk);
+ carry = tuple.0;
+ self.w[i] = tuple.1;
+ }
+ return carry;
+ }
+
+ /* self*=c and catch overflow in DBIG */
+ pub fn pxmul(&mut self, c: isize) -> DBIG {
+ let mut m = DBIG::new();
+ let mut carry = 0 as Chunk;
+ for j in 0..NLEN {
+ let tuple = BIG::muladd(self.w[j], c as Chunk, carry, m.w[j]);
+ carry = tuple.0;
+ m.w[j] = tuple.1;
+ }
+ m.w[NLEN] = carry;
+ return m;
+ }
+
+ /* divide by 3 */
+ pub fn div3(&mut self) -> Chunk {
+ let mut carry = 0 as Chunk;
+ self.norm();
+ let base = 1 << BASEBITS;
+ for i in (0..NLEN).rev() {
+ let ak = carry * base + self.w[i];
+ self.w[i] = ak / 3;
+ carry = ak % 3;
+ }
+ return carry;
+ }
+
+ /* return a*b where result fits in a BIG */
+ pub fn smul(a: &BIG, b: &BIG) -> BIG {
+ let mut c = BIG::new();
+ for i in 0..NLEN {
+ let mut carry = 0 as Chunk;
+ for j in 0..NLEN {
+ if i + j < NLEN {
+ let tuple = BIG::muladd(a.w[i], b.w[j], carry, c.w[i + j]);
+ carry = tuple.0;
+ c.w[i + j] = tuple.1;
+ }
+ }
+ }
+ return c;
+ }
+
+ /* Compare a and b, return 0 if a==b, -1 if a<b, +1 if a>b. Inputs must be normalised */
+ pub fn comp(a: &BIG, b: &BIG) -> isize {
+ for i in (0..NLEN).rev() {
+ if a.w[i] == b.w[i] {
+ continue;
+ }
+ if a.w[i] > b.w[i] {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /* set x = x mod 2^m */
+ pub fn mod2m(&mut self, m: usize) {
+ let wd = m / BASEBITS;
+ let bt = m % BASEBITS;
+ let msk = (1 << bt) - 1;
+ self.w[wd] &= msk;
+ for i in wd + 1..NLEN {
+ self.w[i] = 0
+ }
+ }
+
+ /* Arazi and Qi inversion mod 256 */
+ pub fn invmod256(a: isize) -> isize {
+ let mut t1: isize = 0;
+ let mut c = (a >> 1) & 1;
+ t1 += c;
+ t1 &= 1;
+ t1 = 2 - t1;
+ t1 <<= 1;
+ let mut u = t1 + 1;
+
+ // i=2
+ let mut b = a & 3;
+ t1 = u * b;
+ t1 >>= 2;
+ c = (a >> 2) & 3;
+ let mut t2 = (u * c) & 3;
+ t1 += t2;
+ t1 *= u;
+ t1 &= 3;
+ t1 = 4 - t1;
+ t1 <<= 2;
+ u += t1;
+
+ // i=4
+ b = a & 15;
+ t1 = u * b;
+ t1 >>= 4;
+ c = (a >> 4) & 15;
+ t2 = (u * c) & 15;
+ t1 += t2;
+ t1 *= u;
+ t1 &= 15;
+ t1 = 16 - t1;
+ t1 <<= 4;
+ u += t1;
+
+ return u;
+ }
+
+ /* return parity */
+ pub fn parity(&self) -> isize {
+ return (self.w[0] % 2) as isize;
+ }
+
+ /* return n-th bit */
+ pub fn bit(&self, n: usize) -> isize {
+ if (self.w[n / (BASEBITS as usize)] & (1 << (n % BASEBITS))) > 0 {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ /* return n last bits */
+ pub fn lastbits(&mut self, n: usize) -> isize {
+ let msk = ((1 << n) - 1) as Chunk;
+ self.norm();
+ return (self.w[0] & msk) as isize;
+ }
+
+ /* a=1/a mod 2^256. This is very fast! */
+ pub fn invmod2m(&mut self) {
+ let mut u = BIG::new();
+ let mut b = BIG::new();
+ let mut c = BIG::new();
+
+ u.inc(BIG::invmod256(self.lastbits(8)));
+
+ let mut i = 8;
+ while i < BIGBITS {
+ u.norm();
+ b.copy(self);
+ b.mod2m(i);
+ let mut t1 = BIG::smul(&u, &b);
+ t1.shr(i);
+ c.copy(self);
+ c.shr(i);
+ c.mod2m(i);
+
+ let mut t2 = BIG::smul(&u, &c);
+ t2.mod2m(i);
+ t1.add(&t2);
+ t1.norm();
+ b = BIG::smul(&t1, &u);
+ t1.copy(&b);
+ t1.mod2m(i);
+
+ t2.one();
+ t2.shl(i);
+ t1.rsub(&t2);
+ t1.norm();
+ t1.shl(i);
+ u.add(&t1);
+ i <<= 1;
+ }
+ u.mod2m(BIGBITS);
+ self.copy(&u);
+ self.norm();
+ }
+
+ /* reduce self mod m */
+ pub fn rmod(&mut self, n: &BIG) {
+ let mut k = 0;
+ let mut m = BIG::new_copy(n);
+ let mut r = BIG::new();
+ self.norm();
+ if BIG::comp(self, &m) < 0 {
+ return;
+ }
+ loop {
+ m.fshl(1);
+ k += 1;
+ if BIG::comp(self, &m) < 0 {
+ break;
+ }
+ }
+
+ while k > 0 {
+ m.fshr(1);
+
+ r.copy(self);
+ r.sub(&m);
+ r.norm();
+ self.cmove(
+ &r,
+ (1 - ((r.w[NLEN - 1] >> (arch::CHUNK - 1)) & 1)) as isize,
+ );
+ k -= 1;
+ }
+ }
+
+ /* divide self by m */
+ pub fn div(&mut self, n: &BIG) {
+ let mut k = 0;
+ self.norm();
+ let mut e = BIG::new_int(1);
+ let mut b = BIG::new_copy(self);
+ let mut m = BIG::new_copy(n);
+ let mut r = BIG::new();
+ self.zero();
+
+ while BIG::comp(&b, &m) >= 0 {
+ e.fshl(1);
+ m.fshl(1);
+ k += 1;
+ }
+
+ while k > 0 {
+ m.fshr(1);
+ e.fshr(1);
+
+ r.copy(&b);
+ r.sub(&m);
+ r.norm();
+ let d = (1 - ((r.w[NLEN - 1] >> (arch::CHUNK - 1)) & 1)) as isize;
+ b.cmove(&r, d);
+ r.copy(self);
+ r.add(&e);
+ r.norm();
+ self.cmove(&r, d);
+ k -= 1;
+ }
+ }
+
+ /* get 8*MODBYTES size random number */
+ pub fn random(rng: &mut RAND) -> BIG {
+ let mut m = BIG::new();
+ let mut j = 0;
+ let mut r: u8 = 0;
+ /* generate random BIG */
+
+ for _ in 0..8 * (MODBYTES as usize) {
+ if j == 0 {
+ r = rng.getbyte()
+ } else {
+ r >>= 1
+ }
+
+ let b = (r as Chunk) & 1;
+ m.shl(1);
+ m.w[0] += b;
+ j += 1;
+ j &= 7;
+ }
+ return m;
+ }
+
+ /* Create random BIG in portable way, one bit at a time */
+ pub fn randomnum(q: &BIG, rng: &mut RAND) -> BIG {
+ let mut d = DBIG::new();
+ let mut j = 0;
+ let mut r: u8 = 0;
+ let t = BIG::new_copy(q);
+ for _ in 0..2 * t.nbits() {
+ if j == 0 {
+ r = rng.getbyte();
+ } else {
+ r >>= 1
+ }
+
+ let b = (r as Chunk) & 1;
+ d.shl(1);
+ d.w[0] += b;
+ j += 1;
+ j &= 7;
+ }
+ let m = d.dmod(q);
+ return m;
+ }
+
+ /* Jacobi Symbol (this/p). Returns 0, 1 or -1 */
+ pub fn jacobi(&mut self, p: &BIG) -> isize {
+ let mut m: usize = 0;
+ let mut t = BIG::new();
+ let mut x = BIG::new();
+ let mut n = BIG::new();
+ let zilch = BIG::new();
+ let one = BIG::new_int(1);
+ if p.parity() == 0 || BIG::comp(self, &zilch) == 0 || BIG::comp(p, &one) <= 0 {
+ return 0;
+ }
+ self.norm();
+
+ x.copy(self);
+ n.copy(p);
+ x.rmod(p);
+
+ while BIG::comp(&n, &one) > 0 {
+ if BIG::comp(&x, &zilch) == 0 {
+ return 0;
+ }
+ let n8 = n.lastbits(3) as usize;
+ let mut k = 0;
+ while x.parity() == 0 {
+ k += 1;
+ x.shr(1);
+ }
+ if k % 2 == 1 {
+ m += (n8 * n8 - 1) / 8
+ }
+ m += (n8 - 1) * ((x.lastbits(2) as usize) - 1) / 4;
+ t.copy(&n);
+ t.rmod(&x);
+ n.copy(&x);
+ x.copy(&t);
+ m %= 2;
+ }
+ if m == 0 {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ /* self=1/self mod p. Binary method */
+ pub fn invmodp(&mut self, p: &BIG) {
+ self.rmod(p);
+ let mut u = BIG::new_copy(self);
+ let mut v = BIG::new_copy(p);
+ let mut x1 = BIG::new_int(1);
+ let mut x2 = BIG::new();
+ let mut t = BIG::new();
+ let one = BIG::new_int(1);
+
+ while (BIG::comp(&u, &one) != 0) && (BIG::comp(&v, &one) != 0) {
+ while u.parity() == 0 {
+ u.fshr(1);
+ if x1.parity() != 0 {
+ x1.add(p);
+ x1.norm();
+ }
+ x1.fshr(1);
+ }
+ while v.parity() == 0 {
+ v.fshr(1);
+ if x2.parity() != 0 {
+ x2.add(p);
+ x2.norm();
+ }
+ x2.fshr(1);
+ }
+ if BIG::comp(&u, &v) >= 0 {
+ u.sub(&v);
+ u.norm();
+ if BIG::comp(&x1, &x2) >= 0 {
+ x1.sub(&x2)
+ } else {
+ t.copy(p);
+ t.sub(&x2);
+ x1.add(&t);
+ }
+ x1.norm();
+ } else {
+ v.sub(&u);
+ v.norm();
+ if BIG::comp(&x2, &x1) >= 0 {
+ x2.sub(&x1)
+ } else {
+ t.copy(p);
+ t.sub(&x1);
+ x2.add(&t);
+ }
+ x2.norm();
+ }
+ }
+ if BIG::comp(&u, &one) == 0 {
+ self.copy(&x1)
+ } else {
+ self.copy(&x2)
+ }
+ }
+
+ /* return a*b as DBIG */
+
+ pub fn mul(a: &BIG, b: &BIG) -> DBIG {
+ let mut c = DBIG::new();
+ let rm = BMASK as DChunk;
+ let rb = BASEBITS;
+
+ let mut d: [DChunk; DNLEN] = [0; DNLEN];
+ for i in 0..NLEN {
+ d[i] = (a.w[i] as DChunk) * (b.w[i] as DChunk);
+ }
+ let mut s = d[0];
+ let mut t = s;
+ c.w[0] = (t & rm) as Chunk;
+ let mut co = t >> rb;
+ for k in 1..NLEN {
+ s += d[k];
+ t = co + s;
+ for i in 1 + k / 2..k + 1 {
+ t += ((a.w[i] - a.w[k - i]) as DChunk) * ((b.w[k - i] - b.w[i]) as DChunk)
+ }
+ c.w[k] = (t & rm) as Chunk;
+ co = t >> rb;
+ }
+ for k in NLEN..2 * NLEN - 1 {
+ s -= d[k - NLEN];
+ t = co + s;
+ let mut i = 1 + k / 2;
+ while i < NLEN {
+ t += ((a.w[i] - a.w[k - i]) as DChunk) * ((b.w[k - i] - b.w[i]) as DChunk);
+ i += 1;
+ }
+
+ c.w[k] = (t & rm) as Chunk;
+ co = t >> rb;
+ }
+ c.w[2 * NLEN - 1] = co as Chunk;
+ return c;
+ }
+
+ /* return a^2 as DBIG */
+ pub fn sqr(a: &BIG) -> DBIG {
+ let mut c = DBIG::new();
+ let rm = BMASK as DChunk;
+ let rb = BASEBITS;
+
+ let mut t = (a.w[0] as DChunk) * (a.w[0] as DChunk);
+ c.w[0] = (t & rm) as Chunk;
+ let mut co = t >> rb;
+
+ let mut j = 1;
+ while j < NLEN - 1 {
+ t = (a.w[j] as DChunk) * (a.w[0] as DChunk);
+ for i in 1..(j + 1) / 2 {
+ t += (a.w[j - i] as DChunk) * (a.w[i] as DChunk);
+ }
+ t += t;
+ t += co;
+ c.w[j] = (t & rm) as Chunk;
+ co = t >> rb;
+ j += 1;
+ t = (a.w[j] as DChunk) * (a.w[0] as DChunk);
+ for i in 1..(j + 1) / 2 {
+ t += (a.w[j - i] as DChunk) * (a.w[i] as DChunk);
+ }
+ t += t;
+ t += co;
+ t += (a.w[j / 2] as DChunk) * (a.w[j / 2] as DChunk);
+ c.w[j] = (t & rm) as Chunk;
+ co = t >> rb;
+ j += 1;
+ }
+
+ j = NLEN + (NLEN % 2) - 1;
+ while j < DNLEN - 3 {
+ t = (a.w[NLEN - 1] as DChunk) * (a.w[j + 1 - NLEN] as DChunk);
+ for i in j + 2 - NLEN..(j + 1) / 2 {
+ t += (a.w[j - i] as DChunk) * (a.w[i] as DChunk);
+ }
+ t += t;
+ t += co;
+ c.w[j] = (t & rm) as Chunk;
+ co = t >> rb;
+ j += 1;
+ t = (a.w[NLEN - 1] as DChunk) * (a.w[j + 1 - NLEN] as DChunk);
+ for i in j + 2 - NLEN..(j + 1) / 2 {
+ t += (a.w[j - i] as DChunk) * (a.w[i] as DChunk);
+ }
+ t += t;
+ t += co;
+ t += (a.w[j / 2] as DChunk) * (a.w[j / 2] as DChunk);
+ c.w[j] = (t & rm) as Chunk;
+ co = t >> rb;
+ j += 1;
+ }
+
+ t = (a.w[NLEN - 2] as DChunk) * (a.w[NLEN - 1] as DChunk);
+ t += t;
+ t += co;
+ c.w[DNLEN - 3] = (t & rm) as Chunk;
+ co = t >> rb;
+
+ t = (a.w[NLEN - 1] as DChunk) * (a.w[NLEN - 1] as DChunk) + co;
+ c.w[DNLEN - 2] = (t & rm) as Chunk;
+ co = t >> rb;
+ c.w[DNLEN - 1] = co as Chunk;
+
+ return c;
+ }
+
+ pub fn monty(md: &BIG, mc: Chunk, d: &mut DBIG) -> BIG {
+ let mut b = BIG::new();
+ let rm = BMASK as DChunk;
+ let rb = BASEBITS;
+
+ let mut dd: [DChunk; NLEN] = [0; NLEN];
+ let mut v: [Chunk; NLEN] = [0; NLEN];
+
+ b.zero();
+
+ let mut t = d.w[0] as DChunk;
+ v[0] = (((t & rm) as Chunk).wrapping_mul(mc)) & BMASK;
+ t += (v[0] as DChunk) * (md.w[0] as DChunk);
+ let mut c = (d.w[1] as DChunk) + (t >> rb);
+ let mut s: DChunk = 0;
+ for k in 1..NLEN {
+ t = c + s + (v[0] as DChunk) * (md.w[k] as DChunk);
+ let mut i = 1 + k / 2;
+ while i < k {
+ t += ((v[k - i] - v[i]) as DChunk) * ((md.w[i] - md.w[k - i]) as DChunk);
+ i += 1;
+ }
+ v[k] = (((t & rm) as Chunk).wrapping_mul(mc)) & BMASK;
+ t += (v[k] as DChunk) * (md.w[0] as DChunk);
+ c = (d.w[k + 1] as DChunk) + (t >> rb);
+ dd[k] = (v[k] as DChunk) * (md.w[k] as DChunk);
+ s += dd[k];
+ }
+
+ for k in NLEN..2 * NLEN - 1 {
+ t = c + s;
+ let mut i = 1 + k / 2;
+ while i < NLEN {
+ t += ((v[k - i] - v[i]) as DChunk) * ((md.w[i] - md.w[k - i]) as DChunk);
+ i += 1;
+ }
+ b.w[k - NLEN] = (t & rm) as Chunk;
+ c = (d.w[k + 1] as DChunk) + (t >> rb);
+ s -= dd[k + 1 - NLEN];
+ }
+ b.w[NLEN - 1] = (c & rm) as Chunk;
+ return b;
+ }
+
+ pub fn ssn(r: &mut BIG, a: &BIG, m: &mut BIG) -> isize {
+ let n = NLEN - 1;
+ m.w[0] = (m.w[0] >> 1) | ((m.w[1] << (BASEBITS - 1)) & BMASK);
+ r.w[0] = a.w[0] - m.w[0];
+ let mut carry = r.w[0] >> BASEBITS;
+ r.w[0] &= BMASK;
+ for i in 1..n {
+ m.w[i] = (m.w[i] >> 1) | ((m.w[i + 1] << (BASEBITS - 1)) & BMASK);
+ r.w[i] = a.w[i] - m.w[i] + carry;
+ carry = r.w[i] >> BASEBITS;
+ r.w[i] &= BMASK;
+ }
+ m.w[n] >>= 1;
+ r.w[n] = a.w[n] - m.w[n] + carry;
+ return ((r.w[n] >> (arch::CHUNK - 1)) & 1) as isize;
+ }
+
+ /* return a*b mod m */
+ pub fn modmul(a1: &BIG, b1: &BIG, m: &BIG) -> BIG {
+ let mut a = BIG::new_copy(a1);
+ let mut b = BIG::new_copy(b1);
+ a.rmod(m);
+ b.rmod(m);
+ let mut d = BIG::mul(&a, &b);
+ return d.dmod(m);
+ }
+
+ /* return a^2 mod m */
+ pub fn modsqr(a1: &BIG, m: &BIG) -> BIG {
+ let mut a = BIG::new_copy(a1);
+ a.rmod(m);
+ let mut d = BIG::sqr(&a);
+ return d.dmod(m);
+ }
+
+ /* return -a mod m */
+ pub fn modneg(a1: &BIG, m: &BIG) -> BIG {
+ let mut a = BIG::new_copy(a1);
+ a.rmod(m);
+ return m.minus(&a);
+ }
+
+ /* return this^e mod m */
+ pub fn powmod(&mut self, e1: &BIG, m: &BIG) -> BIG {
+ self.norm();
+ let mut e = BIG::new_copy(e1);
+ e.norm();
+ let mut a = BIG::new_int(1);
+ let mut z = BIG::new_copy(&e);
+ let mut s = BIG::new_copy(self);
+ loop {
+ let bt = z.parity();
+ z.fshr(1);
+ if bt == 1 {
+ a = BIG::modmul(&a, &s, m)
+ }
+ if z.iszilch() {
+ break;
+ }
+ s = BIG::modsqr(&mut s, m);
+ }
+ return a;
+ }
+}
diff --git a/src/bls.rs b/src/bls.rs
new file mode 100644
index 0000000..7e7fd7a
--- /dev/null
+++ b/src/bls.rs
@@ -0,0 +1,96 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+use std::str;
+use super::ecp::ECP;
+use super::ecp2::ECP2;
+//use super::fp12::FP12;
+use super::big::BIG;
+use super::pair;
+use super::big;
+use super::rom;
+
+use rand::RAND;
+use sha3::SHA3;
+use sha3::SHAKE256;
+
+/* BLS API Functions */
+
+pub const BFS: usize = big::MODBYTES as usize;
+pub const BGS: usize = big::MODBYTES as usize;
+pub const BLS_OK: isize = 0;
+pub const BLS_FAIL: isize = -1;
+
+/* hash a message to an ECP point, using SHA3 */
+
+#[allow(non_snake_case)]
+fn bls_hashit(m: &str) -> ECP {
+ let mut sh = SHA3::new(SHAKE256);
+ let mut hm: [u8; BFS] = [0; BFS];
+ let t = m.as_bytes();
+ for i in 0..m.len() {
+ sh.process(t[i]);
+ }
+ sh.shake(&mut hm, BFS);
+ let P = ECP::mapit(&hm);
+ return P;
+}
+
+/* generate key pair, private key s, public key w */
+pub fn key_pair_generate(mut rng: &mut RAND, s: &mut [u8], w: &mut [u8]) -> isize {
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let g = ECP2::generator();
+ let mut sc = BIG::randomnum(&q, &mut rng);
+ sc.tobytes(s);
+ pair::g2mul(&g, &mut sc).tobytes(w);
+ return BLS_OK;
+}
+
+/* Sign message m using private key s to produce signature sig */
+
+pub fn sign(sig: &mut [u8], m: &str, s: &[u8]) -> isize {
+ let d = bls_hashit(m);
+ let mut sc = BIG::frombytes(&s);
+ pair::g1mul(&d, &mut sc).tobytes(sig, true);
+ return BLS_OK;
+}
+
+/* Verify signature given message m, the signature sig, and the public key w */
+
+pub fn verify(sig: &[u8], m: &str, w: &[u8]) -> isize {
+ let hm = bls_hashit(m);
+ let mut d = ECP::frombytes(&sig);
+ let g = ECP2::generator();
+ let pk = ECP2::frombytes(&w);
+ d.neg();
+
+// Use new multi-pairing mechanism
+ let mut r=pair::initmp();
+ pair::another(&mut r,&g,&d);
+ pair::another(&mut r,&pk,&hm);
+ let mut v=pair::miller(&r);
+
+//.. or alternatively
+// let mut v = pair::ate2(&g, &d, &pk, &hm);
+
+ v = pair::fexp(&v);
+ if v.isunity() {
+ return BLS_OK;
+ }
+ return BLS_FAIL;
+}
diff --git a/src/bls192.rs b/src/bls192.rs
new file mode 100644
index 0000000..20ee92e
--- /dev/null
+++ b/src/bls192.rs
@@ -0,0 +1,96 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+use std::str;
+use super::ecp::ECP;
+use super::ecp4::ECP4;
+//use super::fp24::FP24;
+use super::big::BIG;
+use super::pair192;
+use super::big;
+use super::rom;
+
+use rand::RAND;
+use sha3::SHA3;
+use sha3::SHAKE256;
+
+/* BLS API Functions */
+
+pub const BFS: usize = big::MODBYTES as usize;
+pub const BGS: usize = big::MODBYTES as usize;
+pub const BLS_OK: isize = 0;
+pub const BLS_FAIL: isize = -1;
+
+/* hash a message to an ECP point, using SHA3 */
+
+#[allow(non_snake_case)]
+fn bls_hashit(m: &str) -> ECP {
+ let mut sh = SHA3::new(SHAKE256);
+ let mut hm: [u8; BFS] = [0; BFS];
+ let t = m.as_bytes();
+ for i in 0..m.len() {
+ sh.process(t[i]);
+ }
+ sh.shake(&mut hm, BFS);
+ let P = ECP::mapit(&hm);
+ return P;
+}
+
+/* generate key pair, private key s, public key w */
+pub fn key_pair_generate(mut rng: &mut RAND, s: &mut [u8], w: &mut [u8]) -> isize {
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let g = ECP4::generator();
+ let mut sc = BIG::randomnum(&q, &mut rng);
+ sc.tobytes(s);
+ pair192::g2mul(&g, &mut sc).tobytes(w);
+ return BLS_OK;
+}
+
+/* Sign message m using private key s to produce signature sig */
+
+pub fn sign(sig: &mut [u8], m: &str, s: &[u8]) -> isize {
+ let d = bls_hashit(m);
+ let mut sc = BIG::frombytes(&s);
+ pair192::g1mul(&d, &mut sc).tobytes(sig, true);
+ return BLS_OK;
+}
+
+/* Verify signature given message m, the signature sig, and the public key w */
+
+pub fn verify(sig: &[u8], m: &str, w: &[u8]) -> isize {
+ let hm = bls_hashit(m);
+ let mut d = ECP::frombytes(&sig);
+ let g = ECP4::generator();
+ let pk = ECP4::frombytes(&w);
+ d.neg();
+
+// Use new multi-pairing mechanism
+ let mut r=pair192::initmp();
+ pair192::another(&mut r,&g,&d);
+ pair192::another(&mut r,&pk,&hm);
+ let mut v=pair192::miller(&r);
+
+//.. or alternatively
+// let mut v = pair192::ate2(&g, &d, &pk, &hm);
+
+ v = pair192::fexp(&v);
+ if v.isunity() {
+ return BLS_OK;
+ }
+ return BLS_FAIL;
+}
diff --git a/src/bls256.rs b/src/bls256.rs
new file mode 100644
index 0000000..cdb553d
--- /dev/null
+++ b/src/bls256.rs
@@ -0,0 +1,96 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+use std::str;
+use super::ecp::ECP;
+use super::ecp8::ECP8;
+//use super::fp48::FP48;
+use super::big::BIG;
+use super::pair256;
+use super::big;
+use super::rom;
+
+use rand::RAND;
+use sha3::SHA3;
+use sha3::SHAKE256;
+
+/* BLS API Functions */
+
+pub const BFS: usize = big::MODBYTES as usize;
+pub const BGS: usize = big::MODBYTES as usize;
+pub const BLS_OK: isize = 0;
+pub const BLS_FAIL: isize = -1;
+
+/* hash a message to an ECP point, using SHA3 */
+
+#[allow(non_snake_case)]
+fn bls_hashit(m: &str) -> ECP {
+ let mut sh = SHA3::new(SHAKE256);
+ let mut hm: [u8; BFS] = [0; BFS];
+ let t = m.as_bytes();
+ for i in 0..m.len() {
+ sh.process(t[i]);
+ }
+ sh.shake(&mut hm, BFS);
+ let P = ECP::mapit(&hm);
+ return P;
+}
+
+/* generate key pair, private key s, public key w */
+pub fn key_pair_generate(mut rng: &mut RAND, s: &mut [u8], w: &mut [u8]) -> isize {
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let g = ECP8::generator();
+ let mut sc = BIG::randomnum(&q, &mut rng);
+ sc.tobytes(s);
+ pair256::g2mul(&g, &mut sc).tobytes(w);
+ return BLS_OK;
+}
+
+/* Sign message m using private key s to produce signature sig */
+
+pub fn sign(sig: &mut [u8], m: &str, s: &[u8]) -> isize {
+ let d = bls_hashit(m);
+ let mut sc = BIG::frombytes(&s);
+ pair256::g1mul(&d, &mut sc).tobytes(sig, true);
+ return BLS_OK;
+}
+
+/* Verify signature given message m, the signature sig, and the public key w */
+
+pub fn verify(sig: &[u8], m: &str, w: &[u8]) -> isize {
+ let hm = bls_hashit(m);
+ let mut d = ECP::frombytes(&sig);
+ let g = ECP8::generator();
+ let pk = ECP8::frombytes(&w);
+ d.neg();
+
+// Use new multi-pairing mechanism
+ let mut r=pair256::initmp();
+ pair256::another(&mut r,&g,&d);
+ pair256::another(&mut r,&pk,&hm);
+ let mut v=pair256::miller(&r);
+
+//.. or alternatively
+// let mut v = pair256::ate2(&g, &d, &pk, &hm);
+
+ v = pair256::fexp(&v);
+ if v.isunity() {
+ return BLS_OK;
+ }
+ return BLS_FAIL;
+}
diff --git a/src/dbig.rs b/src/dbig.rs
new file mode 100644
index 0000000..353443a
--- /dev/null
+++ b/src/dbig.rs
@@ -0,0 +1,301 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::super::arch;
+use super::big;
+use super::big::BIG;
+use super::super::arch::Chunk;
+
+#[derive(Copy)]
+pub struct DBIG {
+ pub w: [Chunk; big::DNLEN],
+}
+
+impl Clone for DBIG {
+ fn clone(&self) -> DBIG { *self }
+}
+
+impl DBIG {
+ pub fn new() -> DBIG {
+ DBIG {
+ w: [0; big::DNLEN as usize],
+ }
+ }
+
+ pub fn new_copy(y: &DBIG) -> DBIG {
+ let mut s = DBIG::new();
+ for i in 0..big::DNLEN {
+ s.w[i] = y.w[i]
+ }
+ return s;
+ }
+
+ pub fn new_scopy(x: &BIG) -> DBIG {
+ let mut b = DBIG::new();
+ for i in 0..big::NLEN {
+ b.w[i] = x.w[i];
+ }
+ b.w[big::NLEN - 1] = x.get(big::NLEN - 1) & big::BMASK; /* top word normalized */
+ b.w[big::NLEN] = x.get(big::NLEN - 1) >> big::BASEBITS;
+
+ for i in big::NLEN + 1..big::DNLEN {
+ b.w[i] = 0
+ }
+ return b;
+ }
+
+ /* split DBIG at position n, return higher half, keep lower half */
+ pub fn split(&mut self, n: usize) -> BIG {
+ let mut t = BIG::new();
+ let m = n % big::BASEBITS;
+ let mut carry = self.w[big::DNLEN - 1] << (big::BASEBITS - m);
+
+ for i in (big::NLEN - 1..big::DNLEN - 1).rev() {
+ let nw = (self.w[i] >> m) | carry;
+ carry = (self.w[i] << (big::BASEBITS - m)) & big::BMASK;
+ t.set(i + 1 - big::NLEN, nw);
+ }
+ self.w[big::NLEN - 1] &= ((1 as Chunk) << m) - 1;
+ return t;
+ }
+
+ /* general shift left */
+ pub fn shl(&mut self, k: usize) {
+ let n = k % big::BASEBITS;
+ let m = k / big::BASEBITS;
+ self.w[big::DNLEN - 1] =
+ (self.w[big::DNLEN - 1 - m] << n) | (self.w[big::DNLEN - m - 2] >> (big::BASEBITS - n));
+ for i in (m + 1..big::DNLEN - 1).rev() {
+ self.w[i] =
+ ((self.w[i - m] << n) & big::BMASK) | (self.w[i - m - 1] >> (big::BASEBITS - n));
+ }
+
+ self.w[m] = (self.w[0] << n) & big::BMASK;
+ for i in 0..m {
+ self.w[i] = 0
+ }
+ }
+
+ /* general shift right */
+ pub fn shr(&mut self, k: usize) {
+ let n = k % big::BASEBITS;
+ let m = k / big::BASEBITS;
+ for i in 0..big::DNLEN - m - 1 {
+ self.w[i] =
+ (self.w[m + i] >> n) | ((self.w[m + i + 1] << (big::BASEBITS - n)) & big::BMASK);
+ }
+ self.w[big::DNLEN - m - 1] = self.w[big::DNLEN - 1] >> n;
+ for i in big::DNLEN - m..big::DNLEN {
+ self.w[i] = 0
+ }
+ }
+
+ /* Copy from another DBIG */
+ pub fn copy(&mut self, x: &DBIG) {
+ for i in 0..big::DNLEN {
+ self.w[i] = x.w[i];
+ }
+ }
+
+ pub fn ucopy(&mut self, x: &BIG) {
+ for i in 0..big::NLEN {
+ self.w[i] = 0;
+ }
+ for i in big::NLEN..big::DNLEN {
+ self.w[i] = x.w[i - big::NLEN];
+ }
+ }
+
+ pub fn cmove(&mut self, g: &DBIG, d: isize) {
+ let b = -d as Chunk;
+ for i in 0..big::DNLEN {
+ self.w[i] ^= (self.w[i] ^ g.w[i]) & b;
+ }
+ }
+
+ /* self+=x */
+ pub fn add(&mut self, x: &DBIG) {
+ for i in 0..big::DNLEN {
+ self.w[i] += x.w[i];
+ }
+ }
+
+ /* self-=x */
+ pub fn sub(&mut self, x: &DBIG) {
+ for i in 0..big::DNLEN {
+ self.w[i] -= x.w[i];
+ }
+ }
+
+ /* self=x-self */
+ pub fn rsub(&mut self, x: &DBIG) {
+ for i in 0..big::DNLEN {
+ self.w[i] = x.w[i] - self.w[i];
+ }
+ }
+
+ /* Compare a and b, return 0 if a==b, -1 if a<b, +1 if a>b. Inputs must be normalised */
+ pub fn comp(a: &DBIG, b: &DBIG) -> isize {
+ for i in (0..big::DNLEN).rev() {
+ if a.w[i] == b.w[i] {
+ continue;
+ }
+ if a.w[i] > b.w[i] {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /* normalise BIG - force all digits < 2^big::BASEBITS */
+ pub fn norm(&mut self) {
+ let mut carry = 0 as Chunk;
+ for i in 0..big::DNLEN - 1 {
+ let d = self.w[i] + carry;
+ self.w[i] = d & big::BMASK;
+ carry = d >> big::BASEBITS;
+ }
+ self.w[big::DNLEN - 1] += carry
+ }
+
+ /* reduces self DBIG mod a BIG, and returns the BIG */
+ pub fn dmod(&mut self, c: &BIG) -> BIG {
+ let mut k = 0;
+ self.norm();
+ let mut m = DBIG::new_scopy(c);
+ let mut dr = DBIG::new();
+
+ if DBIG::comp(self, &m) < 0 {
+ let r = BIG::new_dcopy(self);
+ return r;
+ }
+
+ loop {
+ m.shl(1);
+ k += 1;
+ if DBIG::comp(self, &m) < 0 {
+ break;
+ }
+ }
+
+ while k > 0 {
+ m.shr(1);
+
+ dr.copy(self);
+ dr.sub(&m);
+ dr.norm();
+ self.cmove(
+ &dr,
+ (1 - ((dr.w[big::DNLEN - 1] >> (arch::CHUNK - 1)) & 1)) as isize,
+ );
+
+ k -= 1;
+ }
+ let r = BIG::new_dcopy(self);
+ return r;
+ }
+
+ /* return this/c */
+ pub fn div(&mut self, c: &BIG) -> BIG {
+ let mut k = 0;
+ let mut m = DBIG::new_scopy(c);
+ let mut a = BIG::new();
+ let mut e = BIG::new_int(1);
+ let mut dr = DBIG::new();
+ let mut r = BIG::new();
+ self.norm();
+
+ while DBIG::comp(self, &m) >= 0 {
+ e.fshl(1);
+ m.shl(1);
+ k += 1;
+ }
+
+ while k > 0 {
+ m.shr(1);
+ e.shr(1);
+
+ dr.copy(self);
+ dr.sub(&m);
+ dr.norm();
+ let d = (1 - ((dr.w[big::DNLEN - 1] >> (arch::CHUNK - 1)) & 1)) as isize;
+ self.cmove(&dr, d);
+ r.copy(&a);
+ r.add(&e);
+ r.norm();
+ a.cmove(&r, d);
+
+ k -= 1;
+ }
+ return a;
+ }
+
+ /* set x = x mod 2^m */
+ pub fn mod2m(&mut self, m: usize) {
+ let wd = m / big::BASEBITS;
+ let bt = m % big::BASEBITS;
+ let msk = (1 << bt) - 1;
+ self.w[wd] &= msk;
+ for i in wd + 1..big::DNLEN {
+ self.w[i] = 0
+ }
+ }
+
+ /* return number of bits */
+ pub fn nbits(&mut self) -> usize {
+ let mut k = big::DNLEN - 1;
+ let mut s = DBIG::new_copy(&self);
+ s.norm();
+ while (k as isize) >= 0 && s.w[k] == 0 {
+ k = k.wrapping_sub(1)
+ }
+ if (k as isize) < 0 {
+ return 0;
+ }
+ let mut bts = (big::BASEBITS as usize) * k;
+ let mut c = s.w[k];
+ while c != 0 {
+ c /= 2;
+ bts += 1;
+ }
+ return bts;
+ }
+
+ /* Convert to Hex String */
+ pub fn to_string(&mut self) -> String {
+ let mut s = String::new();
+ let mut len = self.nbits();
+
+ if len % 4 == 0 {
+ len /= 4;
+ } else {
+ len /= 4;
+ len += 1;
+ }
+
+ for i in (0..len).rev() {
+ let mut b = DBIG::new_copy(&self);
+ b.shr(i * 4);
+ s = s + &format!("{:X}", b.w[0] & 15);
+ }
+ return s;
+ }
+}
diff --git a/src/ecdh.rs b/src/ecdh.rs
new file mode 100644
index 0000000..9b49e18
--- /dev/null
+++ b/src/ecdh.rs
@@ -0,0 +1,744 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::ecp;
+use super::ecp::ECP;
+use super::big::BIG;
+use super::rom;
+use super::big;
+
+use rand::RAND;
+use hash256::HASH256;
+use hash384::HASH384;
+use hash512::HASH512;
+use aes;
+use aes::AES;
+
+
+pub const INVALID_PUBLIC_KEY: isize = -2;
+pub const ERROR: isize = -3;
+pub const INVALID: isize = -4;
+pub const EFS: usize = big::MODBYTES as usize;
+pub const EGS: usize = big::MODBYTES as usize;
+pub const SHA256: usize = 32;
+pub const SHA384: usize = 48;
+pub const SHA512: usize = 64;
+
+#[allow(non_snake_case)]
+
+fn inttobytes(n: usize, b: &mut [u8]) {
+ let mut i = b.len();
+ let mut m = n;
+ while m > 0 && i > 0 {
+ i -= 1;
+ b[i] = (m & 0xff) as u8;
+ m /= 256;
+ }
+}
+
+fn hashit(sha: usize, a: &[u8], n: usize, b: Option<&[u8]>, pad: usize, w: &mut [u8]) {
+ let mut r: [u8; 64] = [0; 64];
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ h.process_array(a);
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ if let Some(x) = b {
+ h.process_array(x);
+ }
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ h.process_array(a);
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ if let Some(x) = b {
+ h.process_array(x);
+ }
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ h.process_array(a);
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ if let Some(x) = b {
+ h.process_array(x);
+ }
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ }
+
+ if pad == 0 {
+ for i in 0..sha {
+ w[i] = r[i]
+ }
+ } else {
+ if pad <= sha {
+ for i in 0..pad {
+ w[i] = r[i]
+ }
+ } else {
+ for i in 0..sha {
+ w[i + pad - sha] = r[i]
+ }
+ for i in 0..(pad - sha) {
+ w[i] = 0
+ }
+ }
+ }
+}
+
+/* Key Derivation Functions */
+/* Input octet Z */
+/* Output key of length olen */
+pub fn kdf1(sha: usize, z: &[u8], olen: usize, k: &mut [u8]) {
+ /* NOTE: the parameter olen is the length of the output K in bytes */
+ let hlen = sha;
+ let mut lk = 0;
+
+ let mut cthreshold = olen / hlen;
+ if olen % hlen != 0 {
+ cthreshold += 1
+ }
+
+ for counter in 0..cthreshold {
+ let mut b: [u8; 64] = [0; 64];
+ hashit(sha, z, counter, None, 0, &mut b);
+ if lk + hlen > olen {
+ for i in 0..(olen % hlen) {
+ k[lk] = b[i];
+ lk += 1
+ }
+ } else {
+ for i in 0..hlen {
+ k[lk] = b[i];
+ lk += 1
+ }
+ }
+ }
+}
+
+pub fn kdf2(sha: usize, z: &[u8], p: Option<&[u8]>, olen: usize, k: &mut [u8]) {
+ /* NOTE: the parameter olen is the length of the output K in bytes */
+ let hlen = sha;
+ let mut lk = 0;
+
+ let mut cthreshold = olen / hlen;
+ if olen % hlen != 0 {
+ cthreshold += 1
+ }
+
+ for counter in 1..cthreshold + 1 {
+ let mut b: [u8; 64] = [0; 64];
+ hashit(sha, z, counter, p, 0, &mut b);
+ if lk + hlen > olen {
+ for i in 0..(olen % hlen) {
+ k[lk] = b[i];
+ lk += 1
+ }
+ } else {
+ for i in 0..hlen {
+ k[lk] = b[i];
+ lk += 1
+ }
+ }
+ }
+}
+
+/* Password based Key Derivation Function */
+/* Input password p, salt s, and repeat count */
+/* Output key of length olen */
+pub fn pbkdf2(sha: usize, pass: &[u8], salt: &[u8], rep: usize, olen: usize, k: &mut [u8]) {
+ let mut d = olen / sha;
+ if olen % sha != 0 {
+ d += 1
+ }
+ let mut f: [u8; 64] = [0; 64];
+ let mut u: [u8; 64] = [0; 64];
+ let mut ku: [u8; 64] = [0; 64];
+ let mut s: [u8; 36] = [0; 36]; // Maximum salt of 32 bytes + 4
+ let mut n: [u8; 4] = [0; 4];
+
+ let sl = salt.len();
+ let mut kp = 0;
+ for i in 0..d {
+ for j in 0..sl {
+ s[j] = salt[j]
+ }
+ inttobytes(i + 1, &mut n);
+ for j in 0..4 {
+ s[sl + j] = n[j]
+ }
+
+ hmac(sha, &s[0..sl + 4], pass, sha, &mut f);
+
+ for j in 0..sha {
+ u[j] = f[j]
+ }
+ for _ in 1..rep {
+ hmac(sha, &mut u, pass, sha, &mut ku);
+ for k in 0..sha {
+ u[k] = ku[k];
+ f[k] ^= u[k]
+ }
+ }
+ for j in 0..EFS {
+ if kp < olen {
+ k[kp] = f[j]
+ }
+ kp += 1
+ }
+ }
+}
+
+/* Calculate HMAC of m using key k. HMAC is tag of length olen (which is length of tag) */
+pub fn hmac(sha: usize, m: &[u8], k: &[u8], olen: usize, tag: &mut [u8]) -> bool {
+ /* Input is from an octet m *
+ * olen is requested output length in bytes. k is the key *
+ * The output is the calculated tag */
+ let mut b: [u8; 64] = [0; 64]; /* Not good */
+ let mut k0: [u8; 128] = [0; 128];
+
+ if olen < 4 {
+ return false;
+ }
+
+ let mut lb = 64;
+ if sha > 32 {
+ lb = 128
+ }
+
+ for i in 0..lb {
+ k0[i] = 0
+ }
+
+ if k.len() > lb {
+ hashit(sha, k, 0, None, 0, &mut b);
+ for i in 0..sha {
+ k0[i] = b[i]
+ }
+ } else {
+ for i in 0..k.len() {
+ k0[i] = k[i]
+ }
+ }
+
+ for i in 0..lb {
+ k0[i] ^= 0x36
+ }
+ hashit(sha, &mut k0[0..lb], 0, Some(m), 0, &mut b);
+
+ for i in 0..lb {
+ k0[i] ^= 0x6a
+ }
+ hashit(sha, &mut k0[0..lb], 0, Some(&b[0..sha]), olen, tag);
+
+ return true;
+}
+
+/* AES encryption/decryption. Encrypt byte array m using key k and returns ciphertext c */
+pub fn cbc_iv0_encrypt(k: &[u8], m: &[u8]) -> Vec<u8> {
+ /* AES CBC encryption, with Null IV and key K */
+ /* Input is from an octet string m, output is to an octet string c */
+ /* Input is padded as necessary to make up a full final block */
+ let mut a = AES::new();
+ let mut fin = false;
+ let mut c: Vec<u8> = Vec::new();
+
+ let mut buff: [u8; 16] = [0; 16];
+
+ a.init(aes::CBC, k.len(), k, None);
+
+ let mut ipt = 0;
+ let mut i;
+ loop {
+ i = 0;
+ while i < 16 {
+ if ipt < m.len() {
+ buff[i] = m[ipt];
+ i += 1;
+ ipt += 1;
+ } else {
+ fin = true;
+ break;
+ }
+ }
+ if fin {
+ break;
+ }
+ a.encrypt(&mut buff);
+ for j in 0..16 {
+ c.push(buff[j]);
+ }
+ }
+
+ /* last block, filled up to i-th index */
+
+ let padlen = 16 - i;
+ for j in i..16 {
+ buff[j] = padlen as u8
+ }
+
+ a.encrypt(&mut buff);
+
+ for j in 0..16 {
+ c.push(buff[j]);
+ }
+ a.end();
+ return c;
+}
+
+/* returns plaintext if all consistent, else returns null string */
+pub fn cbc_iv0_decrypt(k: &[u8], c: &[u8]) -> Option<Vec<u8>> {
+ /* padding is removed */
+ let mut a = AES::new();
+ let mut fin = false;
+ let mut m: Vec<u8> = Vec::new();
+
+ let mut buff: [u8; 16] = [0; 16];
+
+ a.init(aes::CBC, k.len(), k, None);
+
+ let mut ipt = 0;
+ let mut i;
+
+ if c.len() == 0 {
+ return None;
+ }
+ let mut ch = c[ipt];
+ ipt += 1;
+
+ loop {
+ i = 0;
+ while i < 16 {
+ buff[i] = ch;
+ if ipt >= c.len() {
+ fin = true;
+ break;
+ } else {
+ ch = c[ipt];
+ ipt += 1
+ }
+ i += 1;
+ }
+ a.decrypt(&mut buff);
+ if fin {
+ break;
+ }
+ for j in 0..16 {
+ m.push(buff[j]);
+ }
+ }
+
+ a.end();
+ let mut bad = false;
+ let padlen = buff[15] as usize;
+ if i != 15 || padlen < 1 || padlen > 16 {
+ bad = true
+ }
+ if padlen >= 2 && padlen <= 16 {
+ for j in 16 - padlen..16 {
+ if buff[j] != padlen as u8 {
+ bad = true
+ }
+ }
+ }
+
+ if !bad {
+ for i in 0..16 - padlen {
+ m.push(buff[i]);
+ }
+ }
+
+ if bad {
+ return None;
+ }
+ return Some(m);
+}
+
+/* Calculate a public/private EC GF(p) key pair w,s where W=s.G mod EC(p),
+ * where s is the secret key and W is the public key
+ * and G is fixed generator.
+ * If RNG is NULL then the private key is provided externally in s
+ * otherwise it is generated randomly internally */
+#[allow(non_snake_case)]
+pub fn key_pair_generate(rng: Option<&mut RAND>, s: &mut [u8], w: &mut [u8]) -> isize {
+ let res = 0;
+ let mut sc: BIG;
+ let G = ECP::generator();
+
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ if let Some(mut x) = rng {
+ sc = BIG::randomnum(&r, &mut x);
+ } else {
+ sc = BIG::frombytes(&s);
+ sc.rmod(&r);
+ }
+
+ sc.tobytes(s);
+
+ let WP = G.mul(&mut sc);
+
+ WP.tobytes(w, false); // To use point compression on public keys, change to true
+
+ return res;
+}
+
+/* validate public key */
+#[allow(non_snake_case)]
+pub fn public_key_validate(w: &[u8]) -> isize {
+ let mut WP = ECP::frombytes(w);
+ let mut res = 0;
+
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ if WP.is_infinity() {
+ res = INVALID_PUBLIC_KEY
+ }
+ if res == 0 {
+ let q = BIG::new_ints(&rom::MODULUS);
+ let nb = q.nbits();
+ let mut k = BIG::new();
+ k.one();
+ k.shl((nb + 4) / 2);
+ k.add(&q);
+ k.div(&r);
+
+ while k.parity() == 0 {
+ k.shr(1);
+ WP.dbl();
+ }
+
+ if !k.isunity() {
+ WP = WP.mul(&mut k)
+ }
+ if WP.is_infinity() {
+ res = INVALID_PUBLIC_KEY
+ }
+ }
+ return res;
+}
+
+/* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */
+#[allow(non_snake_case)]
+pub fn ecpsvdp_dh(s: &[u8], wd: &[u8], z: &mut [u8]) -> isize {
+ let mut res = 0;
+ let mut t: [u8; EFS] = [0; EFS];
+
+ let mut sc = BIG::frombytes(&s);
+
+ let mut W = ECP::frombytes(&wd);
+ if W.is_infinity() {
+ res = ERROR
+ }
+
+ if res == 0 {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+ sc.rmod(&r);
+ W = W.mul(&mut sc);
+ if W.is_infinity() {
+ res = ERROR;
+ } else {
+ W.getx().tobytes(&mut t);
+ for i in 0..EFS {
+ z[i] = t[i]
+ }
+ }
+ }
+ return res;
+}
+
+/* IEEE ECDSA Signature, C and D are signature on F using private key S */
+#[allow(non_snake_case)]
+pub fn ecpsp_dsa(
+ sha: usize,
+ rng: &mut RAND,
+ s: &[u8],
+ f: &[u8],
+ c: &mut [u8],
+ d: &mut [u8],
+) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+ let mut b: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+
+ hashit(sha, f, 0, None, big::MODBYTES as usize, &mut b);
+
+ let G = ECP::generator();
+
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ let mut sc = BIG::frombytes(s); /* s or &s? */
+ let fb = BIG::frombytes(&b);
+
+ let mut cb = BIG::new();
+ let mut db = BIG::new();
+ let mut tb = BIG::new();
+ let mut V = ECP::new();
+
+ while db.iszilch() {
+ let mut u = BIG::randomnum(&r, rng);
+ let mut w = BIG::randomnum(&r, rng); /* side channel masking */
+
+ V.copy(&G);
+ V = V.mul(&mut u);
+ let vx = V.getx();
+ cb.copy(&vx);
+ cb.rmod(&r);
+ if cb.iszilch() {
+ continue;
+ }
+
+ tb.copy(&BIG::modmul(&mut u, &mut w, &r));
+ u.copy(&tb);
+
+ u.invmodp(&r);
+ db.copy(&BIG::modmul(&mut sc, &mut cb, &r));
+ db.add(&fb);
+
+ tb.copy(&BIG::modmul(&mut db, &mut w, &r));
+ db.copy(&tb);
+
+ tb.copy(&BIG::modmul(&mut u, &mut db, &r));
+ db.copy(&tb);
+ }
+
+ cb.tobytes(&mut t);
+ for i in 0..EFS {
+ c[i] = t[i]
+ }
+ db.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i] = t[i]
+ }
+ return 0;
+}
+
+/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */
+#[allow(non_snake_case)]
+pub fn ecpvp_dsa(sha: usize, w: &[u8], f: &[u8], c: &[u8], d: &[u8]) -> isize {
+ let mut res = 0;
+
+ let mut b: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+
+ hashit(sha, f, 0, None, big::MODBYTES as usize, &mut b);
+
+ let mut G = ECP::generator();
+
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ let mut cb = BIG::frombytes(c); /* c or &c ? */
+ let mut db = BIG::frombytes(d); /* d or &d ? */
+ let mut fb = BIG::frombytes(&b);
+ let mut tb = BIG::new();
+
+ if cb.iszilch() || BIG::comp(&cb, &r) >= 0 || db.iszilch() || BIG::comp(&db, &r) >= 0 {
+ res = INVALID;
+ }
+
+ if res == 0 {
+ db.invmodp(&r);
+ tb.copy(&BIG::modmul(&mut fb, &mut db, &r));
+ fb.copy(&tb);
+ let h2 = BIG::modmul(&mut cb, &mut db, &r);
+
+ let WP = ECP::frombytes(&w);
+ if WP.is_infinity() {
+ res = ERROR;
+ } else {
+ let mut P = ECP::new();
+ P.copy(&WP);
+
+ P = P.mul2(&h2, &mut G, &fb);
+
+ if P.is_infinity() {
+ res = INVALID;
+ } else {
+ db = P.getx();
+ db.rmod(&r);
+
+ if BIG::comp(&db, &cb) != 0 {
+ res = INVALID
+ }
+ }
+ }
+ }
+
+ return res;
+}
+
+/* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */
+#[allow(non_snake_case)]
+pub fn ecies_encrypt(
+ sha: usize,
+ p1: &[u8],
+ p2: &[u8],
+ rng: &mut RAND,
+ w: &[u8],
+ m: &[u8],
+ v: &mut [u8],
+ t: &mut [u8],
+) -> Option<Vec<u8>> {
+ let mut z: [u8; EFS] = [0; EFS];
+ let mut k1: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
+ let mut k2: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
+ let mut u: [u8; EGS] = [0; EGS];
+ let mut vz: [u8; 3 * EFS + 1] = [0; 3 * EFS + 1];
+ let mut k: [u8; 2 * ecp::AESKEY] = [0; 2 * ecp::AESKEY];
+
+ if key_pair_generate(Some(rng), &mut u, v) != 0 {
+ return None;
+ }
+ if ecpsvdp_dh(&u, &w, &mut z) != 0 {
+ return None;
+ }
+
+ for i in 0..2 * EFS + 1 {
+ vz[i] = v[i]
+ }
+ for i in 0..EFS {
+ vz[2 * EFS + 1 + i] = z[i]
+ }
+
+ kdf2(sha, &vz, Some(p1), 2 * ecp::AESKEY, &mut k);
+
+ for i in 0..ecp::AESKEY {
+ k1[i] = k[i];
+ k2[i] = k[ecp::AESKEY + i]
+ }
+
+ let mut c = cbc_iv0_encrypt(&k1, m);
+
+ let mut l2: [u8; 8] = [0; 8];
+ let p2l = p2.len();
+
+ inttobytes(p2l, &mut l2);
+
+ for i in 0..p2l {
+ c.push(p2[i]);
+ }
+ for i in 0..8 {
+ c.push(l2[i]);
+ }
+
+ hmac(sha, &c, &k2, t.len(), t);
+
+ for _ in 0..p2l + 8 {
+ c.pop();
+ }
+
+ return Some(c);
+}
+
+/* constant time n-byte compare */
+fn ncomp(t1: &[u8], t2: &[u8], n: usize) -> bool {
+ let mut res = 0;
+ for i in 0..n {
+ res |= (t1[i] ^ t2[i]) as isize;
+ }
+ if res == 0 {
+ return true;
+ }
+ return false;
+}
+
+/* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */
+#[allow(non_snake_case)]
+pub fn ecies_decrypt(
+ sha: usize,
+ p1: &[u8],
+ p2: &[u8],
+ v: &[u8],
+ c: &mut Vec<u8>,
+ t: &[u8],
+ u: &[u8],
+) -> Option<Vec<u8>> {
+ let mut z: [u8; EFS] = [0; EFS];
+ let mut k1: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
+ let mut k2: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
+ let mut vz: [u8; 3 * EFS + 1] = [0; 3 * EFS + 1];
+ let mut k: [u8; 2 * ecp::AESKEY] = [0; 2 * ecp::AESKEY];
+
+ let mut tag: [u8; 32] = [0; 32]; /* 32 is max length of tag */
+
+ for i in 0..t.len() {
+ tag[i] = t[i]
+ }
+
+ if ecpsvdp_dh(&u, &v, &mut z) != 0 {
+ return None;
+ }
+
+ for i in 0..2 * EFS + 1 {
+ vz[i] = v[i]
+ }
+ for i in 0..EFS {
+ vz[2 * EFS + 1 + i] = z[i]
+ }
+
+ kdf2(sha, &vz, Some(p1), 2 * ecp::AESKEY, &mut k);
+
+ for i in 0..ecp::AESKEY {
+ k1[i] = k[i];
+ k2[i] = k[ecp::AESKEY + i]
+ }
+
+ let m = cbc_iv0_decrypt(&k1, &c);
+
+ if m == None {
+ return None;
+ }
+
+ let mut l2: [u8; 8] = [0; 8];
+ let p2l = p2.len();
+
+ inttobytes(p2l, &mut l2);
+
+ for i in 0..p2l {
+ c.push(p2[i]);
+ }
+ for i in 0..8 {
+ c.push(l2[i]);
+ }
+
+ hmac(sha, &c, &k2, t.len(), &mut tag);
+
+ for _ in 0..p2l + 8 {
+ c.pop();
+ }
+
+ if !ncomp(&t, &tag, t.len()) {
+ return None;
+ }
+
+ return m;
+}
diff --git a/src/ecp.rs b/src/ecp.rs
new file mode 100644
index 0000000..9e7b29c
--- /dev/null
+++ b/src/ecp.rs
@@ -0,0 +1,1261 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::fp::FP;
+use super::big::BIG;
+use super::big;
+use super::rom;
+
+pub use super::rom::{CURVETYPE, CURVE_PAIRING_TYPE, SEXTIC_TWIST, SIGN_OF_X, HASH_TYPE, AESKEY};
+pub use types::CurveType;
+use std::str::SplitWhitespace;
+use std::fmt;
+
+#[derive(Copy, Clone)]
+pub struct ECP {
+ x: FP,
+ y: FP,
+ z: FP,
+}
+
+impl PartialEq for ECP {
+ fn eq(&self, other: &ECP) -> bool {
+ self.equals(other)
+ }
+}
+
+impl fmt::Display for ECP {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ECP: [ {}, {}, {} ]", self.x, self.y, self.z)
+ }
+}
+
+impl fmt::Debug for ECP {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ECP: [ {}, {}, {} ]", self.x, self.y, self.z)
+ }
+}
+
+#[allow(non_snake_case)]
+impl ECP {
+ pub fn pnew() -> ECP {
+ ECP {
+ x: FP::new(),
+ y: FP::new_int(1),
+ z: FP::new(),
+ }
+ }
+
+ pub fn new() -> ECP {
+ let mut E = ECP::pnew();
+ if CURVETYPE == CurveType::EDWARDS {
+ E.z.one();
+ }
+ return E;
+ }
+
+ /* set (x,y) from two BIGs */
+ pub fn new_bigs(ix: &BIG, iy: &BIG) -> ECP {
+ let mut E = ECP::new();
+ E.x.bcopy(ix);
+ E.y.bcopy(iy);
+ E.z.one();
+ E.x.norm();
+ let mut rhs = ECP::rhs(&E.x);
+ if CURVETYPE == CurveType::MONTGOMERY {
+ if rhs.jacobi() != 1 {
+ E.inf();
+ }
+ } else {
+ let mut y2 = FP::new_copy(&E.y);
+ y2.sqr();
+ if !y2.equals(&mut rhs) {
+ E.inf();
+ }
+ }
+ return E;
+ }
+
+ /* set (x,y) from BIG and a bit */
+ pub fn new_bigint(ix: &BIG, s: isize) -> ECP {
+ let mut E = ECP::new();
+ E.x.bcopy(ix);
+ E.x.norm();
+ E.z.one();
+
+ let mut rhs = ECP::rhs(&E.x);
+
+ if rhs.jacobi() == 1 {
+ let mut ny = rhs.sqrt();
+ if ny.redc().parity() != s {
+ ny.neg()
+ }
+ E.y.copy(&ny);
+ } else {
+ E.inf()
+ }
+ return E;
+ }
+
+ #[allow(non_snake_case)]
+ /* set from x - calculate y from curve equation */
+ pub fn new_big(ix: &BIG) -> ECP {
+ let mut E = ECP::new();
+ E.x.bcopy(ix);
+ E.x.norm();
+ E.z.one();
+ let mut rhs = ECP::rhs(&E.x);
+ if rhs.jacobi() == 1 {
+ if CURVETYPE != CurveType::MONTGOMERY {
+ E.y.copy(&rhs.sqrt())
+ }
+ } else {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* set this=O */
+ pub fn inf(&mut self) {
+ self.x.zero();
+ if CURVETYPE != CurveType::MONTGOMERY {
+ self.y.one();
+ }
+ if CURVETYPE != CurveType::EDWARDS {
+ self.z.zero();
+ } else {
+ self.z.one()
+ }
+ }
+
+ /* Calculate RHS of curve equation */
+ fn rhs(x: &FP) -> FP {
+ let mut r = FP::new_copy(x);
+ r.sqr();
+
+ if CURVETYPE == CurveType::WEIERSTRASS {
+ // x^3+Ax+B
+ let b = FP::new_big(&BIG::new_ints(&rom::CURVE_B));
+ r.mul(x);
+ if rom::CURVE_A == -3 {
+ let mut cx = FP::new_copy(x);
+ cx.imul(3);
+ cx.neg();
+ cx.norm();
+ r.add(&cx);
+ }
+ r.add(&b);
+ }
+ if CURVETYPE == CurveType::EDWARDS {
+ // (Ax^2-1)/(Bx^2-1)
+ let mut b = FP::new_big(&BIG::new_ints(&rom::CURVE_B));
+ let one = FP::new_int(1);
+ b.mul(&r);
+ b.sub(&one);
+ b.norm();
+ if rom::CURVE_A == -1 {
+ r.neg()
+ }
+ r.sub(&one);
+ r.norm();
+ b.inverse();
+ r.mul(&b);
+ }
+ if CURVETYPE == CurveType::MONTGOMERY {
+ // x^3+Ax^2+x
+ let mut x3 = FP::new();
+ x3.copy(&r);
+ x3.mul(x);
+ r.imul(rom::CURVE_A);
+ r.add(&x3);
+ r.add(&x);
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* test for O point-at-infinity */
+ pub fn is_infinity(&self) -> bool {
+ match CURVETYPE {
+ CurveType::EDWARDS=> self.x.iszilch() && self.y.equals(&self.z),
+ CurveType::WEIERSTRASS => self.x.iszilch() && self.z.iszilch(),
+ CurveType::MONTGOMERY => self.z.iszilch(),
+ }
+ }
+
+ /* Conditional swap of P and Q dependant on d */
+ pub fn cswap(&mut self, Q: &mut ECP, d: isize) {
+ self.x.cswap(&mut Q.x, d);
+ if CURVETYPE != CurveType::MONTGOMERY {
+ self.y.cswap(&mut Q.y, d)
+ }
+ self.z.cswap(&mut Q.z, d);
+ }
+
+ /* Conditional move of Q to P dependant on d */
+ pub fn cmove(&mut self, Q: &ECP, d: isize) {
+ self.x.cmove(&Q.x, d);
+ if CURVETYPE != CurveType::MONTGOMERY {
+ self.y.cmove(&Q.y, d)
+ }
+ self.z.cmove(&Q.z, d);
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* this=P */
+ pub fn copy(&mut self, P: &ECP) {
+ self.x.copy(&P.x);
+ if CURVETYPE != CurveType::MONTGOMERY {
+ self.y.copy(&P.y)
+ }
+ self.z.copy(&P.z);
+ }
+
+ /* this=-this */
+ pub fn neg(&mut self) {
+ if CURVETYPE == CurveType::WEIERSTRASS {
+ self.y.neg();
+ self.y.norm();
+ }
+ if CURVETYPE == CurveType::EDWARDS {
+ self.x.neg();
+ self.x.norm();
+ }
+ return;
+ }
+ /* multiply x coordinate */
+ pub fn mulx(&mut self, c: &mut FP) {
+ self.x.mul(c);
+ }
+
+ /* Constant time select from pre-computed table */
+ fn selector(&mut self, W: &[ECP], b: i32) {
+ // unsure about &[& syntax. An array of pointers I hope..
+ let mut MP = ECP::new();
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&W[0], ECP::teq(babs, 0)); // conditional move
+ self.cmove(&W[1], ECP::teq(babs, 1));
+ self.cmove(&W[2], ECP::teq(babs, 2));
+ self.cmove(&W[3], ECP::teq(babs, 3));
+ self.cmove(&W[4], ECP::teq(babs, 4));
+ self.cmove(&W[5], ECP::teq(babs, 5));
+ self.cmove(&W[6], ECP::teq(babs, 6));
+ self.cmove(&W[7], ECP::teq(babs, 7));
+
+ MP.copy(self);
+ MP.neg();
+ self.cmove(&MP, (m & 1) as isize);
+ }
+
+ /* Test P == Q */
+ pub fn equals(&self, Q: &ECP) -> bool {
+ let mut a = FP::new();
+ let mut b = FP::new();
+ a.copy(&self.x);
+ a.mul(&Q.z);
+ b.copy(&Q.x);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+ if CURVETYPE != CurveType::MONTGOMERY {
+ a.copy(&self.y);
+ a.mul(&Q.z);
+ b.copy(&Q.y);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* set to affine - from (x,y,z) to (x,y) */
+ pub fn affine(&mut self) {
+ if self.is_infinity() {
+ return;
+ }
+ let mut one = FP::new_int(1);
+ if self.z.equals(&mut one) {
+ return;
+ }
+ self.z.inverse();
+
+ self.x.mul(&self.z);
+ self.x.reduce();
+ if CURVETYPE != CurveType::MONTGOMERY {
+ self.y.mul(&self.z);
+ self.y.reduce();
+ }
+ self.z.copy(&one);
+ }
+
+ /* extract x as a BIG */
+ pub fn getx(&self) -> BIG {
+ let mut W = ECP::new();
+ W.copy(self);
+ W.affine();
+ return W.x.redc();
+ }
+
+ /* extract y as a BIG */
+ pub fn gety(&self) -> BIG {
+ let mut W = ECP::new();
+ W.copy(self);
+ W.affine();
+ return W.y.redc();
+ }
+
+ /* get sign of Y */
+ pub fn gets(&self) -> isize {
+ let y = self.gety();
+ return y.parity();
+ }
+
+ /* extract x as an FP */
+ pub fn getpx(&self) -> FP {
+ let w = FP::new_copy(&self.x);
+ return w;
+ }
+ /* extract y as an FP */
+ pub fn getpy(&self) -> FP {
+ let w = FP::new_copy(&self.y);
+ return w;
+ }
+
+ /* extract z as an FP */
+ pub fn getpz(&self) -> FP {
+ let w = FP::new_copy(&self.z);
+ return w;
+ }
+
+ /* convert to byte array */
+ pub fn tobytes(&self, b: &mut [u8], compress: bool) {
+ let mb = big::MODBYTES as usize;
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mut W = ECP::new();
+ W.copy(self);
+
+ W.affine();
+ W.x.redc().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 1] = t[i]
+ }
+
+ if CURVETYPE == CurveType::MONTGOMERY {
+ b[0] = 0x06;
+ return;
+ }
+
+ if compress {
+ b[0] = 0x02;
+ if W.y.redc().parity() == 1 {
+ b[0] = 0x03
+ }
+ return;
+ }
+
+ b[0] = 0x04;
+
+ W.y.redc().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + mb + 1] = t[i]
+ }
+ }
+
+ /* convert from byte array to point */
+ pub fn frombytes(b: &[u8]) -> ECP {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+ let p = BIG::new_ints(&rom::MODULUS);
+
+ for i in 0..mb {
+ t[i] = b[i + 1]
+ }
+ let px = BIG::frombytes(&t);
+ if BIG::comp(&px, &p) >= 0 {
+ return ECP::new();
+ }
+
+ if CURVETYPE == CurveType::MONTGOMERY {
+ return ECP::new_big(&px);
+ }
+
+ if b[0] == 0x04 {
+ for i in 0..mb {
+ t[i] = b[i + mb + 1]
+ }
+ let py = BIG::frombytes(&t);
+ if BIG::comp(&py, &p) >= 0 {
+ return ECP::new();
+ }
+ return ECP::new_bigs(&px, &py);
+ }
+
+ if b[0] == 0x02 || b[0] == 0x03 {
+ return ECP::new_bigint(&px, (b[0] & 1) as isize);
+ }
+
+ return ECP::new();
+ }
+
+ /* convert to hex string */
+ pub fn tostring(&self) -> String {
+ let mut W = ECP::new();
+ W.copy(self);
+ if W.is_infinity() {
+ return String::from("infinity");
+ }
+ if CURVETYPE == CurveType::MONTGOMERY {
+ return format!("({})", W.x.redc().tostring());
+ } else {
+ return format!("({},{})", W.x.redc().tostring(), W.y.redc().tostring());
+ };
+ }
+
+ pub fn to_hex(&self) -> String {
+ format!("{} {} {}", self.x.to_hex(), self.y.to_hex(), self.z.to_hex())
+ }
+
+ pub fn from_hex_iter(iter: &mut SplitWhitespace) -> ECP {
+ ECP {
+ x: FP::from_hex_iter(iter),
+ y: FP::from_hex_iter(iter),
+ z: FP::from_hex_iter(iter),
+ }
+ }
+
+ pub fn from_hex(val: String) -> ECP {
+ let mut iter = val.split_whitespace();
+ return ECP::from_hex_iter(&mut iter);
+ }
+
+ /* this*=2 */
+ pub fn dbl(&mut self) {
+ if CURVETYPE == CurveType::WEIERSTRASS {
+ if rom::CURVE_A == 0 {
+ let mut t0 = FP::new_copy(&self.y);
+ t0.sqr();
+ let mut t1 = FP::new_copy(&self.y);
+ t1.mul(&self.z);
+ let mut t2 = FP::new_copy(&self.z);
+ t2.sqr();
+
+ self.z.copy(&t0);
+ self.z.add(&t0);
+ self.z.norm();
+ self.z.dbl();
+ self.z.dbl();
+ self.z.norm();
+ t2.imul(3 * rom::CURVE_B_I);
+
+ let mut x3 = FP::new_copy(&t2);
+ x3.mul(&self.z);
+
+ let mut y3 = FP::new_copy(&t0);
+ y3.add(&t2);
+ y3.norm();
+ self.z.mul(&t1);
+ t1.copy(&t2);
+ t1.add(&t2);
+ t2.add(&t1);
+ t0.sub(&t2);
+ t0.norm();
+ y3.mul(&t0);
+ y3.add(&x3);
+ t1.copy(&self.x);
+ t1.mul(&self.y);
+ self.x.copy(&t0);
+ self.x.norm();
+ self.x.mul(&t1);
+ self.x.dbl();
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ } else {
+ let mut t0 = FP::new_copy(&self.x);
+ let mut t1 = FP::new_copy(&self.y);
+ let mut t2 = FP::new_copy(&self.z);
+ let mut t3 = FP::new_copy(&self.x);
+ let mut z3 = FP::new_copy(&self.z);
+ let mut y3 = FP::new();
+ let mut x3 = FP::new();
+ let mut b = FP::new();
+
+ if rom::CURVE_B_I == 0 {
+ b.copy(&FP::new_big(&BIG::new_ints(&rom::CURVE_B)));
+ }
+
+ t0.sqr(); //1 x^2
+ t1.sqr(); //2 y^2
+ t2.sqr(); //3
+
+ t3.mul(&self.y); //4
+ t3.dbl();
+ t3.norm(); //5
+ z3.mul(&self.x); //6
+ z3.dbl();
+ z3.norm(); //7
+ y3.copy(&t2);
+
+ if rom::CURVE_B_I == 0 {
+ y3.mul(&b); //8
+ } else {
+ y3.imul(rom::CURVE_B_I);
+ }
+
+ y3.sub(&z3); //9 ***
+ x3.copy(&y3);
+ x3.add(&y3);
+ x3.norm(); //10
+
+ y3.add(&x3); //11
+ x3.copy(&t1);
+ x3.sub(&y3);
+ x3.norm(); //12
+ y3.add(&t1);
+ y3.norm(); //13
+ y3.mul(&x3); //14
+ x3.mul(&t3); //15
+ t3.copy(&t2);
+ t3.add(&t2); //16
+ t2.add(&t3); //17
+
+ if rom::CURVE_B_I == 0 {
+ z3.mul(&b); //18
+ } else {
+ z3.imul(rom::CURVE_B_I);
+ }
+
+ z3.sub(&t2); //19
+ z3.sub(&t0);
+ z3.norm(); //20 ***
+ t3.copy(&z3);
+ t3.add(&z3); //21
+
+ z3.add(&t3);
+ z3.norm(); //22
+ t3.copy(&t0);
+ t3.add(&t0); //23
+ t0.add(&t3); //24
+ t0.sub(&t2);
+ t0.norm(); //25
+
+ t0.mul(&z3); //26
+ y3.add(&t0); //27
+ t0.copy(&self.y);
+ t0.mul(&self.z); //28
+ t0.dbl();
+ t0.norm(); //29
+ z3.mul(&t0); //30
+ x3.sub(&z3); //31
+ t0.dbl();
+ t0.norm(); //32
+ t1.dbl();
+ t1.norm(); //33
+ z3.copy(&t0);
+ z3.mul(&t1); //34
+
+ self.x.copy(&x3);
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ self.z.copy(&z3);
+ self.z.norm();
+ }
+ }
+ if CURVETYPE == CurveType::EDWARDS {
+ let mut c = FP::new_copy(&self.x);
+ let mut d = FP::new_copy(&self.y);
+ let mut h = FP::new_copy(&self.z);
+ let mut j = FP::new();
+
+ self.x.mul(&self.y);
+ self.x.dbl();
+ self.x.norm();
+ c.sqr();
+ d.sqr();
+ if rom::CURVE_A == -1 {
+ c.neg()
+ }
+ self.y.copy(&c);
+ self.y.add(&d);
+ self.y.norm();
+ h.sqr();
+ h.dbl();
+ self.z.copy(&self.y);
+ j.copy(&self.y);
+ j.sub(&h);
+ j.norm();
+ self.x.mul(&j);
+ c.sub(&d);
+ c.norm();
+ self.y.mul(&c);
+ self.z.mul(&j);
+ }
+ if CURVETYPE == CurveType::MONTGOMERY {
+ let mut a = FP::new_copy(&self.x);
+ let mut b = FP::new_copy(&self.x);
+ let mut aa = FP::new();
+ let mut bb = FP::new();
+ let mut c = FP::new();
+
+ a.add(&self.z);
+ a.norm();
+ aa.copy(&a);
+ aa.sqr();
+ b.sub(&self.z);
+ b.norm();
+ bb.copy(&b);
+ bb.sqr();
+ c.copy(&aa);
+ c.sub(&bb);
+ c.norm();
+
+ self.x.copy(&aa);
+ self.x.mul(&bb);
+
+ a.copy(&c);
+ a.imul((rom::CURVE_A + 2) / 4);
+
+ bb.add(&a);
+ bb.norm();
+ self.z.copy(&bb);
+ self.z.mul(&c);
+ }
+ return;
+ }
+
+ /* self+=Q */
+ pub fn add(&mut self, Q: &ECP) {
+ if CURVETYPE == CurveType::WEIERSTRASS {
+ if rom::CURVE_A == 0 {
+ let b = 3 * rom::CURVE_B_I;
+ let mut t0 = FP::new_copy(&self.x);
+ t0.mul(&Q.x);
+ let mut t1 = FP::new_copy(&self.y);
+ t1.mul(&Q.y);
+ let mut t2 = FP::new_copy(&self.z);
+ t2.mul(&Q.z);
+ let mut t3 = FP::new_copy(&self.x);
+ t3.add(&self.y);
+ t3.norm();
+ let mut t4 = FP::new_copy(&Q.x);
+ t4.add(&Q.y);
+ t4.norm();
+ t3.mul(&t4);
+ t4.copy(&t0);
+ t4.add(&t1);
+
+ t3.sub(&t4);
+ t3.norm();
+ t4.copy(&self.y);
+ t4.add(&self.z);
+ t4.norm();
+ let mut x3 = FP::new_copy(&Q.y);
+ x3.add(&Q.z);
+ x3.norm();
+
+ t4.mul(&x3);
+ x3.copy(&t1);
+ x3.add(&t2);
+
+ t4.sub(&x3);
+ t4.norm();
+ x3.copy(&self.x);
+ x3.add(&self.z);
+ x3.norm();
+ let mut y3 = FP::new_copy(&Q.x);
+ y3.add(&Q.z);
+ y3.norm();
+ x3.mul(&y3);
+ y3.copy(&t0);
+ y3.add(&t2);
+ y3.rsub(&x3);
+ y3.norm();
+ x3.copy(&t0);
+ x3.add(&t0);
+ t0.add(&x3);
+ t0.norm();
+ t2.imul(b);
+
+ let mut z3 = FP::new_copy(&t1);
+ z3.add(&t2);
+ z3.norm();
+ t1.sub(&t2);
+ t1.norm();
+ y3.imul(b);
+
+ x3.copy(&y3);
+ x3.mul(&t4);
+ t2.copy(&t3);
+ t2.mul(&t1);
+ x3.rsub(&t2);
+ y3.mul(&t0);
+ t1.mul(&z3);
+ y3.add(&t1);
+ t0.mul(&t3);
+ z3.mul(&t4);
+ z3.add(&t0);
+
+ self.x.copy(&x3);
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ self.z.copy(&z3);
+ self.z.norm();
+ } else {
+ let mut t0 = FP::new_copy(&self.x);
+ let mut t1 = FP::new_copy(&self.y);
+ let mut t2 = FP::new_copy(&self.z);
+ let mut t3 = FP::new_copy(&self.x);
+ let mut t4 = FP::new_copy(&Q.x);
+ let mut z3 = FP::new();
+ let mut y3 = FP::new_copy(&Q.x);
+ let mut x3 = FP::new_copy(&Q.y);
+ let mut b = FP::new();
+
+ if rom::CURVE_B_I == 0 {
+ b.copy(&FP::new_big(&BIG::new_ints(&rom::CURVE_B)));
+ }
+
+ t0.mul(&Q.x); //1
+ t1.mul(&Q.y); //2
+ t2.mul(&Q.z); //3
+
+ t3.add(&self.y);
+ t3.norm(); //4
+ t4.add(&Q.y);
+ t4.norm(); //5
+ t3.mul(&t4); //6
+ t4.copy(&t0);
+ t4.add(&t1); //7
+ t3.sub(&t4);
+ t3.norm(); //8
+ t4.copy(&self.y);
+ t4.add(&self.z);
+ t4.norm(); //9
+ x3.add(&Q.z);
+ x3.norm(); //10
+ t4.mul(&x3); //11
+ x3.copy(&t1);
+ x3.add(&t2); //12
+
+ t4.sub(&x3);
+ t4.norm(); //13
+ x3.copy(&self.x);
+ x3.add(&self.z);
+ x3.norm(); //14
+ y3.add(&Q.z);
+ y3.norm(); //15
+
+ x3.mul(&y3); //16
+ y3.copy(&t0);
+ y3.add(&t2); //17
+
+ y3.rsub(&x3);
+ y3.norm(); //18
+ z3.copy(&t2);
+
+ if rom::CURVE_B_I == 0 {
+ z3.mul(&b); //18
+ } else {
+ z3.imul(rom::CURVE_B_I);
+ }
+
+ x3.copy(&y3);
+ x3.sub(&z3);
+ x3.norm(); //20
+ z3.copy(&x3);
+ z3.add(&x3); //21
+
+ x3.add(&z3); //22
+ z3.copy(&t1);
+ z3.sub(&x3);
+ z3.norm(); //23
+ x3.add(&t1);
+ x3.norm(); //24
+
+ if rom::CURVE_B_I == 0 {
+ y3.mul(&b); //18
+ } else {
+ y3.imul(rom::CURVE_B_I);
+ }
+
+ t1.copy(&t2);
+ t1.add(&t2); //t1.norm();//26
+ t2.add(&t1); //27
+
+ y3.sub(&t2); //28
+
+ y3.sub(&t0);
+ y3.norm(); //29
+ t1.copy(&y3);
+ t1.add(&y3); //30
+ y3.add(&t1);
+ y3.norm(); //31
+
+ t1.copy(&t0);
+ t1.add(&t0); //32
+ t0.add(&t1); //33
+ t0.sub(&t2);
+ t0.norm(); //34
+ t1.copy(&t4);
+ t1.mul(&y3); //35
+ t2.copy(&t0);
+ t2.mul(&y3); //36
+ y3.copy(&x3);
+ y3.mul(&z3); //37
+ y3.add(&t2); //y3.norm();//38
+ x3.mul(&t3); //39
+ x3.sub(&t1); //40
+ z3.mul(&t4); //41
+ t1.copy(&t3);
+ t1.mul(&t0); //42
+ z3.add(&t1);
+ self.x.copy(&x3);
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ self.z.copy(&z3);
+ self.z.norm();
+ }
+ }
+ if CURVETYPE == CurveType::EDWARDS {
+ let bb = FP::new_big(&BIG::new_ints(&rom::CURVE_B));
+ let mut a = FP::new_copy(&self.z);
+ let mut b = FP::new();
+ let mut c = FP::new_copy(&self.x);
+ let mut d = FP::new_copy(&self.y);
+ let mut e = FP::new();
+ let mut f = FP::new();
+ let mut g = FP::new();
+
+ a.mul(&Q.z);
+ b.copy(&a);
+ b.sqr();
+ c.mul(&Q.x);
+ d.mul(&Q.y);
+
+ e.copy(&c);
+ e.mul(&d);
+ e.mul(&bb);
+ f.copy(&b);
+ f.sub(&e);
+ g.copy(&b);
+ g.add(&e);
+
+ if rom::CURVE_A == 1 {
+ e.copy(&d);
+ e.sub(&c);
+ }
+ c.add(&d);
+
+ b.copy(&self.x);
+ b.add(&self.y);
+ d.copy(&Q.x);
+ d.add(&Q.y);
+ b.norm();
+ d.norm();
+ b.mul(&d);
+ b.sub(&c);
+ b.norm();
+ f.norm();
+ b.mul(&f);
+ self.x.copy(&a);
+ self.x.mul(&b);
+ g.norm();
+ if rom::CURVE_A == 1 {
+ e.norm();
+ c.copy(&e);
+ c.mul(&g);
+ }
+ if rom::CURVE_A == -1 {
+ c.norm();
+ c.mul(&g);
+ }
+ self.y.copy(&a);
+ self.y.mul(&c);
+ self.z.copy(&f);
+ self.z.mul(&g);
+ }
+ return;
+ }
+
+ /* Differential Add for Montgomery curves. this+=Q where W is this-Q and is affine. */
+ pub fn dadd(&mut self, Q: &ECP, W: &ECP) {
+ let mut a = FP::new_copy(&self.x);
+ let mut b = FP::new_copy(&self.x);
+ let mut c = FP::new_copy(&Q.x);
+ let mut d = FP::new_copy(&Q.x);
+ let mut da = FP::new();
+ let mut cb = FP::new();
+
+ a.add(&self.z);
+ b.sub(&self.z);
+
+ c.add(&Q.z);
+ d.sub(&Q.z);
+
+ a.norm();
+ d.norm();
+
+ da.copy(&d);
+ da.mul(&a);
+
+ c.norm();
+ b.norm();
+
+ cb.copy(&c);
+ cb.mul(&b);
+
+ a.copy(&da);
+ a.add(&cb);
+ a.norm();
+ a.sqr();
+ b.copy(&da);
+ b.sub(&cb);
+ b.norm();
+ b.sqr();
+
+ self.x.copy(&a);
+ self.z.copy(&W.x);
+ self.z.mul(&b);
+ }
+
+ /* self-=Q */
+ pub fn sub(&mut self, Q: &ECP) {
+ let mut NQ = ECP::new();
+ NQ.copy(Q);
+ NQ.neg();
+ self.add(&NQ);
+ }
+
+ /* constant time multiply by small integer of length bts - use ladder */
+ pub fn pinmul(&self, e: i32, bts: i32) -> ECP {
+ if CURVETYPE == CurveType::MONTGOMERY {
+ return self.mul(&mut BIG::new_int(e as isize));
+ } else {
+ let mut P = ECP::new();
+ let mut R0 = ECP::new();
+ let mut R1 = ECP::new();
+ R1.copy(&self);
+
+ for i in (0..bts).rev() {
+ let b = ((e >> i) & 1) as isize;
+ P.copy(&R1);
+ P.add(&mut R0);
+ R0.cswap(&mut R1, b);
+ R1.copy(&P);
+ R0.dbl();
+ R0.cswap(&mut R1, b);
+ }
+ P.copy(&R0);
+ P.affine();
+ return P;
+ }
+ }
+
+ /* return e.self */
+
+ pub fn mul(&self, e: &BIG) -> ECP {
+ if e.iszilch() || self.is_infinity() {
+ return ECP::new();
+ }
+ let mut P = ECP::new();
+ if CURVETYPE == CurveType::MONTGOMERY {
+ /* use Ladder */
+ let mut D = ECP::new();
+ let mut R0 = ECP::new();
+ R0.copy(&self);
+ let mut R1 = ECP::new();
+ R1.copy(&self);
+ R1.dbl();
+ D.copy(&self);
+ D.affine();
+ let nb = e.nbits();
+
+ for i in (0..nb - 1).rev() {
+ let b = e.bit(i);
+ P.copy(&R1);
+ P.dadd(&mut R0, &D);
+ R0.cswap(&mut R1, b);
+ R1.copy(&P);
+ R0.dbl();
+ R0.cswap(&mut R1, b);
+ }
+ P.copy(&R0)
+ } else {
+ // fixed size windows
+ let mut mt = BIG::new();
+ let mut t = BIG::new();
+ let mut Q = ECP::new();
+ let mut C = ECP::new();
+
+ let mut W: [ECP; 8] = [
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ];
+
+ const CT: usize = 1 + (big::NLEN * (big::BASEBITS as usize) + 3) / 4;
+ let mut w: [i8; CT] = [0; CT];
+
+ Q.copy(&self);
+ Q.dbl();
+
+ W[0].copy(&self);
+
+ for i in 1..8 {
+ C.copy(&W[i - 1]);
+ W[i].copy(&C);
+ W[i].add(&mut Q);
+ }
+
+ // make exponent odd - add 2P if even, P if odd
+ t.copy(&e);
+ let s = t.parity();
+ t.inc(1);
+ t.norm();
+ let ns = t.parity();
+ mt.copy(&t);
+ mt.inc(1);
+ mt.norm();
+ t.cmove(&mt, s);
+ Q.cmove(&self, ns);
+ C.copy(&Q);
+
+ let nb = 1 + (t.nbits() + 3) / 4;
+
+ // convert exponent to signed 4-bit window
+ for i in 0..nb {
+ w[i] = (t.lastbits(5) - 16) as i8;
+ t.dec(w[i] as isize);
+ t.norm();
+ t.fshr(4);
+ }
+ w[nb] = t.lastbits(5) as i8;
+
+ P.copy(&W[((w[nb] as usize) - 1) / 2]);
+ for i in (0..nb).rev() {
+ Q.selector(&W, w[i] as i32);
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.add(&mut Q);
+ }
+ P.sub(&mut C); /* apply correction */
+ }
+ P.affine();
+ return P;
+ }
+
+ /* Return e.this+f.Q */
+
+ pub fn mul2(&self, e: &BIG, Q: &ECP, f: &BIG) -> ECP {
+ let mut te = BIG::new();
+ let mut tf = BIG::new();
+ let mut mt = BIG::new();
+ let mut S = ECP::new();
+ let mut T = ECP::new();
+ let mut C = ECP::new();
+
+ let mut W: [ECP; 8] = [
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ECP::new(),
+ ];
+
+ const CT: usize = 1 + (big::NLEN * (big::BASEBITS as usize) + 1) / 2;
+ let mut w: [i8; CT] = [0; CT];
+
+ te.copy(e);
+ tf.copy(f);
+
+ // precompute table
+
+ W[1].copy(&self);
+ W[1].sub(Q);
+ W[2].copy(&self);
+ W[2].add(Q);
+ S.copy(&Q);
+ S.dbl();
+ C.copy(&W[1]);
+ W[0].copy(&C);
+ W[0].sub(&mut S); // copy to C is stupid Rust thing..
+ C.copy(&W[2]);
+ W[3].copy(&C);
+ W[3].add(&mut S);
+ T.copy(&self);
+ T.dbl();
+ C.copy(&W[1]);
+ W[5].copy(&C);
+ W[5].add(&mut T);
+ C.copy(&W[2]);
+ W[6].copy(&C);
+ W[6].add(&mut T);
+ C.copy(&W[5]);
+ W[4].copy(&C);
+ W[4].sub(&mut S);
+ C.copy(&W[6]);
+ W[7].copy(&C);
+ W[7].add(&mut S);
+
+ // if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction
+
+ let mut s = te.parity();
+ te.inc(1);
+ te.norm();
+ let mut ns = te.parity();
+ mt.copy(&te);
+ mt.inc(1);
+ mt.norm();
+ te.cmove(&mt, s);
+ T.cmove(&self, ns);
+ C.copy(&T);
+
+ s = tf.parity();
+ tf.inc(1);
+ tf.norm();
+ ns = tf.parity();
+ mt.copy(&tf);
+ mt.inc(1);
+ mt.norm();
+ tf.cmove(&mt, s);
+ S.cmove(&Q, ns);
+ C.add(&mut S);
+
+ mt.copy(&te);
+ mt.add(&tf);
+ mt.norm();
+ let nb = 1 + (mt.nbits() + 1) / 2;
+
+ // convert exponent to signed 2-bit window
+ for i in 0..nb {
+ let a = te.lastbits(3) - 4;
+ te.dec(a);
+ te.norm();
+ te.fshr(2);
+ let b = tf.lastbits(3) - 4;
+ tf.dec(b);
+ tf.norm();
+ tf.fshr(2);
+ w[i] = (4 * a + b) as i8;
+ }
+ w[nb] = (4 * te.lastbits(3) + tf.lastbits(3)) as i8;
+ S.copy(&W[((w[nb] as usize) - 1) / 2]);
+
+ for i in (0..nb).rev() {
+ T.selector(&W, w[i] as i32);
+ S.dbl();
+ S.dbl();
+ S.add(&mut T);
+ }
+ S.sub(&mut C); /* apply correction */
+ S.affine();
+ return S;
+ }
+
+ // Multiply itself by cofactor of the curve
+ pub fn cfp(&mut self) {
+ let cf = rom::CURVE_COF_I;
+ if cf == 1 {
+ return;
+ }
+ if cf == 4 {
+ self.dbl();
+ self.dbl();
+ return;
+ }
+ if cf == 8 {
+ self.dbl();
+ self.dbl();
+ self.dbl();
+ return;
+ }
+ let c = BIG::new_ints(&rom::CURVE_COF);
+ let P = self.mul(&c);
+ self.copy(&P);
+ }
+
+ // Map a given byte slice to a point on the curve. The byte slice should be atleast the size of the modulus
+ #[allow(non_snake_case)]
+ pub fn mapit(h: &[u8]) -> ECP {
+ let mut q = BIG::new_ints(&rom::MODULUS);
+ let mut x = BIG::frombytes(h);
+ x.rmod(&mut q);
+ let mut P: ECP;
+
+ loop {
+ loop {
+ if CURVETYPE != CurveType::MONTGOMERY {
+ P = ECP::new_bigint(&x, 0);
+ } else {
+ P = ECP::new_big(&x);
+ }
+ x.inc(1);
+ x.norm();
+ if !P.is_infinity() {
+ break;
+ }
+ }
+ P.cfp();
+ if !P.is_infinity() {
+ break;
+ }
+ }
+
+ return P;
+ }
+
+ pub fn generator() -> ECP {
+ let G: ECP;
+
+ let gx = BIG::new_ints(&rom::CURVE_GX);
+
+ if CURVETYPE != CurveType::MONTGOMERY {
+ let gy = BIG::new_ints(&rom::CURVE_GY);
+ G = ECP::new_bigs(&gx, &gy);
+ } else {
+ G = ECP::new_big(&gx);
+ }
+ return G;
+ }
+}
diff --git a/src/ecp2.rs b/src/ecp2.rs
new file mode 100644
index 0000000..afd9376
--- /dev/null
+++ b/src/ecp2.rs
@@ -0,0 +1,784 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::rom;
+use super::big;
+use super::ecp;
+use super::fp2::FP2;
+use super::big::BIG;
+use types::{SexticTwist, CurvePairingType, SignOfX};
+use std::str::SplitWhitespace;
+use std::fmt;
+
+#[derive(Copy, Clone)]
+pub struct ECP2 {
+ x: FP2,
+ y: FP2,
+ z: FP2,
+}
+
+impl PartialEq for ECP2 {
+ fn eq(&self, other: &ECP2) -> bool {
+ self.equals(other)
+ }
+}
+
+impl fmt::Display for ECP2 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ECP2: [ {}, {}, {} ]", self.x, self.y, self.z)
+ }
+}
+
+impl fmt::Debug for ECP2 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ECP2: [ {}, {}, {} ]", self.x, self.y, self.z)
+ }
+}
+
+#[allow(non_snake_case)]
+impl ECP2 {
+ pub fn new() -> ECP2 {
+ ECP2 {
+ x: FP2::new(),
+ y: FP2::new_int(1),
+ z: FP2::new(),
+ }
+ }
+ #[allow(non_snake_case)]
+ /* construct this from (x,y) - but set to O if not on curve */
+ pub fn new_fp2s(ix: &FP2, iy: &FP2) -> ECP2 {
+ let mut E = ECP2::new();
+ E.x.copy(&ix);
+ E.y.copy(&iy);
+ E.z.one();
+ E.x.norm();
+
+ let mut rhs = ECP2::rhs(&E.x);
+ let mut y2 = FP2::new_copy(&E.y);
+ y2.sqr();
+ if !y2.equals(&mut rhs) {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* construct this from x - but set to O if not on curve */
+ pub fn new_fp2(ix: &FP2) -> ECP2 {
+ let mut E = ECP2::new();
+ E.x.copy(&ix);
+ E.y.one();
+ E.z.one();
+ E.x.norm();
+ let mut rhs = ECP2::rhs(&E.x);
+ if rhs.sqrt() {
+ E.y.copy(&rhs);
+ } else {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* Test this=O? */
+ pub fn is_infinity(&self) -> bool {
+ self.x.iszilch() && self.z.iszilch()
+ }
+
+ /* copy self=P */
+ pub fn copy(&mut self, P: &ECP2) {
+ self.x.copy(&P.x);
+ self.y.copy(&P.y);
+ self.z.copy(&P.z);
+ }
+
+ /* set self=O */
+ pub fn inf(&mut self) {
+ self.x.zero();
+ self.y.one();
+ self.z.zero();
+ }
+
+ /* set self=-self */
+ pub fn neg(&mut self) {
+ self.y.norm();
+ self.y.neg();
+ self.y.norm();
+ }
+
+ /* Conditional move of Q to self dependant on d */
+ pub fn cmove(&mut self, Q: &ECP2, d: isize) {
+ self.x.cmove(&Q.x, d);
+ self.y.cmove(&Q.y, d);
+ self.z.cmove(&Q.z, d);
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* Constant time select from pre-computed table */
+ pub fn selector(&mut self, W: &[ECP2], b: i32) {
+ let mut MP = ECP2::new();
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&W[0], ECP2::teq(babs, 0)); // conditional move
+ self.cmove(&W[1], ECP2::teq(babs, 1));
+ self.cmove(&W[2], ECP2::teq(babs, 2));
+ self.cmove(&W[3], ECP2::teq(babs, 3));
+ self.cmove(&W[4], ECP2::teq(babs, 4));
+ self.cmove(&W[5], ECP2::teq(babs, 5));
+ self.cmove(&W[6], ECP2::teq(babs, 6));
+ self.cmove(&W[7], ECP2::teq(babs, 7));
+
+ MP.copy(self);
+ MP.neg();
+ self.cmove(&MP, (m & 1) as isize);
+ }
+
+ /* Test if P == Q */
+ pub fn equals(&self, Q: &ECP2) -> bool {
+ let mut a = FP2::new_copy(&self.x);
+ let mut b = FP2::new_copy(&Q.x);
+
+ a.mul(&Q.z);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+ a.copy(&self.y);
+ a.mul(&Q.z);
+ b.copy(&Q.y);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /* set to Affine - (x,y,z) to (x,y) */
+ pub fn affine(&mut self) {
+ if self.is_infinity() {
+ return;
+ }
+ let mut one = FP2::new_int(1);
+ if self.z.equals(&mut one) {
+ return;
+ }
+ self.z.inverse();
+
+ self.x.mul(&self.z);
+ self.x.reduce();
+ self.y.mul(&self.z);
+ self.y.reduce();
+ self.z.copy(&one);
+ }
+
+ /* extract affine x as FP2 */
+ pub fn getx(&self) -> FP2 {
+ let mut W = ECP2::new();
+ W.copy(self);
+ W.affine();
+ return FP2::new_copy(&W.x);
+ }
+
+ /* extract affine y as FP2 */
+ pub fn gety(&self) -> FP2 {
+ let mut W = ECP2::new();
+ W.copy(self);
+ W.affine();
+ return FP2::new_copy(&W.y);
+ }
+
+ /* extract projective x */
+ pub fn getpx(&self) -> FP2 {
+ return FP2::new_copy(&self.x);
+ }
+ /* extract projective y */
+ pub fn getpy(&self) -> FP2 {
+ return FP2::new_copy(&self.y);
+ }
+ /* extract projective z */
+ pub fn getpz(&self) -> FP2 {
+ return FP2::new_copy(&self.z);
+ }
+
+ /* convert to byte array */
+ pub fn tobytes(&self, b: &mut [u8]) {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+ let mut W = ECP2::new();
+ W.copy(self);
+
+ W.affine();
+ W.x.geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i] = t[i]
+ }
+ W.x.getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + mb] = t[i]
+ }
+
+ W.y.geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 2 * mb] = t[i]
+ }
+ W.y.getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 3 * mb] = t[i]
+ }
+ }
+
+ /* convert from byte array to point */
+ pub fn frombytes(b: &[u8]) -> ECP2 {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ for i in 0..mb {
+ t[i] = b[i]
+ }
+ let mut ra = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = b[i + mb]
+ }
+ let mut rb = BIG::frombytes(&t);
+ let rx = FP2::new_bigs(&ra, &rb);
+
+ for i in 0..mb {
+ t[i] = b[i + 2 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 3 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+ let ry = FP2::new_bigs(&ra, &rb);
+
+ return ECP2::new_fp2s(&rx, &ry);
+ }
+
+ /* convert this to hex string */
+ pub fn tostring(&self) -> String {
+ let mut W = ECP2::new();
+ W.copy(self);
+ W.affine();
+ if W.is_infinity() {
+ return String::from("infinity");
+ }
+ return format!("({},{})", W.x.tostring(), W.y.tostring());
+ }
+
+ pub fn to_hex(&self) -> String {
+ format!("{} {} {}", self.x.to_hex(), self.y.to_hex(), self.z.to_hex())
+ }
+
+ pub fn from_hex_iter(iter: &mut SplitWhitespace) -> ECP2 {
+ ECP2 {
+ x: FP2::from_hex_iter(iter),
+ y: FP2::from_hex_iter(iter),
+ z: FP2::from_hex_iter(iter)
+ }
+ }
+
+ pub fn from_hex(val: String) -> ECP2 {
+ let mut iter = val.split_whitespace();
+ return ECP2::from_hex_iter(&mut iter);
+ }
+
+ /* Calculate RHS of twisted curve equation x^3+B/i */
+ pub fn rhs(x: &FP2) -> FP2 {
+ let mut r = FP2::new_copy(x);
+ r.sqr();
+ let mut b = FP2::new_big(&BIG::new_ints(&rom::CURVE_B));
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.div_ip();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ b.norm();
+ b.mul_ip();
+ b.norm();
+ }
+
+ r.mul(x);
+ r.add(&b);
+
+ r.reduce();
+ return r;
+ }
+
+ /* self+=self */
+ pub fn dbl(&mut self) -> isize {
+ let mut iy = FP2::new_copy(&self.y);
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ iy.mul_ip();
+ iy.norm();
+ }
+
+ let mut t0 = FP2::new_copy(&self.y); //***** Change
+ t0.sqr();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t0.mul_ip();
+ }
+ let mut t1 = FP2::new_copy(&iy);
+ t1.mul(&self.z);
+ let mut t2 = FP2::new_copy(&self.z);
+ t2.sqr();
+
+ self.z.copy(&t0);
+ self.z.add(&t0);
+ self.z.norm();
+ self.z.dbl();
+ self.z.dbl();
+ self.z.norm();
+
+ t2.imul(3 * rom::CURVE_B_I);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ t2.mul_ip();
+ t2.norm();
+ }
+ let mut x3 = FP2::new_copy(&t2);
+ x3.mul(&self.z);
+
+ let mut y3 = FP2::new_copy(&t0);
+
+ y3.add(&t2);
+ y3.norm();
+ self.z.mul(&t1);
+ t1.copy(&t2);
+ t1.add(&t2);
+ t2.add(&t1);
+ t2.norm();
+ t0.sub(&t2);
+ t0.norm(); //y^2-9bz^2
+ y3.mul(&t0);
+ y3.add(&x3); //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2
+ t1.copy(&self.x);
+ t1.mul(&iy); //
+ self.x.copy(&t0);
+ self.x.norm();
+ self.x.mul(&t1);
+ self.x.dbl(); //(y^2-9bz^2)xy2
+
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+
+ return 1;
+ }
+
+ /* self+=Q - return 0 for add, 1 for double, -1 for O */
+ pub fn add(&mut self, Q: &ECP2) -> isize {
+ let b = 3 * rom::CURVE_B_I;
+ let mut t0 = FP2::new_copy(&self.x);
+ t0.mul(&Q.x); // x.Q.x
+ let mut t1 = FP2::new_copy(&self.y);
+ t1.mul(&Q.y); // y.Q.y
+
+ let mut t2 = FP2::new_copy(&self.z);
+ t2.mul(&Q.z);
+ let mut t3 = FP2::new_copy(&self.x);
+ t3.add(&self.y);
+ t3.norm(); //t3=X1+Y1
+ let mut t4 = FP2::new_copy(&Q.x);
+ t4.add(&Q.y);
+ t4.norm(); //t4=X2+Y2
+ t3.mul(&t4); //t3=(X1+Y1)(X2+Y2)
+ t4.copy(&t0);
+ t4.add(&t1); //t4=X1.X2+Y1.Y2
+
+ t3.sub(&t4);
+ t3.norm();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t3.mul_ip();
+ t3.norm(); //t3=(X1+Y1)(X2+Y2)-(X1.X2+Y1.Y2) = X1.Y2+X2.Y1
+ }
+ t4.copy(&self.y);
+ t4.add(&self.z);
+ t4.norm(); //t4=Y1+Z1
+ let mut x3 = FP2::new_copy(&Q.y);
+ x3.add(&Q.z);
+ x3.norm(); //x3=Y2+Z2
+
+ t4.mul(&x3); //t4=(Y1+Z1)(Y2+Z2)
+ x3.copy(&t1); //
+ x3.add(&t2); //X3=Y1.Y2+Z1.Z2
+
+ t4.sub(&x3);
+ t4.norm();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t4.mul_ip();
+ t4.norm(); //t4=(Y1+Z1)(Y2+Z2) - (Y1.Y2+Z1.Z2) = Y1.Z2+Y2.Z1
+ }
+ x3.copy(&self.x);
+ x3.add(&self.z);
+ x3.norm(); // x3=X1+Z1
+ let mut y3 = FP2::new_copy(&Q.x);
+ y3.add(&Q.z);
+ y3.norm(); // y3=X2+Z2
+ x3.mul(&y3); // x3=(X1+Z1)(X2+Z2)
+ y3.copy(&t0);
+ y3.add(&t2); // y3=X1.X2+Z1+Z2
+ y3.rsub(&x3);
+ y3.norm(); // y3=(X1+Z1)(X2+Z2) - (X1.X2+Z1.Z2) = X1.Z2+X2.Z1
+
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t0.mul_ip();
+ t0.norm(); // x.Q.x
+ t1.mul_ip();
+ t1.norm(); // y.Q.y
+ }
+ x3.copy(&t0);
+ x3.add(&t0);
+ t0.add(&x3);
+ t0.norm();
+ t2.imul(b);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ t2.mul_ip();
+ t2.norm();
+ }
+ let mut z3 = FP2::new_copy(&t1);
+ z3.add(&t2);
+ z3.norm();
+ t1.sub(&t2);
+ t1.norm();
+ y3.imul(b);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ y3.mul_ip();
+ y3.norm();
+ }
+ x3.copy(&y3);
+ x3.mul(&t4);
+ t2.copy(&t3);
+ t2.mul(&t1);
+ x3.rsub(&t2);
+ y3.mul(&t0);
+ t1.mul(&z3);
+ y3.add(&t1);
+ t0.mul(&t3);
+ z3.mul(&t4);
+ z3.add(&t0);
+
+ self.x.copy(&x3);
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ self.z.copy(&z3);
+ self.z.norm();
+
+ return 0;
+ }
+
+ /* set this-=Q */
+ pub fn sub(&mut self, Q: &ECP2) -> isize {
+ let mut NQ = ECP2::new();
+ NQ.copy(Q);
+ NQ.neg();
+ let d = self.add(&NQ);
+ return d;
+ }
+
+ /* set this*=q, where q is Modulus, using Frobenius */
+ pub fn frob(&mut self, x: &FP2) {
+ let mut x2 = FP2::new_copy(x);
+ x2.sqr();
+ self.x.conj();
+ self.y.conj();
+ self.z.conj();
+ self.z.reduce();
+ self.x.mul(&x2);
+ self.y.mul(&x2);
+ self.y.mul(x);
+ }
+
+ /* self*=e */
+ pub fn mul(&self, e: &BIG) -> ECP2 {
+ /* fixed size windows */
+ let mut mt = BIG::new();
+ let mut t = BIG::new();
+ let mut P = ECP2::new();
+ let mut Q = ECP2::new();
+ let mut C = ECP2::new();
+
+ if self.is_infinity() {
+ return P;
+ }
+
+ let mut W: [ECP2; 8] = [
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ];
+
+ const CT: usize = 1 + (big::NLEN * (big::BASEBITS as usize) + 3) / 4;
+ let mut w: [i8; CT] = [0; CT];
+
+ /* precompute table */
+ Q.copy(&self);
+ Q.dbl();
+
+ W[0].copy(&self);
+
+ for i in 1..8 {
+ C.copy(&W[i - 1]);
+ W[i].copy(&C);
+ W[i].add(&mut Q);
+ }
+
+ /* make exponent odd - add 2P if even, P if odd */
+ t.copy(&e);
+ let s = t.parity();
+ t.inc(1);
+ t.norm();
+ let ns = t.parity();
+ mt.copy(&t);
+ mt.inc(1);
+ mt.norm();
+ t.cmove(&mt, s);
+ Q.cmove(&self, ns);
+ C.copy(&Q);
+
+ let nb = 1 + (t.nbits() + 3) / 4;
+
+ /* convert exponent to signed 4-bit window */
+ for i in 0..nb {
+ w[i] = (t.lastbits(5) - 16) as i8;
+ t.dec(w[i] as isize);
+ t.norm();
+ t.fshr(4);
+ }
+ w[nb] = (t.lastbits(5)) as i8;
+
+ P.copy(&W[((w[nb] as usize) - 1) / 2]);
+ for i in (0..nb).rev() {
+ Q.selector(&W, w[i] as i32);
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.add(&mut Q);
+ }
+ P.sub(&mut C);
+ P.affine();
+ return P;
+ }
+
+ /* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3 */
+ // Bos & Costello https://eprint.iacr.org/2013/458.pdf
+ // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
+ // Side channel attack secure
+
+ pub fn mul4(Q: &mut [ECP2], u: &[BIG]) -> ECP2 {
+ let mut W = ECP2::new();
+ let mut P = ECP2::new();
+
+ let mut T: [ECP2; 8] = [
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ECP2::new(),
+ ];
+
+ let mut mt = BIG::new();
+
+ let mut t: [BIG; 4] = [
+ BIG::new_copy(&u[0]),
+ BIG::new_copy(&u[1]),
+ BIG::new_copy(&u[2]),
+ BIG::new_copy(&u[3]),
+ ];
+
+ const CT: usize = 1 + big::NLEN * (big::BASEBITS as usize);
+ let mut w: [i8; CT] = [0; CT];
+ let mut s: [i8; CT] = [0; CT];
+
+ for i in 0..4 {
+ t[i].norm();
+ }
+
+ T[0].copy(&Q[0]);
+ W.copy(&T[0]);
+ T[1].copy(&W);
+ T[1].add(&mut Q[1]); // Q[0]+Q[1]
+ T[2].copy(&W);
+ T[2].add(&mut Q[2]);
+ W.copy(&T[1]); // Q[0]+Q[2]
+ T[3].copy(&W);
+ T[3].add(&mut Q[2]);
+ W.copy(&T[0]); // Q[0]+Q[1]+Q[2]
+ T[4].copy(&W);
+ T[4].add(&mut Q[3]);
+ W.copy(&T[1]); // Q[0]+Q[3]
+ T[5].copy(&W);
+ T[5].add(&mut Q[3]);
+ W.copy(&T[2]); // Q[0]+Q[1]+Q[3]
+ T[6].copy(&W);
+ T[6].add(&mut Q[3]);
+ W.copy(&T[3]); // Q[0]+Q[2]+Q[3]
+ T[7].copy(&W);
+ T[7].add(&mut Q[3]); // Q[0]+Q[1]+Q[2]+Q[3]
+
+ // Make it odd
+ let pb = 1 - t[0].parity();
+ t[0].inc(pb);
+ t[0].norm();
+
+ // Number of bits
+ mt.zero();
+ for i in 0..4 {
+ mt.or(&t[i]);
+ }
+
+ let nb = 1 + mt.nbits();
+
+ // Sign pivot
+
+ s[nb - 1] = 1;
+ for i in 0..nb - 1 {
+ t[0].fshr(1);
+ s[i] = (2 * t[0].parity() - 1) as i8;
+ }
+
+ // Recoded exponent
+ for i in 0..nb {
+ w[i] = 0;
+ let mut k = 1;
+ for j in 1..4 {
+ let bt = s[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+ }
+
+ // Main loop
+ P.selector(&T, (2 * w[nb - 1] + 1) as i32);
+ for i in (0..nb - 1).rev() {
+ P.dbl();
+ W.selector(&T, (2 * w[i] + s[i]) as i32);
+ P.add(&mut W);
+ }
+
+ // apply correction
+ W.copy(&P);
+ W.sub(&mut Q[0]);
+ P.cmove(&W, pb);
+ P.affine();
+
+ return P;
+ }
+
+ #[allow(non_snake_case)]
+ pub fn mapit(h: &[u8]) -> ECP2 {
+ let mut q = BIG::new_ints(&rom::MODULUS);
+ let mut x = BIG::frombytes(h);
+ x.rmod(&mut q);
+ let mut Q: ECP2;
+ let one = BIG::new_int(1);
+
+ loop {
+ let X = FP2::new_bigs(&one, &x);
+ Q = ECP2::new_fp2(&X);
+ if !Q.is_infinity() {
+ break;
+ }
+ x.inc(1);
+ x.norm();
+ }
+ let mut X = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ X.inverse();
+ X.norm();
+ }
+ x = BIG::new_ints(&rom::CURVE_BNX);
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ let mut T = Q.mul(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ T.neg();
+ }
+ let mut K = ECP2::new();
+ K.copy(&T);
+ K.dbl();
+ K.add(&T);
+
+ K.frob(&X);
+ Q.frob(&X);
+ Q.frob(&X);
+ Q.frob(&X);
+ Q.add(&T);
+ Q.add(&K);
+ T.frob(&X);
+ T.frob(&X);
+ Q.add(&T);
+ }
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BLS {
+ let mut xQ = Q.mul(&mut x);
+ let mut x2Q = xQ.mul(&mut x);
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ xQ.neg();
+ }
+ x2Q.sub(&xQ);
+ x2Q.sub(&Q);
+
+ xQ.sub(&Q);
+ xQ.frob(&X);
+
+ Q.dbl();
+ Q.frob(&X);
+ Q.frob(&X);
+
+ Q.add(&x2Q);
+ Q.add(&xQ);
+ }
+
+ Q.affine();
+ return Q;
+ }
+
+ pub fn generator() -> ECP2 {
+ return ECP2::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXA),
+ &BIG::new_ints(&rom::CURVE_PXB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYA),
+ &BIG::new_ints(&rom::CURVE_PYB),
+ ),
+ );
+ }
+}
diff --git a/src/ecp4.rs b/src/ecp4.rs
new file mode 100644
index 0000000..d34b0fd
--- /dev/null
+++ b/src/ecp4.rs
@@ -0,0 +1,866 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::rom;
+use super::big;
+use super::ecp;
+use super::fp2::FP2;
+use super::fp4::FP4;
+use super::big::BIG;
+use types::{SexticTwist, SignOfX};
+//use std::str::SplitWhitespace;
+
+pub struct ECP4 {
+ x: FP4,
+ y: FP4,
+ z: FP4,
+}
+
+#[allow(non_snake_case)]
+impl ECP4 {
+ pub fn new() -> ECP4 {
+ ECP4 {
+ x: FP4::new(),
+ y: FP4::new_int(1),
+ z: FP4::new(),
+ }
+ }
+ #[allow(non_snake_case)]
+ /* construct this from (x,y) - but set to O if not on curve */
+ pub fn new_fp4s(ix: &FP4, iy: &FP4) -> ECP4 {
+ let mut E = ECP4::new();
+ E.x.copy(&ix);
+ E.y.copy(&iy);
+ E.z.one();
+ E.x.norm();
+
+ let mut rhs = ECP4::rhs(&E.x);
+ let mut y2 = FP4::new_copy(&E.y);
+ y2.sqr();
+ if !y2.equals(&mut rhs) {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* construct this from x - but set to O if not on curve */
+ pub fn new_fp4(ix: &FP4) -> ECP4 {
+ let mut E = ECP4::new();
+ E.x.copy(&ix);
+ E.y.one();
+ E.z.one();
+ E.x.norm();
+
+ let mut rhs = ECP4::rhs(&E.x);
+ if rhs.sqrt() {
+ E.y.copy(&rhs);
+ } else {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* Test this=O? */
+ pub fn is_infinity(&self) -> bool {
+ let xx = FP4::new_copy(&self.x);
+ let zz = FP4::new_copy(&self.z);
+ return xx.iszilch() && zz.iszilch();
+ }
+
+ /* copy self=P */
+ pub fn copy(&mut self, P: &ECP4) {
+ self.x.copy(&P.x);
+ self.y.copy(&P.y);
+ self.z.copy(&P.z);
+ }
+
+ /* set self=O */
+ pub fn inf(&mut self) {
+ self.x.zero();
+ self.y.one();
+ self.z.zero();
+ }
+
+ /* set self=-self */
+ pub fn neg(&mut self) {
+ self.y.norm();
+ self.y.neg();
+ self.y.norm();
+ }
+
+ /* Conditional move of Q to self dependant on d */
+ pub fn cmove(&mut self, Q: &ECP4, d: isize) {
+ self.x.cmove(&Q.x, d);
+ self.y.cmove(&Q.y, d);
+ self.z.cmove(&Q.z, d);
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* Constant time select from pre-computed table */
+ pub fn selector(&mut self, W: &[ECP4], b: i32) {
+ let mut MP = ECP4::new();
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&W[0], ECP4::teq(babs, 0)); // conditional move
+ self.cmove(&W[1], ECP4::teq(babs, 1));
+ self.cmove(&W[2], ECP4::teq(babs, 2));
+ self.cmove(&W[3], ECP4::teq(babs, 3));
+ self.cmove(&W[4], ECP4::teq(babs, 4));
+ self.cmove(&W[5], ECP4::teq(babs, 5));
+ self.cmove(&W[6], ECP4::teq(babs, 6));
+ self.cmove(&W[7], ECP4::teq(babs, 7));
+
+ MP.copy(self);
+ MP.neg();
+ self.cmove(&MP, (m & 1) as isize);
+ }
+
+ /* Test if P == Q */
+ pub fn equals(&mut self, Q: &mut ECP4) -> bool {
+ let mut a = FP4::new_copy(&self.x);
+ let mut b = FP4::new_copy(&Q.x);
+
+ a.mul(&Q.z);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+ a.copy(&self.y);
+ a.mul(&Q.z);
+ b.copy(&Q.y);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /* set to Affine - (x,y,z) to (x,y) */
+ pub fn affine(&mut self) {
+ if self.is_infinity() {
+ return;
+ }
+ let mut one = FP4::new_int(1);
+ if self.z.equals(&mut one) {
+ return;
+ }
+ self.z.inverse();
+
+ self.x.mul(&self.z);
+ self.x.reduce();
+ self.y.mul(&self.z);
+ self.y.reduce();
+ self.z.copy(&one);
+ }
+
+ /* extract affine x as FP4 */
+ pub fn getx(&self) -> FP4 {
+ let mut W = ECP4::new();
+ W.copy(self);
+ W.affine();
+ return FP4::new_copy(&self.x);
+ }
+
+ /* extract affine y as FP4 */
+ pub fn gety(&self) -> FP4 {
+ let mut W = ECP4::new();
+ W.copy(self);
+ W.affine();
+ return FP4::new_copy(&W.y);
+ }
+
+ /* extract projective x */
+ pub fn getpx(&self) -> FP4 {
+ return FP4::new_copy(&self.x);
+ }
+ /* extract projective y */
+ pub fn getpy(&self) -> FP4 {
+ return FP4::new_copy(&self.y);
+ }
+ /* extract projective z */
+ pub fn getpz(&self) -> FP4 {
+ return FP4::new_copy(&self.z);
+ }
+
+ /* convert to byte array */
+ pub fn tobytes(&self, b: &mut [u8]) {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ let mut W = ECP4::new();
+ W.copy(self);
+
+ W.affine();
+
+ W.x.geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i] = t[i]
+ }
+ W.x.geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + mb] = t[i]
+ }
+
+ W.x.getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 2 * mb] = t[i]
+ }
+ W.x.getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 3 * mb] = t[i]
+ }
+
+ W.y.geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 4 * mb] = t[i]
+ }
+ W.y.geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 5 * mb] = t[i]
+ }
+
+ W.y.getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 6 * mb] = t[i]
+ }
+ W.y.getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 7 * mb] = t[i]
+ }
+ }
+
+ /* convert from byte array to point */
+ pub fn frombytes(b: &[u8]) -> ECP4 {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ for i in 0..mb {
+ t[i] = b[i]
+ }
+ let mut ra = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = b[i + mb]
+ }
+ let mut rb = BIG::frombytes(&t);
+
+ let mut ra4 = FP2::new_bigs(&ra, &rb);
+
+ for i in 0..mb {
+ t[i] = b[i + 2 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 3 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ let mut rb4 = FP2::new_bigs(&ra, &rb);
+
+ let rx = FP4::new_fp2s(&ra4, &rb4);
+
+ for i in 0..mb {
+ t[i] = b[i + 4 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 5 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ ra4.copy(&FP2::new_bigs(&ra, &rb));
+
+ for i in 0..mb {
+ t[i] = b[i + 6 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 7 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ rb4.copy(&FP2::new_bigs(&ra, &rb));
+
+ let ry = FP4::new_fp2s(&ra4, &rb4);
+
+ return ECP4::new_fp4s(&rx, &ry);
+ }
+
+ /* convert this to hex string */
+ pub fn tostring(&self) -> String {
+ let mut W = ECP4::new();
+ W.copy(self);
+ W.affine();
+ if W.is_infinity() {
+ return String::from("infinity");
+ }
+ return format!("({},{})", W.x.tostring(), W.y.tostring());
+ }
+
+ /* Calculate RHS of twisted curve equation x^3+B/i */
+ pub fn rhs(x: &FP4) -> FP4 {
+ //x.norm();
+ let mut r = FP4::new_copy(x);
+ r.sqr();
+ let mut b = FP4::new_fp2(&FP2::new_big(&BIG::new_ints(&rom::CURVE_B)));
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.div_i();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ b.times_i();
+ }
+
+ r.mul(x);
+ r.add(&b);
+
+ r.reduce();
+ return r;
+ }
+
+ /* self+=self */
+ pub fn dbl(&mut self) -> isize {
+ let mut iy = FP4::new_copy(&self.y);
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ iy.times_i(); //iy.norm();
+ }
+
+ let mut t0 = FP4::new_copy(&self.y);
+ t0.sqr();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t0.times_i();
+ }
+ let mut t1 = FP4::new_copy(&iy);
+ t1.mul(&self.z);
+ let mut t2 = FP4::new_copy(&self.z);
+ t2.sqr();
+
+ self.z.copy(&t0);
+ self.z.add(&t0);
+ self.z.norm();
+ self.z.dbl();
+ self.z.dbl();
+ self.z.norm();
+
+ t2.imul(3 * rom::CURVE_B_I);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ t2.times_i();
+ }
+ let mut x3 = FP4::new_copy(&t2);
+ x3.mul(&self.z);
+
+ let mut y3 = FP4::new_copy(&t0);
+
+ y3.add(&t2);
+ y3.norm();
+ self.z.mul(&t1);
+ t1.copy(&t2);
+ t1.add(&t2);
+ t2.add(&t1);
+ t2.norm();
+ t0.sub(&t2);
+ t0.norm(); //y^2-9bz^2
+ y3.mul(&t0);
+ y3.add(&x3); //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2
+ t1.copy(&self.x);
+ t1.mul(&iy); //
+ self.x.copy(&t0);
+ self.x.norm();
+ self.x.mul(&t1);
+ self.x.dbl(); //(y^2-9bz^2)xy2
+
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+
+ return 1;
+ }
+
+ /* self+=Q - return 0 for add, 1 for double, -1 for O */
+ pub fn add(&mut self, Q: &ECP4) -> isize {
+ let b = 3 * rom::CURVE_B_I;
+ let mut t0 = FP4::new_copy(&self.x);
+ t0.mul(&Q.x); // x.Q.x
+ let mut t1 = FP4::new_copy(&self.y);
+ t1.mul(&Q.y); // y.Q.y
+
+ let mut t2 = FP4::new_copy(&self.z);
+ t2.mul(&Q.z);
+ let mut t3 = FP4::new_copy(&self.x);
+ t3.add(&self.y);
+ t3.norm(); //t3=X1+Y1
+ let mut t4 = FP4::new_copy(&Q.x);
+ t4.add(&Q.y);
+ t4.norm(); //t4=X2+Y2
+ t3.mul(&t4); //t3=(X1+Y1)(X2+Y2)
+ t4.copy(&t0);
+ t4.add(&t1); //t4=X1.X2+Y1.Y2
+
+ t3.sub(&t4);
+ t3.norm();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t3.times_i(); //t3=(X1+Y1)(X2+Y2)-(X1.X2+Y1.Y2) = X1.Y2+X2.Y1
+ }
+ t4.copy(&self.y);
+ t4.add(&self.z);
+ t4.norm(); //t4=Y1+Z1
+ let mut x3 = FP4::new_copy(&Q.y);
+ x3.add(&Q.z);
+ x3.norm(); //x3=Y2+Z2
+
+ t4.mul(&x3); //t4=(Y1+Z1)(Y2+Z2)
+ x3.copy(&t1); //
+ x3.add(&t2); //X3=Y1.Y2+Z1.Z2
+
+ t4.sub(&x3);
+ t4.norm();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t4.times_i(); //t4=(Y1+Z1)(Y2+Z2) - (Y1.Y2+Z1.Z2) = Y1.Z2+Y2.Z1
+ }
+ x3.copy(&self.x);
+ x3.add(&self.z);
+ x3.norm(); // x3=X1+Z1
+ let mut y3 = FP4::new_copy(&Q.x);
+ y3.add(&Q.z);
+ y3.norm(); // y3=X2+Z2
+ x3.mul(&y3); // x3=(X1+Z1)(X2+Z2)
+ y3.copy(&t0);
+ y3.add(&t2); // y3=X1.X2+Z1+Z2
+ y3.rsub(&x3);
+ y3.norm(); // y3=(X1+Z1)(X2+Z2) - (X1.X2+Z1.Z2) = X1.Z2+X2.Z1
+
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t0.times_i(); // x.Q.x
+ t1.times_i(); // y.Q.y
+ }
+ x3.copy(&t0);
+ x3.add(&t0);
+ t0.add(&x3);
+ t0.norm();
+ t2.imul(b);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ t2.times_i();
+ }
+ let mut z3 = FP4::new_copy(&t1);
+ z3.add(&t2);
+ z3.norm();
+ t1.sub(&t2);
+ t1.norm();
+ y3.imul(b);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ y3.times_i();
+ }
+ x3.copy(&y3);
+ x3.mul(&t4);
+ t2.copy(&t3);
+ t2.mul(&t1);
+ x3.rsub(&t2);
+ y3.mul(&t0);
+ t1.mul(&z3);
+ y3.add(&t1);
+ t0.mul(&t3);
+ z3.mul(&t4);
+ z3.add(&t0);
+
+ self.x.copy(&x3);
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ self.z.copy(&z3);
+ self.z.norm();
+
+ return 0;
+ }
+
+ /* set this-=Q */
+ pub fn sub(&mut self, Q: &ECP4) -> isize {
+ let mut NQ = ECP4::new();
+ NQ.copy(Q);
+ NQ.neg();
+ let d = self.add(&NQ);
+ return d;
+ }
+
+ pub fn frob_constants() -> [FP2; 3] {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+
+ let mut f0 = FP2::new_copy(&f);
+ f0.sqr();
+ let mut f2 = FP2::new_copy(&f0);
+ f2.mul_ip();
+ f2.norm();
+ let mut f1 = FP2::new_copy(&f2);
+ f1.sqr();
+ f2.mul(&f1);
+ f1.copy(&f);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ f1.mul_ip();
+ f1.inverse();
+ f0.copy(&f1);
+ f0.sqr();
+ }
+ f0.mul_ip();
+ f0.norm();
+ f1.mul(&f0);
+
+ let F: [FP2; 3] = [f0, f1, f2];
+ return F;
+ }
+
+ /* set this*=q, where q is Modulus, using Frobenius */
+ pub fn frob(&mut self, f: &[FP2; 3], n: isize) {
+ for _i in 0..n {
+ self.x.frob(&f[2]);
+ self.x.pmul(&f[0]);
+
+ self.y.frob(&f[2]);
+ self.y.pmul(&f[1]);
+ self.y.times_i();
+
+ self.z.frob(&f[2]);
+ }
+ }
+
+ /* self*=e */
+ pub fn mul(&self, e: &BIG) -> ECP4 {
+ /* fixed size windows */
+ let mut mt = BIG::new();
+ let mut t = BIG::new();
+ let mut P = ECP4::new();
+ let mut Q = ECP4::new();
+ let mut C = ECP4::new();
+
+ if self.is_infinity() {
+ return P;
+ }
+
+ let mut W: [ECP4; 8] = [
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ];
+
+ const CT: usize = 1 + (big::NLEN * (big::BASEBITS as usize) + 3) / 4;
+ let mut w: [i8; CT] = [0; CT];
+
+ /* precompute table */
+ Q.copy(&self);
+ Q.dbl();
+
+ W[0].copy(&self);
+
+ for i in 1..8 {
+ C.copy(&W[i - 1]);
+ W[i].copy(&C);
+ W[i].add(&mut Q);
+ }
+
+ /* make exponent odd - add 2P if even, P if odd */
+ t.copy(&e);
+ let s = t.parity();
+ t.inc(1);
+ t.norm();
+ let ns = t.parity();
+ mt.copy(&t);
+ mt.inc(1);
+ mt.norm();
+ t.cmove(&mt, s);
+ Q.cmove(&self, ns);
+ C.copy(&Q);
+
+ let nb = 1 + (t.nbits() + 3) / 4;
+
+ /* convert exponent to signed 4-bit window */
+ for i in 0..nb {
+ w[i] = (t.lastbits(5) - 16) as i8;
+ t.dec(w[i] as isize);
+ t.norm();
+ t.fshr(4);
+ }
+ w[nb] = (t.lastbits(5)) as i8;
+
+ P.copy(&W[((w[nb] as usize) - 1) / 2]);
+ for i in (0..nb).rev() {
+ Q.selector(&W, w[i] as i32);
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.add(&mut Q);
+ }
+ P.sub(&mut C);
+ P.affine();
+ return P;
+ }
+
+ /* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3.. */
+ // Bos & Costello https://eprint.iacr.org/2013/458.pdf
+ // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
+ // Side channel attack secure
+
+ pub fn mul8(Q: &mut [ECP4], u: &[BIG]) -> ECP4 {
+ let mut W = ECP4::new();
+ let mut P = ECP4::new();
+
+ let mut T1: [ECP4; 8] = [
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ];
+ let mut T2: [ECP4; 8] = [
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ];
+
+ let mut mt = BIG::new();
+
+ let mut t: [BIG; 8] = [
+ BIG::new_copy(&u[0]),
+ BIG::new_copy(&u[1]),
+ BIG::new_copy(&u[2]),
+ BIG::new_copy(&u[3]),
+ BIG::new_copy(&u[4]),
+ BIG::new_copy(&u[5]),
+ BIG::new_copy(&u[6]),
+ BIG::new_copy(&u[7]),
+ ];
+
+ const CT: usize = 1 + big::NLEN * (big::BASEBITS as usize);
+ let mut w1: [i8; CT] = [0; CT];
+ let mut s1: [i8; CT] = [0; CT];
+ let mut w2: [i8; CT] = [0; CT];
+ let mut s2: [i8; CT] = [0; CT];
+
+ for i in 0..8 {
+ //Q[i].affine();
+ t[i].norm();
+ }
+
+ T1[0].copy(&Q[0]);
+ W.copy(&T1[0]);
+ T1[1].copy(&W);
+ T1[1].add(&mut Q[1]); // Q[0]+Q[1]
+ T1[2].copy(&W);
+ T1[2].add(&mut Q[2]);
+ W.copy(&T1[1]); // Q[0]+Q[2]
+ T1[3].copy(&W);
+ T1[3].add(&mut Q[2]);
+ W.copy(&T1[0]); // Q[0]+Q[1]+Q[2]
+ T1[4].copy(&W);
+ T1[4].add(&mut Q[3]);
+ W.copy(&T1[1]); // Q[0]+Q[3]
+ T1[5].copy(&W);
+ T1[5].add(&mut Q[3]);
+ W.copy(&T1[2]); // Q[0]+Q[1]+Q[3]
+ T1[6].copy(&W);
+ T1[6].add(&mut Q[3]);
+ W.copy(&T1[3]); // Q[0]+Q[2]+Q[3]
+ T1[7].copy(&W);
+ T1[7].add(&mut Q[3]); // Q[0]+Q[1]+Q[2]+Q[3]
+
+ // Use frobenius
+ let f = ECP4::frob_constants();
+ for i in 0..8 {
+ T2[i].copy(&T1[i]);
+ T2[i].frob(&f, 4);
+ }
+
+ // Make it odd
+ let pb1 = 1 - t[0].parity();
+ t[0].inc(pb1);
+ t[0].norm();
+
+ let pb2 = 1 - t[4].parity();
+ t[4].inc(pb2);
+ t[4].norm();
+
+ // Number of bits
+ mt.zero();
+ for i in 0..8 {
+ mt.or(&t[i]);
+ }
+
+ let nb = 1 + mt.nbits();
+
+ // Sign pivot
+
+ s1[nb - 1] = 1;
+ s2[nb - 1] = 1;
+ for i in 0..nb - 1 {
+ t[0].fshr(1);
+ s1[i] = (2 * t[0].parity() - 1) as i8;
+ t[4].fshr(1);
+ s2[i] = (2 * t[4].parity() - 1) as i8;
+ }
+
+ // Recoded exponent
+ for i in 0..nb {
+ w1[i] = 0;
+ let mut k = 1;
+ for j in 1..4 {
+ let bt = s1[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w1[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w2[i] = 0;
+ k = 1;
+ for j in 5..8 {
+ let bt = s2[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w2[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+ }
+
+ // Main loop
+ P.selector(&T1, (2 * w1[nb - 1] + 1) as i32);
+ W.selector(&T2, (2 * w2[nb - 1] + 1) as i32);
+ P.add(&mut W);
+ for i in (0..nb - 1).rev() {
+ P.dbl();
+ W.selector(&T1, (2 * w1[i] + s1[i]) as i32);
+ P.add(&mut W);
+ W.selector(&T2, (2 * w2[i] + s2[i]) as i32);
+ P.add(&mut W);
+ }
+
+ // apply correction
+ W.copy(&P);
+ W.sub(&mut Q[0]);
+ P.cmove(&W, pb1);
+
+ W.copy(&P);
+ W.sub(&mut Q[4]);
+ P.cmove(&W, pb2);
+
+ P.affine();
+
+ return P;
+ }
+
+ pub fn generator() -> ECP4 {
+ return ECP4::new_fp4s(
+ &FP4::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXAA),
+ &BIG::new_ints(&rom::CURVE_PXAB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXBA),
+ &BIG::new_ints(&rom::CURVE_PXBB),
+ ),
+ ),
+ &FP4::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYAA),
+ &BIG::new_ints(&rom::CURVE_PYAB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYBA),
+ &BIG::new_ints(&rom::CURVE_PYBB),
+ ),
+ ),
+ );
+ }
+
+ #[allow(non_snake_case)]
+ pub fn mapit(h: &[u8]) -> ECP4 {
+ let mut q = BIG::new_ints(&rom::MODULUS);
+ let mut x = BIG::frombytes(h);
+ x.rmod(&mut q);
+ let mut Q: ECP4;
+ let one = BIG::new_int(1);
+
+ loop {
+ let X = FP4::new_fp2(&FP2::new_bigs(&one, &x));
+ Q = ECP4::new_fp4(&X);
+ if !Q.is_infinity() {
+ break;
+ }
+ x.inc(1);
+ x.norm();
+ }
+
+ let f = ECP4::frob_constants();
+ x = BIG::new_ints(&rom::CURVE_BNX);
+
+ let mut xQ = Q.mul(&mut x);
+ let mut x2Q = xQ.mul(&mut x);
+ let mut x3Q = x2Q.mul(&mut x);
+ let mut x4Q = x3Q.mul(&mut x);
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ xQ.neg();
+ x3Q.neg();
+ }
+
+ x4Q.sub(&x3Q);
+ x4Q.sub(&Q);
+
+ x3Q.sub(&x2Q);
+ x3Q.frob(&f, 1);
+
+ x2Q.sub(&xQ);
+ x2Q.frob(&f, 2);
+
+ xQ.sub(&Q);
+ xQ.frob(&f, 3);
+
+ Q.dbl();
+ Q.frob(&f, 4);
+
+ Q.add(&x4Q);
+ Q.add(&x3Q);
+ Q.add(&x2Q);
+ Q.add(&xQ);
+
+ Q.affine();
+ return Q;
+ }
+}
diff --git a/src/ecp8.rs b/src/ecp8.rs
new file mode 100644
index 0000000..a6d32a4
--- /dev/null
+++ b/src/ecp8.rs
@@ -0,0 +1,1155 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::rom;
+use super::big;
+use super::ecp;
+use super::fp2::FP2;
+use super::fp4::FP4;
+use super::fp8::FP8;
+use super::big::BIG;
+use types::{SexticTwist, SignOfX};
+
+pub struct ECP8 {
+ x: FP8,
+ y: FP8,
+ z: FP8,
+}
+
+#[allow(non_snake_case)]
+impl ECP8 {
+ pub fn new() -> ECP8 {
+ ECP8 {
+ x: FP8::new(),
+ y: FP8::new_int(1),
+ z: FP8::new(),
+ }
+ }
+ #[allow(non_snake_case)]
+ /* construct this from (x,y) - but set to O if not on curve */
+ pub fn new_fp8s(ix: &FP8, iy: &FP8) -> ECP8 {
+ let mut E = ECP8::new();
+ E.x.copy(&ix);
+ E.y.copy(&iy);
+ E.z.one();
+ E.x.norm();
+
+ let mut rhs = ECP8::rhs(&E.x);
+ let mut y2 = FP8::new_copy(&E.y);
+ y2.sqr();
+ if !y2.equals(&mut rhs) {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* construct this from x - but set to O if not on curve */
+ pub fn new_fp8(ix: &FP8) -> ECP8 {
+ let mut E = ECP8::new();
+ E.x.copy(&ix);
+ E.y.one();
+ E.z.one();
+ E.x.norm();
+
+ let mut rhs = ECP8::rhs(&E.x);
+ if rhs.sqrt() {
+ E.y.copy(&rhs);
+ } else {
+ E.inf();
+ }
+ return E;
+ }
+
+ /* Test this=O? */
+ pub fn is_infinity(&self) -> bool {
+ let xx = FP8::new_copy(&self.x);
+ let zz = FP8::new_copy(&self.z);
+ return xx.iszilch() && zz.iszilch();
+ }
+
+ /* copy self=P */
+ pub fn copy(&mut self, P: &ECP8) {
+ self.x.copy(&P.x);
+ self.y.copy(&P.y);
+ self.z.copy(&P.z);
+ }
+
+ /* set self=O */
+ pub fn inf(&mut self) {
+ self.x.zero();
+ self.y.one();
+ self.z.zero();
+ }
+
+ /* set self=-self */
+ pub fn neg(&mut self) {
+ self.y.norm();
+ self.y.neg();
+ self.y.norm();
+ }
+
+ /* Conditional move of Q to self dependant on d */
+ pub fn cmove(&mut self, Q: &ECP8, d: isize) {
+ self.x.cmove(&Q.x, d);
+ self.y.cmove(&Q.y, d);
+ self.z.cmove(&Q.z, d);
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* Constant time select from pre-computed table */
+ pub fn selector(&mut self, W: &[ECP8], b: i32) {
+ let mut MP = ECP8::new();
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&W[0], ECP8::teq(babs, 0)); // conditional move
+ self.cmove(&W[1], ECP8::teq(babs, 1));
+ self.cmove(&W[2], ECP8::teq(babs, 2));
+ self.cmove(&W[3], ECP8::teq(babs, 3));
+ self.cmove(&W[4], ECP8::teq(babs, 4));
+ self.cmove(&W[5], ECP8::teq(babs, 5));
+ self.cmove(&W[6], ECP8::teq(babs, 6));
+ self.cmove(&W[7], ECP8::teq(babs, 7));
+
+ MP.copy(self);
+ MP.neg();
+ self.cmove(&MP, (m & 1) as isize);
+ }
+
+ /* Test if P == Q */
+ pub fn equals(&mut self, Q: &mut ECP8) -> bool {
+ let mut a = FP8::new_copy(&self.x);
+ let mut b = FP8::new_copy(&Q.x);
+
+ a.mul(&Q.z);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+ a.copy(&self.y);
+ a.mul(&Q.z);
+ b.copy(&Q.y);
+ b.mul(&self.z);
+ if !a.equals(&mut b) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /* set to Affine - (x,y,z) to (x,y) */
+ pub fn affine(&mut self) {
+ if self.is_infinity() {
+ return;
+ }
+ let mut one = FP8::new_int(1);
+ if self.z.equals(&mut one) {
+ return;
+ }
+ self.z.inverse();
+
+ self.x.mul(&self.z);
+ self.x.reduce();
+ self.y.mul(&self.z);
+ self.y.reduce();
+ self.z.copy(&one);
+ }
+
+ /* extract affine x as FP8 */
+ pub fn getx(&self) -> FP8 {
+ let mut W = ECP8::new();
+ W.copy(self);
+ W.affine();
+ return FP8::new_copy(&W.x);
+ }
+
+ /* extract affine y as FP8 */
+ pub fn gety(&self) -> FP8 {
+ let mut W = ECP8::new();
+ W.copy(self);
+ W.affine();
+ return FP8::new_copy(&W.y);
+ }
+
+ /* extract projective x */
+ pub fn getpx(&self) -> FP8 {
+ return FP8::new_copy(&self.x);
+ }
+ /* extract projective y */
+ pub fn getpy(&self) -> FP8 {
+ return FP8::new_copy(&self.y);
+ }
+ /* extract projective z */
+ pub fn getpz(&self) -> FP8 {
+ return FP8::new_copy(&self.z);
+ }
+
+ /* convert to byte array */
+ pub fn tobytes(&self, b: &mut [u8]) {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+ let mut W = ECP8::new();
+ W.copy(self);
+
+ W.affine();
+
+ W.x.geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i] = t[i]
+ }
+ W.x.geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + mb] = t[i]
+ }
+
+ W.x.geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 2 * mb] = t[i]
+ }
+ W.x.geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 3 * mb] = t[i]
+ }
+
+ W.x.getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 4 * mb] = t[i]
+ }
+ W.x.getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 5 * mb] = t[i]
+ }
+
+ W.x.getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 6 * mb] = t[i]
+ }
+ W.x.getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 7 * mb] = t[i]
+ }
+
+ W.y.geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 8 * mb] = t[i]
+ }
+ W.y.geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 9 * mb] = t[i]
+ }
+
+ W.y.geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 10 * mb] = t[i]
+ }
+ W.y.geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 11 * mb] = t[i]
+ }
+
+ W.y.getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 12 * mb] = t[i]
+ }
+ W.y.getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 13 * mb] = t[i]
+ }
+
+ W.y.getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 14 * mb] = t[i]
+ }
+ W.y.getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ b[i + 15 * mb] = t[i]
+ }
+ }
+
+ /* convert from byte array to point */
+ pub fn frombytes(b: &[u8]) -> ECP8 {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ for i in 0..mb {
+ t[i] = b[i]
+ }
+ let mut ra = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = b[i + mb]
+ }
+ let mut rb = BIG::frombytes(&t);
+
+ let mut ra4 = FP2::new_bigs(&ra, &rb);
+
+ for i in 0..mb {
+ t[i] = b[i + 2 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 3 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ let mut rb4 = FP2::new_bigs(&ra, &rb);
+
+ let mut ra8 = FP4::new_fp2s(&ra4, &rb4);
+
+ for i in 0..mb {
+ t[i] = b[i + 4 * mb]
+ }
+ let mut ra = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = b[i + 5 * mb]
+ }
+ let mut rb = BIG::frombytes(&t);
+
+ ra4.copy(&FP2::new_bigs(&ra, &rb));
+
+ for i in 0..mb {
+ t[i] = b[i + 6 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 7 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ rb4.copy(&FP2::new_bigs(&ra, &rb));
+
+ let mut rb8 = FP4::new_fp2s(&ra4, &rb4);
+
+ let rx = FP8::new_fp4s(&ra8, &rb8);
+
+ for i in 0..mb {
+ t[i] = b[i + 8 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 9 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ ra4.copy(&FP2::new_bigs(&ra, &rb));
+
+ for i in 0..mb {
+ t[i] = b[i + 10 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 11 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ rb4.copy(&FP2::new_bigs(&ra, &rb));
+
+ ra8.copy(&FP4::new_fp2s(&ra4, &rb4));
+
+ for i in 0..mb {
+ t[i] = b[i + 12 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 13 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ ra4.copy(&FP2::new_bigs(&ra, &rb));
+
+ for i in 0..mb {
+ t[i] = b[i + 14 * mb]
+ }
+ ra.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = b[i + 15 * mb]
+ }
+ rb.copy(&BIG::frombytes(&t));
+
+ rb4.copy(&FP2::new_bigs(&ra, &rb));
+
+ rb8.copy(&FP4::new_fp2s(&ra4, &rb4));
+
+ let ry = FP8::new_fp4s(&ra8, &rb8);
+
+ return ECP8::new_fp8s(&rx, &ry);
+ }
+
+ /* convert this to hex string */
+ pub fn tostring(&self) -> String {
+ let mut W = ECP8::new();
+ W.copy(self);
+ W.affine();
+ if W.is_infinity() {
+ return String::from("infinity");
+ }
+ return format!("({},{})", W.x.tostring(), W.y.tostring());
+ }
+
+ /* Calculate RHS of twisted curve equation x^3+B/i */
+ pub fn rhs(x: &FP8) -> FP8 {
+ let mut r = FP8::new_copy(x);
+ r.sqr();
+ let mut b = FP8::new_fp4(&FP4::new_fp2(&FP2::new_big(&BIG::new_ints(&rom::CURVE_B))));
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.div_i();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ b.times_i();
+ }
+
+ r.mul(x);
+ r.add(&b);
+
+ r.reduce();
+ return r;
+ }
+
+ /* self+=self */
+ pub fn dbl(&mut self) -> isize {
+ let mut iy = FP8::new_copy(&self.y);
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ iy.times_i(); //iy.norm();
+ }
+
+ let mut t0 = FP8::new_copy(&self.y);
+ t0.sqr();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t0.times_i();
+ }
+ let mut t1 = FP8::new_copy(&iy);
+ t1.mul(&self.z);
+ let mut t2 = FP8::new_copy(&self.z);
+ t2.sqr();
+
+ self.z.copy(&t0);
+ self.z.add(&t0);
+ self.z.norm();
+ self.z.dbl();
+ self.z.dbl();
+ self.z.norm();
+
+ t2.imul(3 * rom::CURVE_B_I);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ t2.times_i();
+ }
+ let mut x3 = FP8::new_copy(&t2);
+ x3.mul(&self.z);
+
+ let mut y3 = FP8::new_copy(&t0);
+
+ y3.add(&t2);
+ y3.norm();
+ self.z.mul(&t1);
+ t1.copy(&t2);
+ t1.add(&t2);
+ t2.add(&t1);
+ t2.norm();
+ t0.sub(&t2);
+ t0.norm(); //y^2-9bz^2
+ y3.mul(&t0);
+ y3.add(&x3); //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2
+ t1.copy(&self.x);
+ t1.mul(&iy); //
+ self.x.copy(&t0);
+ self.x.norm();
+ self.x.mul(&t1);
+ self.x.dbl(); //(y^2-9bz^2)xy2
+
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+
+ return 1;
+ }
+
+ /* self+=Q - return 0 for add, 1 for double, -1 for O */
+ pub fn add(&mut self, Q: &ECP8) -> isize {
+ let b = 3 * rom::CURVE_B_I;
+ let mut t0 = FP8::new_copy(&self.x);
+ t0.mul(&Q.x); // x.Q.x
+ let mut t1 = FP8::new_copy(&self.y);
+ t1.mul(&Q.y); // y.Q.y
+
+ let mut t2 = FP8::new_copy(&self.z);
+ t2.mul(&Q.z);
+ let mut t3 = FP8::new_copy(&self.x);
+ t3.add(&self.y);
+ t3.norm(); //t3=X1+Y1
+ let mut t4 = FP8::new_copy(&Q.x);
+ t4.add(&Q.y);
+ t4.norm(); //t4=X2+Y2
+ t3.mul(&t4); //t3=(X1+Y1)(X2+Y2)
+ t4.copy(&t0);
+ t4.add(&t1); //t4=X1.X2+Y1.Y2
+
+ t3.sub(&t4);
+ t3.norm();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t3.times_i(); //t3=(X1+Y1)(X2+Y2)-(X1.X2+Y1.Y2) = X1.Y2+X2.Y1
+ }
+ t4.copy(&self.y);
+ t4.add(&self.z);
+ t4.norm(); //t4=Y1+Z1
+ let mut x3 = FP8::new_copy(&Q.y);
+ x3.add(&Q.z);
+ x3.norm(); //x3=Y2+Z2
+
+ t4.mul(&x3); //t4=(Y1+Z1)(Y2+Z2)
+ x3.copy(&t1); //
+ x3.add(&t2); //X3=Y1.Y2+Z1.Z2
+
+ t4.sub(&x3);
+ t4.norm();
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t4.times_i(); //t4=(Y1+Z1)(Y2+Z2) - (Y1.Y2+Z1.Z2) = Y1.Z2+Y2.Z1
+ }
+ x3.copy(&self.x);
+ x3.add(&self.z);
+ x3.norm(); // x3=X1+Z1
+ let mut y3 = FP8::new_copy(&Q.x);
+ y3.add(&Q.z);
+ y3.norm(); // y3=X2+Z2
+ x3.mul(&y3); // x3=(X1+Z1)(X2+Z2)
+ y3.copy(&t0);
+ y3.add(&t2); // y3=X1.X2+Z1+Z2
+ y3.rsub(&x3);
+ y3.norm(); // y3=(X1+Z1)(X2+Z2) - (X1.X2+Z1.Z2) = X1.Z2+X2.Z1
+
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ t0.times_i(); // x.Q.x
+ t1.times_i(); // y.Q.y
+ }
+ x3.copy(&t0);
+ x3.add(&t0);
+ t0.add(&x3);
+ t0.norm();
+ t2.imul(b);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ t2.times_i();
+ }
+ let mut z3 = FP8::new_copy(&t1);
+ z3.add(&t2);
+ z3.norm();
+ t1.sub(&t2);
+ t1.norm();
+ y3.imul(b);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ y3.times_i();
+ }
+ x3.copy(&y3);
+ x3.mul(&t4);
+ t2.copy(&t3);
+ t2.mul(&t1);
+ x3.rsub(&t2);
+ y3.mul(&t0);
+ t1.mul(&z3);
+ y3.add(&t1);
+ t0.mul(&t3);
+ z3.mul(&t4);
+ z3.add(&t0);
+
+ self.x.copy(&x3);
+ self.x.norm();
+ self.y.copy(&y3);
+ self.y.norm();
+ self.z.copy(&z3);
+ self.z.norm();
+
+ return 0;
+ }
+
+ /* set this-=Q */
+ pub fn sub(&mut self, Q: &ECP8) -> isize {
+ let mut NQ = ECP8::new();
+ NQ.copy(Q);
+ NQ.neg();
+ let d = self.add(&NQ);
+ return d;
+ }
+
+ pub fn frob_constants() -> [FP2; 3] {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+
+ let mut f0 = FP2::new_copy(&f);
+ f0.sqr();
+ let mut f2 = FP2::new_copy(&f0);
+ f2.mul_ip();
+ f2.norm();
+ let mut f1 = FP2::new_copy(&f2);
+ f1.sqr();
+ f2.mul(&f1);
+
+ f2.mul_ip();
+ f2.norm();
+
+ f1.copy(&f);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ f1.mul_ip();
+ f1.inverse();
+ f0.copy(&f1);
+ f0.sqr();
+ }
+ f0.mul_ip();
+ f0.norm();
+ f1.mul(&f0);
+
+ let F: [FP2; 3] = [f0, f1, f2];
+ return F;
+ }
+
+ /* set this*=q, where q is Modulus, using Frobenius */
+ pub fn frob(&mut self, f: &[FP2; 3], n: isize) {
+ for _i in 0..n {
+ self.x.frob(&f[2]);
+ self.x.qmul(&f[0]);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ self.x.div_i2();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ self.x.times_i2();
+ }
+ self.y.frob(&f[2]);
+ self.y.qmul(&f[1]);
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ self.y.div_i();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ self.y.times_i2();
+ self.y.times_i2();
+ self.y.times_i();
+ }
+
+ self.z.frob(&f[2]);
+ }
+ }
+
+ /* self*=e */
+ pub fn mul(&self, e: &BIG) -> ECP8 {
+ /* fixed size windows */
+ let mut mt = BIG::new();
+ let mut t = BIG::new();
+ let mut P = ECP8::new();
+ let mut Q = ECP8::new();
+ let mut C = ECP8::new();
+
+ if self.is_infinity() {
+ return P;
+ }
+
+ let mut W: [ECP8; 8] = [
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ];
+
+ const CT: usize = 1 + (big::NLEN * (big::BASEBITS as usize) + 3) / 4;
+ let mut w: [i8; CT] = [0; CT];
+
+ /* precompute table */
+ Q.copy(&self);
+ Q.dbl();
+
+ W[0].copy(&self);
+
+ for i in 1..8 {
+ C.copy(&W[i - 1]);
+ W[i].copy(&C);
+ W[i].add(&mut Q);
+ }
+
+ /* make exponent odd - add 2P if even, P if odd */
+ t.copy(&e);
+ let s = t.parity();
+ t.inc(1);
+ t.norm();
+ let ns = t.parity();
+ mt.copy(&t);
+ mt.inc(1);
+ mt.norm();
+ t.cmove(&mt, s);
+ Q.cmove(&self, ns);
+ C.copy(&Q);
+
+ let nb = 1 + (t.nbits() + 3) / 4;
+
+ /* convert exponent to signed 4-bit window */
+ for i in 0..nb {
+ w[i] = (t.lastbits(5) - 16) as i8;
+ t.dec(w[i] as isize);
+ t.norm();
+ t.fshr(4);
+ }
+ w[nb] = (t.lastbits(5)) as i8;
+
+ P.copy(&W[((w[nb] as usize) - 1) / 2]);
+ for i in (0..nb).rev() {
+ Q.selector(&W, w[i] as i32);
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.dbl();
+ P.add(&mut Q);
+ }
+ P.sub(&mut C);
+ P.affine();
+ return P;
+ }
+
+ /* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3.. */
+ // Bos & Costello https://eprint.iacr.org/2013/458.pdf
+ // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
+ // Side channel attack secure
+
+ pub fn mul16(Q: &mut [ECP8], u: &[BIG]) -> ECP8 {
+ let mut W = ECP8::new();
+ let mut P = ECP8::new();
+
+ let mut T1: [ECP8; 8] = [
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ];
+ let mut T2: [ECP8; 8] = [
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ];
+ let mut T3: [ECP8; 8] = [
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ];
+ let mut T4: [ECP8; 8] = [
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ];
+
+ let mut mt = BIG::new();
+
+ let mut t: [BIG; 16] = [
+ BIG::new_copy(&u[0]),
+ BIG::new_copy(&u[1]),
+ BIG::new_copy(&u[2]),
+ BIG::new_copy(&u[3]),
+ BIG::new_copy(&u[4]),
+ BIG::new_copy(&u[5]),
+ BIG::new_copy(&u[6]),
+ BIG::new_copy(&u[7]),
+ BIG::new_copy(&u[8]),
+ BIG::new_copy(&u[9]),
+ BIG::new_copy(&u[10]),
+ BIG::new_copy(&u[11]),
+ BIG::new_copy(&u[12]),
+ BIG::new_copy(&u[13]),
+ BIG::new_copy(&u[14]),
+ BIG::new_copy(&u[15]),
+ ];
+
+ const CT: usize = 1 + big::NLEN * (big::BASEBITS as usize);
+ let mut w1: [i8; CT] = [0; CT];
+ let mut s1: [i8; CT] = [0; CT];
+ let mut w2: [i8; CT] = [0; CT];
+ let mut s2: [i8; CT] = [0; CT];
+ let mut w3: [i8; CT] = [0; CT];
+ let mut s3: [i8; CT] = [0; CT];
+ let mut w4: [i8; CT] = [0; CT];
+ let mut s4: [i8; CT] = [0; CT];
+
+ for i in 0..16 {
+ //Q[i].affine();
+ t[i].norm();
+ }
+
+ T1[0].copy(&Q[0]);
+ W.copy(&T1[0]);
+ T1[1].copy(&W);
+ T1[1].add(&mut Q[1]); // Q[0]+Q[1]
+ T1[2].copy(&W);
+ T1[2].add(&mut Q[2]);
+ W.copy(&T1[1]); // Q[0]+Q[2]
+ T1[3].copy(&W);
+ T1[3].add(&mut Q[2]);
+ W.copy(&T1[0]); // Q[0]+Q[1]+Q[2]
+ T1[4].copy(&W);
+ T1[4].add(&mut Q[3]);
+ W.copy(&T1[1]); // Q[0]+Q[3]
+ T1[5].copy(&W);
+ T1[5].add(&mut Q[3]);
+ W.copy(&T1[2]); // Q[0]+Q[1]+Q[3]
+ T1[6].copy(&W);
+ T1[6].add(&mut Q[3]);
+ W.copy(&T1[3]); // Q[0]+Q[2]+Q[3]
+ T1[7].copy(&W);
+ T1[7].add(&mut Q[3]); // Q[0]+Q[1]+Q[2]+Q[3]
+
+ T2[0].copy(&Q[4]);
+ W.copy(&T2[0]);
+ T2[1].copy(&W);
+ T2[1].add(&mut Q[5]); // Q[0]+Q[1]
+ T2[2].copy(&W);
+ T2[2].add(&mut Q[6]);
+ W.copy(&T2[1]); // Q[0]+Q[2]
+ T2[3].copy(&W);
+ T2[3].add(&mut Q[6]);
+ W.copy(&T2[0]); // Q[0]+Q[1]+Q[2]
+ T2[4].copy(&W);
+ T2[4].add(&mut Q[7]);
+ W.copy(&T2[1]); // Q[0]+Q[3]
+ T2[5].copy(&W);
+ T2[5].add(&mut Q[7]);
+ W.copy(&T2[2]); // Q[0]+Q[1]+Q[3]
+ T2[6].copy(&W);
+ T2[6].add(&mut Q[7]);
+ W.copy(&T2[3]); // Q[0]+Q[2]+Q[3]
+ T2[7].copy(&W);
+ T2[7].add(&mut Q[7]); // Q[0]+Q[1]+Q[2]+Q[3]
+
+ T3[0].copy(&Q[8]);
+ W.copy(&T3[0]);
+ T3[1].copy(&W);
+ T3[1].add(&mut Q[9]); // Q[0]+Q[1]
+ T3[2].copy(&W);
+ T3[2].add(&mut Q[10]);
+ W.copy(&T3[1]); // Q[0]+Q[2]
+ T3[3].copy(&W);
+ T3[3].add(&mut Q[10]);
+ W.copy(&T3[0]); // Q[0]+Q[1]+Q[2]
+ T3[4].copy(&W);
+ T3[4].add(&mut Q[11]);
+ W.copy(&T3[1]); // Q[0]+Q[3]
+ T3[5].copy(&W);
+ T3[5].add(&mut Q[11]);
+ W.copy(&T3[2]); // Q[0]+Q[1]+Q[3]
+ T3[6].copy(&W);
+ T3[6].add(&mut Q[11]);
+ W.copy(&T3[3]); // Q[0]+Q[2]+Q[3]
+ T3[7].copy(&W);
+ T3[7].add(&mut Q[11]); // Q[0]+Q[1]+Q[2]+Q[3]
+
+ T4[0].copy(&Q[12]);
+ W.copy(&T4[0]);
+ T4[1].copy(&W);
+ T4[1].add(&mut Q[13]); // Q[0]+Q[1]
+ T4[2].copy(&W);
+ T4[2].add(&mut Q[14]);
+ W.copy(&T4[1]); // Q[0]+Q[2]
+ T4[3].copy(&W);
+ T4[3].add(&mut Q[14]);
+ W.copy(&T4[0]); // Q[0]+Q[1]+Q[2]
+ T4[4].copy(&W);
+ T4[4].add(&mut Q[15]);
+ W.copy(&T4[1]); // Q[0]+Q[3]
+ T4[5].copy(&W);
+ T4[5].add(&mut Q[15]);
+ W.copy(&T4[2]); // Q[0]+Q[1]+Q[3]
+ T4[6].copy(&W);
+ T4[6].add(&mut Q[15]);
+ W.copy(&T4[3]); // Q[0]+Q[2]+Q[3]
+ T4[7].copy(&W);
+ T4[7].add(&mut Q[15]); // Q[0]+Q[1]+Q[2]+Q[3]
+
+ // Make it odd
+ let pb1 = 1 - t[0].parity();
+ t[0].inc(pb1);
+
+ let pb2 = 1 - t[4].parity();
+ t[4].inc(pb2);
+
+ let pb3 = 1 - t[8].parity();
+ t[8].inc(pb3);
+
+ let pb4 = 1 - t[12].parity();
+ t[12].inc(pb4);
+
+ // Number of bits
+ mt.zero();
+ for i in 0..16 {
+ t[i].norm();
+ mt.or(&t[i]);
+ }
+
+ let nb = 1 + mt.nbits();
+
+ // Sign pivot
+
+ s1[nb - 1] = 1;
+ s2[nb - 1] = 1;
+ s3[nb - 1] = 1;
+ s4[nb - 1] = 1;
+ for i in 0..nb - 1 {
+ t[0].fshr(1);
+ s1[i] = (2 * t[0].parity() - 1) as i8;
+ t[4].fshr(1);
+ s2[i] = (2 * t[4].parity() - 1) as i8;
+ t[8].fshr(1);
+ s3[i] = (2 * t[8].parity() - 1) as i8;
+ t[12].fshr(1);
+ s4[i] = (2 * t[12].parity() - 1) as i8;
+ }
+
+ // Recoded exponent
+ for i in 0..nb {
+ w1[i] = 0;
+ let mut k = 1;
+ for j in 1..4 {
+ let bt = s1[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w1[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w2[i] = 0;
+ k = 1;
+ for j in 5..8 {
+ let bt = s2[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w2[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w3[i] = 0;
+ k = 1;
+ for j in 9..12 {
+ let bt = s3[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w3[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w4[i] = 0;
+ k = 1;
+ for j in 13..16 {
+ let bt = s4[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w4[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+ }
+
+ // Main loop
+ P.selector(&T1, (2 * w1[nb - 1] + 1) as i32);
+ W.selector(&T2, (2 * w2[nb - 1] + 1) as i32);
+ P.add(&mut W);
+ W.selector(&T3, (2 * w3[nb - 1] + 1) as i32);
+ P.add(&mut W);
+ W.selector(&T4, (2 * w4[nb - 1] + 1) as i32);
+ P.add(&mut W);
+ for i in (0..nb - 1).rev() {
+ P.dbl();
+ W.selector(&T1, (2 * w1[i] + s1[i]) as i32);
+ P.add(&mut W);
+ W.selector(&T2, (2 * w2[i] + s2[i]) as i32);
+ P.add(&mut W);
+ W.selector(&T3, (2 * w3[i] + s3[i]) as i32);
+ P.add(&mut W);
+ W.selector(&T4, (2 * w4[i] + s4[i]) as i32);
+ P.add(&mut W);
+ }
+
+ // apply correction
+ W.copy(&P);
+ W.sub(&mut Q[0]);
+ P.cmove(&W, pb1);
+
+ W.copy(&P);
+ W.sub(&mut Q[4]);
+ P.cmove(&W, pb2);
+
+ W.copy(&P);
+ W.sub(&mut Q[8]);
+ P.cmove(&W, pb3);
+
+ W.copy(&P);
+ W.sub(&mut Q[12]);
+ P.cmove(&W, pb4);
+
+ P.affine();
+
+ return P;
+ }
+
+ pub fn generator() -> ECP8 {
+ return ECP8::new_fp8s(
+ &FP8::new_fp4s(
+ &FP4::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXAAA),
+ &BIG::new_ints(&rom::CURVE_PXAAB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXABA),
+ &BIG::new_ints(&rom::CURVE_PXABB),
+ ),
+ ),
+ &FP4::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXBAA),
+ &BIG::new_ints(&rom::CURVE_PXBAB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PXBBA),
+ &BIG::new_ints(&rom::CURVE_PXBBB),
+ ),
+ ),
+ ),
+ &FP8::new_fp4s(
+ &FP4::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYAAA),
+ &BIG::new_ints(&rom::CURVE_PYAAB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYABA),
+ &BIG::new_ints(&rom::CURVE_PYABB),
+ ),
+ ),
+ &FP4::new_fp2s(
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYBAA),
+ &BIG::new_ints(&rom::CURVE_PYBAB),
+ ),
+ &FP2::new_bigs(
+ &BIG::new_ints(&rom::CURVE_PYBBA),
+ &BIG::new_ints(&rom::CURVE_PYBBB),
+ ),
+ ),
+ ),
+ );
+ }
+
+ #[allow(non_snake_case)]
+ pub fn mapit(h: &[u8]) -> ECP8 {
+ let mut q = BIG::new_ints(&rom::MODULUS);
+ let mut x = BIG::frombytes(h);
+ x.rmod(&mut q);
+ let mut Q: ECP8;
+ let one = BIG::new_int(1);
+
+ loop {
+ let X = FP8::new_fp4(&FP4::new_fp2(&FP2::new_bigs(&one, &x)));
+ Q = ECP8::new_fp8(&X);
+ if !Q.is_infinity() {
+ break;
+ }
+ x.inc(1);
+ x.norm();
+ }
+
+ let f = ECP8::frob_constants();
+ x = BIG::new_ints(&rom::CURVE_BNX);
+
+ let mut xQ = Q.mul(&mut x);
+ let mut x2Q = xQ.mul(&mut x);
+ let mut x3Q = x2Q.mul(&mut x);
+ let mut x4Q = x3Q.mul(&mut x);
+ let mut x5Q = x4Q.mul(&mut x);
+ let mut x6Q = x5Q.mul(&mut x);
+ let mut x7Q = x6Q.mul(&mut x);
+ let mut x8Q = x7Q.mul(&mut x);
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ xQ.neg();
+ x3Q.neg();
+ x5Q.neg();
+ x7Q.neg();
+ }
+
+ x8Q.sub(&x7Q);
+ x8Q.sub(&Q);
+
+ x7Q.sub(&x6Q);
+ x7Q.frob(&f, 1);
+
+ x6Q.sub(&x5Q);
+ x6Q.frob(&f, 2);
+
+ x5Q.sub(&x4Q);
+ x5Q.frob(&f, 3);
+
+ x4Q.sub(&x3Q);
+ x4Q.frob(&f, 4);
+
+ x3Q.sub(&x2Q);
+ x3Q.frob(&f, 5);
+
+ x2Q.sub(&xQ);
+ x2Q.frob(&f, 6);
+
+ xQ.sub(&Q);
+ xQ.frob(&f, 7);
+
+ Q.dbl();
+ Q.frob(&f, 8);
+
+ Q.add(&x8Q);
+ Q.add(&x7Q);
+ Q.add(&x6Q);
+ Q.add(&x5Q);
+
+ Q.add(&x4Q);
+ Q.add(&x3Q);
+ Q.add(&x2Q);
+ Q.add(&xQ);
+
+ Q.affine();
+ return Q;
+ }
+}
diff --git a/src/ff.rs b/src/ff.rs
new file mode 100644
index 0000000..4737ee8
--- /dev/null
+++ b/src/ff.rs
@@ -0,0 +1,1058 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+if debug {println!("sf2= {}",self.tostring())}
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::big;
+use super::dbig::DBIG;
+use super::big::BIG;
+use super::super::arch::Chunk;
+use rand::RAND;
+
+use super::super::arch::DChunk;
+
+/* Finite field support - for RSA, DH etc. */
+/* RSA/DH modulus length as multiple of BIGBITS */
+
+pub use super::rom::FFLEN;
+//use std::str::SplitWhitespace;
+
+pub const FF_BITS: usize = (big::BIGBITS * FFLEN); /* Finite Field Size in bits - must be 256.2^n */
+pub const HFLEN: usize = (FFLEN / 2); /* Useful for half-size RSA private key operations */
+
+pub const P_MBITS: usize = (big::MODBYTES as usize) * 8;
+pub const P_OMASK: Chunk = ((-1) << (P_MBITS % big::BASEBITS));
+pub const P_FEXCESS: Chunk = (1 << (big::BASEBITS * big::NLEN - P_MBITS - 1));
+pub const P_TBITS: usize = (P_MBITS % big::BASEBITS);
+
+pub struct FF {
+ v: Vec<BIG>,
+ length: usize,
+}
+
+impl FF {
+ pub fn excess(a: &BIG) -> Chunk {
+ return ((a.w[big::NLEN - 1] & P_OMASK) >> (P_TBITS)) + 1;
+ }
+
+ pub fn pexceed(a: &BIG, b: &BIG) -> bool {
+ let ea = FF::excess(a);
+ let eb = FF::excess(b);
+ if ((ea + 1) as DChunk) * ((eb + 1) as DChunk) > P_FEXCESS as DChunk {
+ return true;
+ }
+ return false;
+ }
+
+ pub fn sexceed(a: &BIG) -> bool {
+ let ea = FF::excess(a);
+ if ((ea + 1) as DChunk) * ((ea + 1) as DChunk) > P_FEXCESS as DChunk {
+ return true;
+ }
+ return false;
+ }
+
+ /* Constructors */
+ pub fn new_int(n: usize) -> FF {
+ let mut f = FF {
+ v: Vec::new(),
+ length: 0,
+ };
+ for _ in 0..n {
+ f.v.push(BIG::new());
+ }
+ f.length = n;
+ return f;
+ }
+
+ pub fn zero(&mut self) {
+ for i in 0..self.length {
+ self.v[i].zero();
+ }
+ }
+
+ pub fn getlen(&self) -> usize {
+ return self.length;
+ }
+
+ /* set to integer */
+ pub fn set(&mut self, m: isize) {
+ self.zero();
+ self.v[0].set(0, m as Chunk);
+ }
+
+ /* copy from FF b */
+ pub fn copy(&mut self, b: &FF) {
+ for i in 0..self.length {
+ self.v[i].copy(&b.v[i]);
+ }
+ }
+
+ /* x=y<<n */
+ pub fn dsucopy(&mut self, b: &FF) {
+ for i in 0..b.length {
+ self.v[b.length + i].copy(&b.v[i]);
+ self.v[i].zero();
+ }
+ }
+
+ /* x=y */
+ pub fn dscopy(&mut self, b: &FF) {
+ for i in 0..b.length {
+ self.v[i].copy(&b.v[i]);
+ self.v[b.length + i].zero();
+ }
+ }
+
+ /* x=y>>n */
+ pub fn sducopy(&mut self, b: &FF) {
+ for i in 0..self.length {
+ self.v[i].copy(&b.v[self.length + i]);
+ }
+ }
+
+ pub fn one(&mut self) {
+ self.v[0].one();
+ for i in 1..self.length {
+ self.v[i].zero();
+ }
+ }
+
+ /* test equals 0 */
+ pub fn iszilch(&mut self) -> bool {
+ for i in 0..self.length {
+ if !self.v[i].iszilch() {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* shift right by BIGBITS-bit words */
+ pub fn shrw(&mut self, n: usize) {
+ let mut t = BIG::new();
+ for i in 0..n {
+ t.copy(&self.v[i + n]);
+ self.v[i].copy(&t);
+ self.v[i + n].zero();
+ }
+ }
+
+ /* shift left by BIGBITS-bit words */
+ pub fn shlw(&mut self, n: usize) {
+ let mut t = BIG::new();
+ for i in 0..n {
+ t.copy(&self.v[i]);
+ self.v[n + i].copy(&t);
+ self.v[i].zero();
+ }
+ }
+
+ /* extract last bit */
+ pub fn parity(&self) -> isize {
+ return self.v[0].parity();
+ }
+
+ pub fn lastbits(&mut self, m: usize) -> isize {
+ return self.v[0].lastbits(m);
+ }
+
+ /* compare x and y - must be normalised, and of same length */
+ pub fn comp(a: &FF, b: &FF) -> isize {
+ let mut i = a.length - 1;
+
+ loop {
+ let j = BIG::comp(&a.v[i], &b.v[i]);
+ if j != 0 {
+ return j;
+ }
+ if i == 0 {
+ break;
+ }
+ i -= 1;
+ }
+ return 0;
+ }
+
+ /* recursive add */
+ pub fn radd(&mut self, vp: usize, x: &FF, xp: usize, y: &FF, yp: usize, n: usize) {
+ for i in 0..n {
+ self.v[vp + i].copy(&x.v[xp + i]);
+ self.v[vp + i].add(&y.v[yp + i]);
+ }
+ }
+
+ /* recursive inc */
+ pub fn rinc(&mut self, vp: usize, y: &FF, yp: usize, n: usize) {
+ for i in 0..n {
+ self.v[vp + i].add(&y.v[yp + i]);
+ }
+ }
+
+ pub fn rsinc(&mut self, n: usize) {
+ let mut t = BIG::new();
+ for i in 0..n {
+ t.copy(&self.v[i]);
+ self.v[n + i].add(&t);
+ }
+ }
+
+ /* recursive sub */
+ pub fn rsub(&mut self, vp: usize, x: &FF, xp: usize, y: &FF, yp: usize, n: usize) {
+ for i in 0..n {
+ self.v[vp + i].copy(&x.v[xp + i]);
+ self.v[vp + i].sub(&y.v[yp + i]);
+ }
+ }
+
+ /* recursive dec */
+ pub fn rdec(&mut self, vp: usize, y: &FF, yp: usize, n: usize) {
+ for i in 0..n {
+ self.v[vp + i].sub(&y.v[yp + i]);
+ }
+ }
+
+ /* simple add */
+ pub fn add(&mut self, b: &FF) {
+ for i in 0..self.length {
+ self.v[i].add(&b.v[i]);
+ }
+ }
+
+ /* simple sub */
+ pub fn sub(&mut self, b: &FF) {
+ for i in 0..self.length {
+ self.v[i].sub(&b.v[i]);
+ }
+ }
+
+ /* reverse sub */
+ pub fn revsub(&mut self, b: &FF) {
+ for i in 0..self.length {
+ self.v[i].rsub(&b.v[i]);
+ }
+ }
+
+ /* normalise - but hold any overflow in top part unless n<0 */
+ pub fn rnorm(&mut self, vp: usize, n: isize) {
+ let mut trunc = false;
+ let mut carry: Chunk;
+ let mut nn: usize = n as usize;
+ if n < 0 {
+ /* -v n signals to do truncation */
+ nn = (-n) as usize;
+ trunc = true;
+ }
+ for i in 0..nn - 1 {
+ carry = self.v[vp + i].norm();
+ self.v[vp + i].xortop(carry << P_TBITS);
+ self.v[vp + i + 1].w[0] += carry;
+ }
+ carry = self.v[vp + nn - 1].norm();
+ if trunc {
+ self.v[vp + nn - 1].xortop(carry << P_TBITS);
+ }
+ }
+
+ pub fn norm(&mut self) {
+ let n: isize = self.length as isize;
+ self.rnorm(0, n);
+ }
+
+ /* increment/decrement by a small integer */
+ pub fn inc(&mut self, m: isize) {
+ self.v[0].inc(m);
+ self.norm();
+ }
+
+ pub fn dec(&mut self, m: isize) {
+ self.v[0].dec(m);
+ self.norm();
+ }
+
+ /* shift left by one bit */
+ pub fn shl(&mut self) {
+ let mut delay_carry: isize = 0;
+ for i in 0..self.length - 1 {
+ let carry = self.v[i].fshl(1);
+ self.v[i].inc(delay_carry);
+ self.v[i].xortop((carry as Chunk) << P_TBITS);
+ delay_carry = carry;
+ }
+ self.v[self.length - 1].fshl(1);
+ self.v[self.length - 1].inc(delay_carry);
+ }
+
+ /* shift right by one bit */
+
+ pub fn shr(&mut self) {
+ let mut i = self.length - 1;
+ while i > 0 {
+ let carry = self.v[i].fshr(1);
+ self.v[i - 1].xortop((carry as Chunk) << P_TBITS);
+ i -= 1;
+ }
+ self.v[0].fshr(1);
+ }
+
+ /* Convert to Hex String */
+ pub fn tostring(&mut self) -> String {
+ self.norm();
+ let mut s = String::new();
+ let mut i: usize = self.length - 1;
+ loop {
+ s = s + self.v[i].tostring().as_ref();
+ if i == 0 {
+ break;
+ }
+ i -= 1;
+ }
+ return s;
+ }
+
+ /* Convert FFs to/from byte arrays */
+ pub fn tobytes(&mut self, b: &mut [u8]) {
+ for i in 0..self.length {
+ self.v[i].tobytearray(b, (self.length - i - 1) * (big::MODBYTES as usize))
+ }
+ }
+
+ pub fn frombytes(x: &mut FF, b: &[u8]) {
+ for i in 0..x.length {
+ x.v[i] = BIG::frombytearray(b, (x.length - i - 1) * (big::MODBYTES as usize))
+ }
+ }
+
+ /* in-place swapping using xor - side channel resistant - lengths must be the same */
+ pub fn cswap(a: &mut FF, b: &mut FF, d: isize) {
+ for i in 0..a.length {
+ a.v[i].cswap(&mut b.v[i], d);
+ }
+ }
+
+ /* z=x*y, t is workspace */
+ fn karmul(
+ &mut self,
+ vp: usize,
+ x: &FF,
+ xp: usize,
+ y: &FF,
+ yp: usize,
+ t: *mut FF,
+ tp: usize,
+ n: usize,
+ ) {
+ if n == 1 {
+ let xx = BIG::new_copy(&x.v[xp]);
+ let yy = BIG::new_copy(&y.v[yp]);
+ let mut d = BIG::mul(&xx, &yy);
+ self.v[vp + 1] = d.split(8 * big::MODBYTES);
+ self.v[vp].dcopy(&d);
+ return;
+ }
+ let nd2 = n / 2;
+ self.radd(vp, x, xp, x, xp + nd2, nd2);
+ self.rnorm(vp, nd2 as isize); /* Important - required for 32-bit build */
+ self.radd(vp + nd2, y, yp, y, yp + nd2, nd2);
+ self.rnorm(vp + nd2, nd2 as isize); /* Important - required for 32-bit build */
+ unsafe {
+ (*t).karmul(tp, self, vp, self, vp + nd2, t, tp + n, nd2);
+ }
+ self.karmul(vp, x, xp, y, yp, t, tp + n, nd2);
+ self.karmul(vp + n, x, xp + nd2, y, yp + nd2, t, tp + n, nd2);
+ unsafe {
+ (*t).rdec(tp, self, vp, n);
+ (*t).rdec(tp, self, vp + n, n);
+ self.rinc(vp + nd2, &(*t), tp, n);
+ }
+ self.rnorm(vp, (2 * n) as isize);
+ }
+
+ fn karsqr(&mut self, vp: usize, x: &FF, xp: usize, t: *mut FF, tp: usize, n: usize) {
+ if n == 1 {
+ let xx = BIG::new_copy(&x.v[xp]);
+ let mut d = BIG::sqr(&xx);
+ self.v[vp + 1].copy(&d.split(8 * big::MODBYTES));
+ self.v[vp].dcopy(&d);
+ return;
+ }
+
+ let nd2 = n / 2;
+ self.karsqr(vp, x, xp, t, tp + n, nd2);
+ self.karsqr(vp + n, x, xp + nd2, t, tp + n, nd2);
+ unsafe {
+ (*t).karmul(tp, x, xp, x, xp + nd2, t, tp + n, nd2);
+ self.rinc(vp + nd2, &(*t), tp, n);
+ self.rinc(vp + nd2, &(*t), tp, n);
+ }
+ self.rnorm(vp + nd2, n as isize);
+ }
+
+ /* Calculates Least Significant bottom half of x*y */
+ fn karmul_lower(
+ &mut self,
+ vp: usize,
+ x: &FF,
+ xp: usize,
+ y: &FF,
+ yp: usize,
+ t: *mut FF,
+ tp: usize,
+ n: usize,
+ ) {
+ if n == 1 {
+ /* only calculate bottom half of product */
+ self.v[vp].copy(&BIG::smul(&x.v[xp], &y.v[yp]));
+ return;
+ }
+ let nd2 = n / 2;
+
+ self.karmul(vp, x, xp, y, yp, t, tp + n, nd2);
+ unsafe {
+ (*t).karmul_lower(tp, x, xp + nd2, y, yp, t, tp + n, nd2);
+ self.rinc(vp + nd2, &(*t), tp, nd2);
+ (*t).karmul_lower(tp, x, xp, y, yp + nd2, t, tp + n, nd2);
+ self.rinc(vp + nd2, &(*t), tp, nd2);
+ }
+ let sn: isize = nd2 as isize;
+ self.rnorm(vp + nd2, -sn); /* truncate it */
+ }
+
+ /* Calculates Most Significant upper half of x*y, given lower part */
+ fn karmul_upper(&mut self, x: &FF, y: &FF, t: *mut FF, n: usize) {
+ let nd2 = n / 2;
+ self.radd(n, x, 0, x, nd2, nd2);
+ self.radd(n + nd2, y, 0, y, nd2, nd2);
+ self.rnorm(n, nd2 as isize);
+ self.rnorm(n + nd2, nd2 as isize);
+
+ unsafe {
+ (*t).karmul(0, self, n + nd2, self, n, t, n, nd2); /* t = (a0+a1)(b0+b1) */
+ }
+ self.karmul(n, x, nd2, y, nd2, t, n, nd2); /* z[n]= a1*b1 */
+ /* z[0-nd2]=l(a0b0) z[nd2-n]= h(a0b0)+l(t)-l(a0b0)-l(a1b1) */
+ unsafe {
+ (*t).rdec(0, self, n, n); /* t=t-a1b1 */
+
+ self.rsinc(nd2); /* z[nd2-n]+=l(a0b0) = h(a0b0)+l(t)-l(a1b1) */
+ self.rdec(nd2, &(*t), 0, nd2); /* z[nd2-n]=h(a0b0)+l(t)-l(a1b1)-l(t-a1b1)=h(a0b0) */
+ }
+
+ let sn: isize = n as isize;
+ self.rnorm(0, -sn); /* a0b0 now in z - truncate it */
+ unsafe {
+ (*t).rdec(0, self, 0, n); /* (a0+a1)(b0+b1) - a0b0 */
+ self.rinc(nd2, &(*t), 0, n);
+ }
+ self.rnorm(nd2, sn);
+ }
+
+ /* z=x*y. Assumes x and y are of same length. */
+ pub fn mul(x: &FF, y: &FF) -> FF {
+ let n = x.length;
+ let mut z = FF::new_int(2 * n);
+ let mut t = FF::new_int(2 * n);
+ z.karmul(0, &x, 0, &y, 0, &mut t, 0, n);
+ return z;
+ }
+
+ /* return low part of product this*y */
+ pub fn lmul(&mut self, y: &FF) {
+ let n = self.length;
+ let mut t = FF::new_int(2 * n);
+ let mut x = FF::new_int(n);
+ x.copy(&self);
+ self.karmul_lower(0, &x, 0, &y, 0, &mut t, 0, n);
+ }
+
+ /* Set b=b mod c */
+ pub fn rmod(&mut self, m: &FF) {
+ let mut k = 1;
+ let n = m.length;
+ let mut c = FF::new_int(n);
+ c.copy(m);
+
+ self.norm();
+ if FF::comp(&self, &c) < 0 {
+ return;
+ }
+
+ c.shl();
+ while FF::comp(&self, &c) >= 0 {
+ c.shl();
+ k += 1;
+ }
+
+ while k > 0 {
+ c.shr();
+ if FF::comp(&self, &c) >= 0 {
+ self.sub(&c);
+ self.norm();
+ }
+ k -= 1;
+ }
+ }
+
+ /* z=x^2 */
+ pub fn sqr(x: &FF) -> FF {
+ let n = x.length;
+ let mut z = FF::new_int(2 * n);
+ let mut t = FF::new_int(2 * n);
+ z.karsqr(0, &x, 0, &mut t, 0, n);
+ return z;
+ }
+
+ /* return This mod modulus, ms is modulus, md is Montgomery Constant */
+ pub fn reduce(&mut self, ms: &FF, md: &FF) -> FF {
+ /* fast karatsuba Montgomery reduction */
+ let n = ms.length;
+ let mut t = FF::new_int(2 * n);
+ let mut r = FF::new_int(n);
+ let mut m = FF::new_int(n);
+
+ r.sducopy(&self);
+ m.karmul_lower(0, &self, 0, &md, 0, &mut t, 0, n);
+ self.karmul_upper(&ms, &m, &mut t, n);
+
+ m.sducopy(self);
+ r.add(&ms);
+ r.sub(&m);
+ r.norm();
+
+ return r;
+ }
+
+ /* Set r=this mod b */
+ /* this is of length - 2*n */
+ /* r,b is of length - n */
+ pub fn dmod(&mut self, b: &FF) -> FF {
+ let n = b.length;
+ let mut m = FF::new_int(2 * n);
+ let mut x = FF::new_int(2 * n);
+ let mut r = FF::new_int(n);
+
+ x.copy(&self);
+ x.norm();
+ m.dsucopy(&b);
+ let mut k = big::BIGBITS * n;
+
+ while FF::comp(&x, &m) >= 0 {
+ x.sub(&m);
+ x.norm();
+ }
+
+ while k > 0 {
+ m.shr();
+
+ if FF::comp(&x, &m) >= 0 {
+ x.sub(&m);
+ x.norm();
+ }
+ k -= 1;
+ }
+
+ r.copy(&x);
+ r.rmod(b);
+ return r;
+ }
+
+ /* Set return=1/this mod p. Binary method - a<p on entry */
+
+ pub fn invmodp(&mut self, p: &FF) {
+ let n = p.length;
+
+ let mut u = FF::new_int(n);
+ let mut v = FF::new_int(n);
+ let mut x1 = FF::new_int(n);
+ let mut x2 = FF::new_int(n);
+ let mut t = FF::new_int(n);
+ let mut one = FF::new_int(n);
+
+ one.one();
+ u.copy(&self);
+ v.copy(&p);
+ x1.copy(&one);
+ x2.zero();
+
+ // reduce n in here as well!
+ while FF::comp(&u, &one) != 0 && FF::comp(&v, &one) != 0 {
+ while u.parity() == 0 {
+ u.shr();
+ if x1.parity() != 0 {
+ x1.add(&p);
+ x1.norm();
+ }
+ x1.shr();
+ }
+ while v.parity() == 0 {
+ v.shr();
+ if x2.parity() != 0 {
+ x2.add(&p);
+ x2.norm();
+ }
+ x2.shr();
+ }
+ if FF::comp(&u, &v) >= 0 {
+ u.sub(&v);
+ u.norm();
+ if FF::comp(&x1, &x2) >= 0 {
+ x1.sub(&x2);
+ } else {
+ t.copy(&p);
+ t.sub(&x2);
+ x1.add(&t);
+ }
+ x1.norm();
+ } else {
+ v.sub(&u);
+ v.norm();
+ if FF::comp(&x2, &x1) >= 0 {
+ x2.sub(&x1);
+ } else {
+ t.copy(&p);
+ t.sub(&x1);
+ x2.add(&t);
+ }
+ x2.norm();
+ }
+ }
+ if FF::comp(&u, &one) == 0 {
+ self.copy(&x1);
+ } else {
+ self.copy(&x2);
+ }
+ }
+
+ /* nresidue mod m */
+ pub fn nres(&mut self, m: &FF) {
+ let n = m.length;
+ if n == 1 {
+ let mut d = DBIG::new_scopy(&(self.v[0]));
+ d.shl(big::NLEN * (big::BASEBITS as usize));
+ self.v[0].copy(&d.dmod(&(m.v[0])));
+ } else {
+ let mut d = FF::new_int(2 * n);
+ d.dsucopy(&self);
+ self.copy(&d.dmod(m));
+ }
+ }
+
+ pub fn redc(&mut self, m: &FF, md: &FF) {
+ let n = m.length;
+ if n == 1 {
+ let mut d = DBIG::new_scopy(&(self.v[0]));
+ self.v[0].copy(&BIG::monty(
+ &(m.v[0]),
+ ((1 as Chunk) << big::BASEBITS) - md.v[0].w[0],
+ &mut d,
+ ));
+ } else {
+ let mut d = FF::new_int(2 * n);
+ self.rmod(m);
+ d.dscopy(&self);
+ self.copy(&d.reduce(&m, &md));
+ self.rmod(m);
+ }
+ }
+
+ pub fn mod2m(&mut self, m: usize) {
+ for i in m..self.length {
+ self.v[i].zero()
+ }
+ }
+
+ /* U=1/a mod 2^m - Arazi & Qi */
+ pub fn invmod2m(&self) -> FF {
+ let n = self.length;
+
+ let mut b = FF::new_int(n);
+ let mut c = FF::new_int(n);
+ let mut u = FF::new_int(n);
+
+ u.zero();
+ u.v[0].copy(&self.v[0]);
+ u.v[0].invmod2m();
+
+ let mut i = 1;
+ while i < n {
+ b.copy(&self);
+ b.mod2m(i);
+ let mut t = FF::mul(&u, &b);
+ t.shrw(i);
+ b.copy(&t);
+ c.copy(&self);
+ c.shrw(i);
+ c.mod2m(i);
+ c.lmul(&u);
+ c.mod2m(i);
+
+ b.add(&c);
+ b.norm();
+ b.lmul(&u);
+ b.mod2m(i);
+
+ c.one();
+ c.shlw(i);
+ b.revsub(&c);
+ b.norm();
+ b.shlw(i);
+ u.add(&b);
+ i <<= 1;
+ }
+ u.norm();
+ return u;
+ }
+
+ pub fn random(&mut self, rng: &mut RAND) {
+ let n = self.length;
+ for i in 0..n {
+ self.v[i].copy(&BIG::random(rng))
+ }
+ /* make sure top bit is 1 */
+ while self.v[n - 1].nbits() < (big::MODBYTES as usize) * 8 {
+ self.v[n - 1].copy(&BIG::random(rng));
+ }
+ }
+
+ /* generate random x less than p */
+ pub fn randomnum(&mut self, p: &FF, rng: &mut RAND) {
+ let n = self.length;
+ let mut d = FF::new_int(2 * n);
+
+ for i in 0..2 * n {
+ d.v[i].copy(&BIG::random(rng));
+ }
+ self.copy(&d.dmod(p));
+ }
+
+ /* this*=y mod p */
+ pub fn modmul(&mut self, y: &FF, p: &FF, nd: &FF) {
+ if FF::pexceed(&self.v[self.length - 1], &y.v[y.length - 1]) {
+ self.rmod(p)
+ }
+ let n = p.length;
+ if n == 1 {
+ let mut d = BIG::mul(&self.v[0], &y.v[0]);
+ self.v[0].copy(&BIG::monty(
+ &(p.v[0]),
+ ((1 as Chunk) << big::BASEBITS) - nd.v[0].w[0],
+ &mut d,
+ ));
+ } else {
+ let mut d = FF::mul(&self, y);
+ self.copy(&d.reduce(p, nd));
+ }
+ }
+
+ /* this*=y mod p */
+ pub fn modsqr(&mut self, p: &FF, nd: &FF) {
+ if FF::sexceed(&self.v[self.length - 1]) {
+ self.rmod(p);
+ }
+ let n = p.length;
+ if n == 1 {
+ let mut d = BIG::sqr(&self.v[0]);
+ self.v[0].copy(&BIG::monty(
+ &(p.v[0]),
+ ((1 as Chunk) << big::BASEBITS) - nd.v[0].w[0],
+ &mut d,
+ ));
+ } else {
+ let mut d = FF::sqr(&self);
+ d.norm();
+ self.copy(&d.reduce(p, nd));
+ }
+ }
+
+ /* this=this^e mod p using side-channel resistant Montgomery Ladder, for large e */
+ pub fn skpow(&mut self, e: &FF, p: &FF) {
+ let n = p.length;
+ let mut r0 = FF::new_int(n);
+ let mut r1 = FF::new_int(n);
+ let nd = p.invmod2m();
+
+ self.rmod(p);
+ r0.one();
+ r1.copy(&self);
+ r0.nres(p);
+ r1.nres(p);
+
+ let mut i = 8 * (big::MODBYTES as usize) * n - 1;
+ loop {
+ let b = (e.v[i / (big::BIGBITS as usize)]).bit(i % (big::BIGBITS as usize)) as isize;
+ self.copy(&r0);
+ self.modmul(&r1, p, &nd);
+
+ FF::cswap(&mut r0, &mut r1, b);
+ r0.modsqr(p, &nd);
+
+ r1.copy(&self);
+ FF::cswap(&mut r0, &mut r1, b);
+ if i == 0 {
+ break;
+ }
+ i -= 1;
+ }
+ self.copy(&r0);
+ self.redc(p, &nd);
+ }
+
+ /* this =this^e mod p using side-channel resistant Montgomery Ladder, for short e */
+ pub fn skpows(&mut self, e: &BIG, p: &FF) {
+ let n = p.length;
+ let mut r0 = FF::new_int(n);
+ let mut r1 = FF::new_int(n);
+ let nd = p.invmod2m();
+
+ self.rmod(p);
+ r0.one();
+ r1.copy(&self);
+ r0.nres(p);
+ r1.nres(p);
+
+ let mut i = 8 * (big::MODBYTES as usize) - 1;
+ loop {
+ let b = e.bit(i);
+ self.copy(&r0);
+ self.modmul(&r1, p, &nd);
+
+ FF::cswap(&mut r0, &mut r1, b);
+ r0.modsqr(p, &nd);
+
+ r1.copy(&self);
+ FF::cswap(&mut r0, &mut r1, b);
+ if i == 0 {
+ break;
+ }
+ i -= 1;
+ }
+ self.copy(&r0);
+ self.redc(p, &nd);
+ }
+
+ /* raise to an integer power - right-to-left method */
+ pub fn power(&mut self, e: isize, p: &FF) {
+ let n = p.length;
+ let mut w = FF::new_int(n);
+ let nd = p.invmod2m();
+ let mut f = true;
+ let mut ee = e;
+
+ w.copy(&self);
+ w.nres(p);
+
+ if ee == 2 {
+ self.copy(&w);
+ self.modsqr(p, &nd);
+ } else {
+ loop {
+ if ee % 2 == 1 {
+ if f {
+ self.copy(&w);
+ } else {
+ self.modmul(&w, p, &nd)
+ }
+ f = false;
+ }
+ ee >>= 1;
+ if ee == 0 {
+ break;
+ }
+ w.modsqr(p, &nd);
+ }
+ }
+
+ self.redc(p, &nd);
+ }
+
+ /* this=this^e mod p, faster but not side channel resistant */
+ pub fn pow(&mut self, e: &FF, p: &FF) {
+ let n = p.length;
+ let mut w = FF::new_int(n);
+ let nd = p.invmod2m();
+
+ w.copy(&self);
+ self.one();
+ self.nres(p);
+ w.nres(p);
+ let mut i = 8 * (big::MODBYTES as usize) * n - 1;
+ loop {
+ self.modsqr(p, &nd);
+ let b = (e.v[i / (big::BIGBITS as usize)]).bit(i % (big::BIGBITS as usize)) as isize;
+ if b == 1 {
+ self.modmul(&w, p, &nd)
+ }
+ if i == 0 {
+ break;
+ }
+ i -= 1;
+ }
+ self.redc(p, &nd);
+ }
+
+ /* double exponentiation r=x^e.y^f mod p */
+ pub fn pow2(&mut self, e: &BIG, y: &FF, f: &BIG, p: &FF) {
+ let n = p.length;
+ let mut xn = FF::new_int(n);
+ let mut yn = FF::new_int(n);
+ let mut xy = FF::new_int(n);
+ let nd = p.invmod2m();
+
+ xn.copy(&self);
+ yn.copy(y);
+ xn.nres(p);
+ yn.nres(p);
+ xy.copy(&xn);
+ xy.modmul(&yn, p, &nd);
+ self.one();
+ self.nres(p);
+
+ let mut i = 8 * (big::MODBYTES as usize) - 1;
+ loop {
+ let eb = e.bit(i);
+ let fb = f.bit(i);
+ self.modsqr(p, &nd);
+ if eb == 1 {
+ if fb == 1 {
+ self.modmul(&xy, p, &nd);
+ } else {
+ self.modmul(&xn, p, &nd)
+ }
+ } else {
+ if fb == 1 {
+ self.modmul(&yn, p, &nd)
+ }
+ }
+ if i == 0 {
+ break;
+ }
+ i -= 1;
+ }
+ self.redc(p, &nd);
+ }
+
+ pub fn igcd(x: isize, y: isize) -> isize {
+ /* integer GCD, returns GCD of x and y */
+
+ if y == 0 {
+ return x;
+ }
+ let mut xx = x;
+ let mut yy = y;
+ loop {
+ let r = xx % yy;
+ if r == 0 {
+ break;
+ }
+ xx = yy;
+ yy = r;
+ }
+ return yy;
+ }
+
+ /* quick and dirty check for common factor with n */
+ pub fn cfactor(&self, s: isize) -> bool {
+ let n = self.length;
+
+ let mut x = FF::new_int(n);
+ let mut y = FF::new_int(n);
+
+ y.set(s);
+ x.copy(&self);
+ x.norm();
+
+ x.sub(&y);
+ x.norm();
+
+ while !x.iszilch() && x.parity() == 0 {
+ x.shr()
+ }
+
+ while FF::comp(&x, &y) > 0 {
+ x.sub(&y);
+ x.norm();
+ while !x.iszilch() && x.parity() == 0 {
+ x.shr()
+ }
+ }
+
+ let g = x.v[0].get(0) as isize;
+ let r = FF::igcd(s, g);
+ if r > 1 {
+ return true;
+ }
+ return false;
+ }
+
+ /* Miller-Rabin test for primality. Slow. */
+ pub fn prime(pp: &FF, rng: &mut RAND) -> bool {
+ let mut s = 0;
+ let n = pp.length;
+ let mut d = FF::new_int(n);
+ let mut x = FF::new_int(n);
+ let mut unity = FF::new_int(n);
+ let mut nm1 = FF::new_int(n);
+ let mut p = FF::new_int(n);
+ p.copy(pp);
+
+ let sf = 4849845; /* 3*5*.. *19 */
+ p.norm();
+
+ if p.cfactor(sf) {
+ return false;
+ }
+ unity.one();
+ nm1.copy(&p);
+ nm1.sub(&unity);
+ nm1.norm();
+ d.copy(&nm1);
+
+ while d.parity() == 0 {
+ d.shr();
+ s += 1;
+ }
+ if s == 0 {
+ return false;
+ }
+ for _ in 0..10 {
+ x.randomnum(&p, rng);
+
+ x.pow(&d, &p);
+
+ if FF::comp(&x, &unity) == 0 || FF::comp(&x, &nm1) == 0 {
+ continue;
+ }
+ let mut looper = false;
+ for _ in 1..s {
+ x.power(2, &p);
+ if FF::comp(&x, &unity) == 0 {
+ return false;
+ }
+ if FF::comp(&x, &nm1) == 0 {
+ looper = true;
+ break;
+ }
+ }
+ if looper {
+ continue;
+ }
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/fp.rs b/src/fp.rs
new file mode 100644
index 0000000..57345c1
--- /dev/null
+++ b/src/fp.rs
@@ -0,0 +1,717 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::big;
+use super::big::BIG;
+use super::dbig::DBIG;
+use super::rom;
+use super::super::arch::Chunk;
+use super::super::arch;
+use types::ModType;
+use std::str::FromStr;
+
+#[derive(Copy, Clone)]
+pub struct FP {
+ pub x: BIG,
+ pub xes: i32,
+}
+
+impl PartialEq for FP {
+ fn eq(&self, other: &FP) -> bool {
+ self.equals(other)
+ }
+}
+
+impl fmt::Display for FP {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "FP: [ {} ]", self.x)
+ }
+}
+
+impl fmt::Debug for FP {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "FP: [ {} ]", self.x)
+ }
+}
+
+pub use super::rom::{MODBITS, MOD8, MODTYPE, SH};
+use std::str::SplitWhitespace;
+use std::fmt;
+
+pub const FEXCESS:i32 = (((1 as i32)<<SH)-1);
+pub const OMASK:Chunk = (-1)<<(MODBITS%big::BASEBITS);
+pub const TBITS:usize=MODBITS%big::BASEBITS; // Number of active bits in top word
+pub const TMASK:Chunk=(1<<TBITS)-1;
+
+impl FP {
+ /* Constructors */
+ pub fn new() -> FP {
+ FP {
+ x: BIG::new(),
+ xes: 1,
+ }
+ }
+
+ pub fn new_int(a: isize) -> FP {
+ let mut f = FP::new();
+ f.x.inc(a);
+ f.nres();
+ return f;
+ }
+
+ pub fn new_copy(y: &FP) -> FP {
+ let mut f = FP::new();
+ f.x.copy(&(y.x));
+ f.xes = y.xes;
+ return f;
+ }
+
+ pub fn new_big(y: &BIG) -> FP {
+ let mut f = FP::new();
+ f.x.copy(y);
+ f.nres();
+ return f;
+ }
+
+ pub fn nres(&mut self) {
+ if MODTYPE != ModType::PSEUDO_MERSENNE && MODTYPE != ModType::GENERALISED_MERSENNE {
+ let r=BIG::new_ints(&rom::R2MODP);
+ let mut d=BIG::mul(&(self.x),&r);
+ self.x.copy(&FP::modulo(&mut d));
+ self.xes = 2;
+ } else {
+ self.xes = 1;
+ }
+ }
+
+ pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP {
+ let xes = i32::from_str(iter.next().unwrap()).unwrap();
+ let x = iter.next().unwrap();
+ FP {
+ x: BIG::from_hex(x.to_string()),
+ xes
+ }
+ }
+
+ pub fn from_hex(val: String) -> FP {
+ let mut s = val.split_whitespace();
+ FP::from_hex_iter(&mut s)
+ }
+
+ pub fn to_hex(&self) -> String {
+ let mut x = self.x;
+ let big = x.to_hex();
+ format!("{} {}", self.xes, big)
+ }
+
+/* convert back to regular form */
+ pub fn redc(&mut self) -> BIG {
+ if MODTYPE != ModType::PSEUDO_MERSENNE && MODTYPE != ModType::GENERALISED_MERSENNE {
+ let mut d=DBIG::new_scopy(&(self.x));
+ return FP::modulo(&mut d);
+ } else {
+ let r = BIG::new_copy(&(self.x));
+ return r;
+ }
+ }
+
+ /* reduce a DBIG to a BIG using the appropriate form of the modulus */
+ /* dd */
+ pub fn modulo(d: &mut DBIG) -> BIG {
+ if MODTYPE==ModType::PSEUDO_MERSENNE {
+ let mut b=BIG::new();
+ let mut t=d.split(MODBITS);
+ b.dcopy(&d);
+ let v = t.pmul(rom::MCONST as isize);
+
+ t.add(&b);
+ t.norm();
+
+ let tw = t.w[big::NLEN - 1];
+ t.w[big::NLEN - 1] &= TMASK;
+ t.w[0] += rom::MCONST * ((tw >> TBITS) + (v << (big::BASEBITS - TBITS)));
+ t.norm();
+ return t;
+ }
+
+ if MODTYPE==ModType::MONTGOMERY_FRIENDLY {
+ let mut b = BIG::new();
+ for i in 0..big::NLEN {
+ let x = d.w[i];
+
+ let tuple = BIG::muladd(x, rom::MCONST - 1, x, d.w[big::NLEN + i - 1]);
+ d.w[big::NLEN + i] += tuple.0;
+ d.w[big::NLEN + i - 1] = tuple.1;
+ }
+
+ b.zero();
+
+ for i in 0..big::NLEN {
+ b.w[i] = d.w[big::NLEN + i];
+ }
+ b.norm();
+ return b;
+ }
+
+ if MODTYPE == ModType::GENERALISED_MERSENNE {
+ // GoldiLocks Only
+ let mut b = BIG::new();
+ let t = d.split(MODBITS);
+ let rm2 = (MODBITS / 2) as usize;
+ b.dcopy(&d);
+ b.add(&t);
+ let mut dd = DBIG::new_scopy(&t);
+ dd.shl(rm2);
+
+ let mut tt = dd.split(MODBITS);
+ let lo = BIG::new_dcopy(&dd);
+ b.add(&tt);
+ b.add(&lo);
+ b.norm();
+ tt.shl(rm2);
+ b.add(&tt);
+
+ let carry = b.w[big::NLEN - 1] >> TBITS;
+ b.w[big::NLEN - 1] &= TMASK;
+ b.w[0] += carry;
+
+ b.w[(224 / big::BASEBITS) as usize] += carry << (224 % big::BASEBITS);
+ b.norm();
+ return b;
+ }
+ if MODTYPE == ModType::NOT_SPECIAL {
+ let m = BIG::new_ints(&rom::MODULUS);
+ return BIG::monty(&m, rom::MCONST, d);
+ }
+ return BIG::new();
+ }
+
+ /* convert to string */
+ pub fn tostring(&mut self) -> String {
+ let s = self.redc().tostring();
+ return s;
+ }
+
+ /* reduce this mod Modulus */
+ pub fn reduce(&mut self) {
+ let mut m = BIG::new_ints(&rom::MODULUS);
+ let mut r = BIG::new_copy(&m);
+ let mut sb: usize;
+ self.x.norm();
+ if self.xes > 16 {
+ let q = FP::quo(&self.x, &m);
+ let carry = r.pmul(q);
+ r.w[big::NLEN - 1] += carry << big::BASEBITS; // correction - put any carry out back in again
+ self.x.sub(&r);
+ self.x.norm();
+ sb = 2;
+ } else {
+ sb = FP::logb2((self.xes - 1) as u32);
+ }
+ m.fshl(sb);
+
+ while sb > 0 {
+ let sr = BIG::ssn(&mut r, &self.x, &mut m);
+ self.x.cmove(&r, 1 - sr);
+ sb = sb - 1;
+ }
+
+ self.xes = 1;
+ }
+
+ /* test this=0? */
+ pub fn iszilch(&self) -> bool {
+ let mut a = FP::new_copy(self);
+ a.reduce();
+ return a.x.iszilch();
+ }
+
+ /* copy from FP b */
+ pub fn copy(&mut self, b: &FP) {
+ self.x.copy(&(b.x));
+ self.xes = b.xes;
+ }
+
+ /* copy from BIG b */
+ pub fn bcopy(&mut self, b: &BIG) {
+ self.x.copy(&b);
+ self.nres();
+ }
+
+ /* set this=0 */
+ pub fn zero(&mut self) {
+ self.x.zero();
+ self.xes = 1;
+ }
+
+ /* set this=1 */
+ pub fn one(&mut self) {
+ self.x.one();
+ self.nres()
+ }
+
+ /* normalise this */
+ pub fn norm(&mut self) {
+ self.x.norm();
+ }
+ /* swap FPs depending on d */
+ pub fn cswap(&mut self, b: &mut FP, d: isize) {
+ self.x.cswap(&mut (b.x), d);
+ let mut c = d as i32;
+ c = !(c - 1);
+ let t = c & (self.xes ^ b.xes);
+ self.xes ^= t;
+ b.xes ^= t;
+ }
+
+ /* copy FPs depending on d */
+ pub fn cmove(&mut self, b: &FP, d: isize) {
+ self.x.cmove(&(b.x), d);
+ let c = d as i32;
+ self.xes ^= (self.xes ^ b.xes) & (-c);
+ }
+
+ /* this*=b mod Modulus */
+ pub fn mul(&mut self, b: &FP) {
+ if (self.xes as i64) * (b.xes as i64) > FEXCESS as i64 {
+ self.reduce()
+ }
+
+ let mut d = BIG::mul(&(self.x), &(b.x));
+ self.x.copy(&FP::modulo(&mut d));
+ self.xes = 2;
+ }
+
+ fn logb2(w: u32) -> usize {
+ let mut v = w;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+
+ v = v - ((v >> 1) & 0x55555555);
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+ let r = ((((v + (v >> 4)) & 0xF0F0F0F).wrapping_mul(0x1010101)) >> 24) as usize;
+ return r;
+ }
+
+ // find approximation to quotient of a/m
+ // Out by at most 2.
+ // Note that MAXXES is bounded to be 2-bits less than half a word
+ fn quo(n: &BIG, m: &BIG) -> isize {
+ let hb = arch::CHUNK / 2;
+
+ if TBITS < hb {
+ let sh = hb - TBITS;
+ let num = (n.w[big::NLEN - 1] << sh) | (n.w[big::NLEN - 2] >> (big::BASEBITS - sh));
+ let den = (m.w[big::NLEN - 1] << sh) | (m.w[big::NLEN - 2] >> (big::BASEBITS - sh));
+ return (num / (den + 1)) as isize;
+ } else {
+ let num = n.w[big::NLEN - 1];
+ let den = m.w[big::NLEN - 1];
+ return (num / (den + 1)) as isize;
+ }
+ }
+
+ /* this = -this mod Modulus */
+ pub fn neg(&mut self) {
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ let sb = FP::logb2((self.xes - 1) as u32);
+
+ p.fshl(sb);
+ self.x.rsub(&p);
+ self.xes = 1 << (sb as i32) + 1;
+ if self.xes > FEXCESS {
+ self.reduce()
+ }
+ }
+
+ /* this*=c mod Modulus, where c is a small int */
+ pub fn imul(&mut self, c: isize) {
+ let mut cc = c;
+ let mut s = false;
+ if cc < 0 {
+ cc = -cc;
+ s = true;
+ }
+
+ if MODTYPE == ModType::PSEUDO_MERSENNE || MODTYPE == ModType::GENERALISED_MERSENNE {
+ let mut d = self.x.pxmul(cc);
+ self.x.copy(&FP::modulo(&mut d));
+ self.xes = 2
+ } else {
+ if self.xes * (cc as i32) <= FEXCESS {
+ self.x.pmul(cc);
+ self.xes *= cc as i32;
+ } else {
+ let n = FP::new_int(cc);
+ self.mul(&n);
+ }
+ }
+
+ if s {
+ self.neg();
+ self.norm();
+ }
+ }
+
+ /* self*=self mod Modulus */
+ pub fn sqr(&mut self) {
+ if (self.xes as i64) * (self.xes as i64) > FEXCESS as i64 {
+ self.reduce()
+ }
+
+ let mut d = BIG::sqr(&(self.x));
+ self.x.copy(&FP::modulo(&mut d));
+ self.xes = 2
+ }
+
+ /* self+=b */
+ pub fn add(&mut self, b: &FP) {
+ self.x.add(&(b.x));
+ self.xes += b.xes;
+ if self.xes > FEXCESS {
+ self.reduce()
+ }
+ }
+
+ /* self+=self */
+ pub fn dbl(&mut self) {
+ self.x.dbl();
+ self.xes += self.xes;
+ if self.xes > FEXCESS {
+ self.reduce()
+ }
+ }
+
+ /* self-=b */
+ pub fn sub(&mut self, b: &FP) {
+ let mut n = FP::new_copy(b);
+ n.neg();
+ self.add(&n);
+ }
+
+ /* self=b-self */
+ pub fn rsub(&mut self, b: &FP) {
+ self.neg();
+ self.add(&b);
+ }
+
+ /* self/=2 mod Modulus */
+ pub fn div2(&mut self) {
+ if self.x.parity() == 0 {
+ self.x.fshr(1);
+ } else {
+ let p = BIG::new_ints(&rom::MODULUS);
+ self.x.add(&p);
+ self.x.norm();
+ self.x.fshr(1);
+ }
+ }
+
+ // See eprint paper https://eprint.iacr.org/2018/1038
+ // return this^(p-3)/4 or this^(p-5)/8
+ pub fn fpow(&mut self) -> FP {
+ let ac: [isize; 11] = [1, 2, 3, 6, 12, 15, 30, 60, 120, 240, 255];
+ let mut xp: [FP; 11] = [
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ ];
+ // phase 1
+ let mut t = FP::new();
+ xp[0].copy(&self); // 1
+ xp[1].copy(&self);
+ xp[1].sqr(); // 2
+ t.copy(&xp[1]);
+ xp[2].copy(&t);
+ xp[2].mul(&self); // 3
+ t.copy(&xp[2]);
+ xp[3].copy(&t);
+ xp[3].sqr(); // 6
+ t.copy(&xp[3]);
+ xp[4].copy(&t);
+ xp[4].sqr(); // 12
+ t.copy(&xp[4]);
+ t.mul(&xp[2]);
+ xp[5].copy(&t); // 15
+ t.copy(&xp[5]);
+ xp[6].copy(&t);
+ xp[6].sqr(); // 30
+ t.copy(&xp[6]);
+ xp[7].copy(&t);
+ xp[7].sqr(); // 60
+ t.copy(&xp[7]);
+ xp[8].copy(&t);
+ xp[8].sqr(); // 120
+ t.copy(&xp[8]);
+ xp[9].copy(&t);
+ xp[9].sqr(); // 240
+ t.copy(&xp[9]);
+ t.mul(&xp[5]);
+ xp[10].copy(&t); // 255
+
+ let mut n = MODBITS as isize;
+ let c: isize;
+
+ if MODTYPE == ModType::GENERALISED_MERSENNE {
+ // Goldilocks ONLY
+ n /= 2;
+ }
+
+ if MOD8 == 5 {
+ n -= 3;
+ c = ((rom::MCONST as isize) + 5) / 8;
+ } else {
+ n -= 2;
+ c = ((rom::MCONST as isize) + 3) / 4;
+ }
+ let mut bw = 0;
+ let mut w = 1;
+ while w < c {
+ w *= 2;
+ bw += 1;
+ }
+ let mut k = w - c;
+
+ let mut i = 10;
+ let mut key = FP::new();
+ if k != 0 {
+ while ac[i] > k {
+ i -= 1;
+ }
+ key.copy(&xp[i]);
+ k -= ac[i];
+ }
+ while k != 0 {
+ i -= 1;
+ if ac[i] > k {
+ continue;
+ }
+ key.mul(&xp[i]);
+ k -= ac[i];
+ }
+ // phase 2
+ t.copy(&xp[2]);
+ xp[1].copy(&t);
+ t.copy(&xp[5]);
+ xp[2].copy(&t);
+ t.copy(&xp[10]);
+ xp[3].copy(&t);
+
+ let mut j = 3;
+ let mut m = 8;
+ let nw = n - bw;
+ let mut r = FP::new();
+
+ while 2 * m < nw {
+ t.copy(&xp[j]);
+ j += 1;
+ for _ in 0..m {
+ t.sqr();
+ }
+ r.copy(&xp[j - 1]);
+ r.mul(&t);
+ xp[j].copy(&r);
+ m *= 2;
+ }
+ let mut lo = nw - m;
+ r.copy(&xp[j]);
+
+ while lo != 0 {
+ m /= 2;
+ j -= 1;
+ if lo < m {
+ continue;
+ }
+ lo -= m;
+ t.copy(&r);
+ for _ in 0..m {
+ t.sqr();
+ }
+ r.copy(&t);
+ r.mul(&xp[j]);
+ }
+ // phase 3
+ if bw != 0 {
+ for _ in 0..bw {
+ r.sqr();
+ }
+ r.mul(&key);
+ }
+ if MODTYPE == ModType::GENERALISED_MERSENNE {
+ // Goldilocks ONLY
+ key.copy(&r);
+ r.sqr();
+ r.mul(&self);
+ for _ in 0..n + 1 {
+ r.sqr();
+ }
+ r.mul(&key);
+ }
+ return r;
+ }
+ /* self=1/self mod Modulus */
+ pub fn inverse(&mut self) {
+ if MODTYPE == ModType::PSEUDO_MERSENNE || MODTYPE == ModType::GENERALISED_MERSENNE {
+ let mut y = self.fpow();
+ if MOD8 == 5 {
+ let mut t = FP::new_copy(self);
+ t.sqr();
+ self.mul(&t);
+ y.sqr();
+ }
+ y.sqr();
+ y.sqr();
+ self.mul(&y);
+ } else {
+ // Constant time inversion using Fermat's little theorem.
+ // Fermat's little theorem says for a prime p and for any a < p, a^p = a % p => a^(p-1) = 1 % p => a^(p-2) = a^-1 % p
+ let mut m2 = BIG::new_ints(&rom::MODULUS);
+ m2.dec(2);
+ m2.norm();
+ let inv = self.pow(&mut m2);
+ self.copy(&inv);
+ }
+ }
+
+ /* return TRUE if self==a */
+ pub fn equals(&self, a: &FP) -> bool {
+ let mut f = FP::new_copy(self);
+ let mut s = FP::new_copy(a);
+ f.reduce();
+ s.reduce();
+ if BIG::comp(&(f.x), &(s.x)) == 0 {
+ return true;
+ }
+ return false;
+ }
+
+ /* return self^e mod Modulus */
+ pub fn pow(&mut self, e: &mut BIG) -> FP {
+ let mut tb: [FP; 16] = [
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ FP::new(),
+ ];
+ const CT: usize = 1 + (big::NLEN * (big::BASEBITS as usize) + 3) / 4;
+ let mut w: [i8; CT] = [0; CT];
+
+ self.norm();
+ let mut t = BIG::new_copy(e);
+ t.norm();
+ let nb = 1 + (t.nbits() + 3) / 4;
+
+ for i in 0..nb {
+ let lsbs = t.lastbits(4);
+ t.dec(lsbs);
+ t.norm();
+ w[i] = lsbs as i8;
+ t.fshr(4);
+ }
+ tb[0].one();
+ tb[1].copy(&self);
+
+ let mut c = FP::new();
+ for i in 2..16 {
+ c.copy(&tb[i - 1]);
+ tb[i].copy(&c);
+ tb[i].mul(&self);
+ }
+ let mut r = FP::new_copy(&tb[w[nb - 1] as usize]);
+ for i in (0..nb - 1).rev() {
+ r.sqr();
+ r.sqr();
+ r.sqr();
+ r.sqr();
+ r.mul(&tb[w[i] as usize])
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* return sqrt(this) mod Modulus */
+ pub fn sqrt(&mut self) -> FP {
+ self.reduce();
+
+ if MOD8 == 5 {
+ let v: FP;
+ let mut i = FP::new_copy(self);
+ i.x.shl(1);
+ if MODTYPE == ModType::PSEUDO_MERSENNE || MODTYPE == ModType::GENERALISED_MERSENNE {
+ v = i.fpow();
+ } else {
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ p.dec(5);
+ p.norm();
+ p.shr(3);
+ v = i.pow(&mut p);
+ }
+ i.mul(&v);
+ i.mul(&v);
+ i.x.dec(1);
+ let mut r = FP::new_copy(self);
+ r.mul(&v);
+ r.mul(&i);
+ r.reduce();
+ return r;
+ } else {
+ let mut r: FP;
+ if MODTYPE == ModType::PSEUDO_MERSENNE || MODTYPE == ModType::GENERALISED_MERSENNE {
+ r = self.fpow();
+ r.mul(self);
+ } else {
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ p.inc(1);
+ p.norm();
+ p.shr(2);
+ r = self.pow(&mut p);
+ }
+ return r;
+ }
+ }
+ /* return jacobi symbol (this/Modulus) */
+ pub fn jacobi(&mut self) -> isize {
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ let mut w = self.redc();
+ return w.jacobi(&mut p);
+ }
+}
diff --git a/src/fp12.rs b/src/fp12.rs
new file mode 100644
index 0000000..9c06a3e
--- /dev/null
+++ b/src/fp12.rs
@@ -0,0 +1,1109 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::big;
+use super::fp2::FP2;
+use super::fp4::FP4;
+use super::big::BIG;
+use super::rom;
+use types::SexticTwist;
+use std::str::SplitWhitespace;
+use super::ecp;
+
+pub const ZERO: usize=0;
+pub const ONE: usize=1;
+pub const SPARSER: usize=2;
+pub const SPARSE: usize=3;
+pub const DENSE: usize=4;
+
+#[derive(Copy, Clone)]
+pub struct FP12 {
+ a: FP4,
+ b: FP4,
+ c: FP4,
+ stype: usize,
+}
+
+impl PartialEq for FP12 {
+ fn eq(&self, other: &FP12) -> bool {
+ self.equals(other)
+ }
+}
+
+impl FP12 {
+ pub fn new() -> FP12 {
+ FP12 {
+ a: FP4::new(),
+ b: FP4::new(),
+ c: FP4::new(),
+ stype: ZERO,
+ }
+ }
+
+ pub fn settype(&mut self,t: usize) {
+ self.stype = t;
+ }
+
+ pub fn gettype(&self) -> usize {
+ return self.stype;
+ }
+
+ pub fn new_int(a: isize) -> FP12 {
+ let mut f = FP12::new();
+ f.a.copy(&FP4::new_int(a));
+ f.b.zero();
+ f.c.zero();
+ if a == 1 {
+ f.stype=ONE;
+ } else {
+ f.stype=SPARSER;
+ }
+ return f;
+ }
+
+ pub fn new_copy(x: &FP12) -> FP12 {
+ let mut f = FP12::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ f.c.copy(&x.c);
+ f.stype=x.stype;
+ return f;
+ }
+
+ pub fn new_fp4s(d: &FP4, e: &FP4, f: &FP4) -> FP12 {
+ let mut g = FP12::new();
+ g.a.copy(d);
+ g.b.copy(e);
+ g.c.copy(f);
+ g.stype=DENSE;
+ return g;
+ }
+
+ pub fn new_fp4(d: &FP4) -> FP12 {
+ let mut g = FP12::new();
+ g.a.copy(d);
+ g.b.zero();
+ g.c.zero();
+ g.stype=SPARSER;
+ return g;
+ }
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ self.c.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ self.c.norm();
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ //self.reduce();
+ return self.a.iszilch() && self.b.iszilch() && self.c.iszilch();
+ }
+
+ /* Conditional move of g to self dependant on d */
+ pub fn cmove(&mut self, g: &FP12, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ self.c.cmove(&g.c, d);
+ let mut u=d as usize;
+ u=!(u-1);
+ self.stype^=(self.stype^g.stype)&u;
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* Constant time select from pre-computed table */
+ pub fn selector(&mut self, g: &[FP12], b: i32) {
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&g[0], FP12::teq(babs, 0)); // conditional move
+ self.cmove(&g[1], FP12::teq(babs, 1));
+ self.cmove(&g[2], FP12::teq(babs, 2));
+ self.cmove(&g[3], FP12::teq(babs, 3));
+ self.cmove(&g[4], FP12::teq(babs, 4));
+ self.cmove(&g[5], FP12::teq(babs, 5));
+ self.cmove(&g[6], FP12::teq(babs, 6));
+ self.cmove(&g[7], FP12::teq(babs, 7));
+
+ let mut invf = FP12::new_copy(self);
+ invf.conj();
+ self.cmove(&invf, (m & 1) as isize);
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP4::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch() && self.c.iszilch();
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP12) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b) && self.c.equals(&x.c);
+ }
+
+ pub fn geta(&mut self) -> FP4 {
+ return self.a;
+// let f = FP4::new_copy(&self.a);
+// return f;
+ }
+
+ pub fn getb(&mut self) -> FP4 {
+ return self.b;
+// let f = FP4::new_copy(&self.b);
+// return f;
+ }
+
+ pub fn getc(&mut self) -> FP4 {
+ return self.c;
+// let f = FP4::new_copy(&self.c);
+// return f;
+ }
+
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP12) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ self.c.copy(&x.c);
+ self.stype=x.stype;
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ self.c.zero();
+ self.stype=ONE;
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ self.c.zero();
+ self.stype=ZERO;
+ }
+
+ /* this=conj(this) */
+ pub fn conj(&mut self) {
+ self.a.conj();
+ self.b.nconj();
+ self.c.conj();
+ }
+
+ /* Granger-Scott Unitary Squaring */
+ pub fn usqr(&mut self) {
+ let mut a = FP4::new_copy(&self.a);
+ let mut b = FP4::new_copy(&self.c);
+ let mut c = FP4::new_copy(&self.b);
+ let mut d = FP4::new();
+
+ self.a.sqr();
+ d.copy(&self.a);
+ d.add(&self.a);
+ self.a.add(&d);
+
+ self.a.norm();
+ a.nconj();
+
+ a.dbl();
+ self.a.add(&a);
+ b.sqr();
+ b.times_i();
+
+ d.copy(&b);
+ d.add(&b);
+ b.add(&d);
+ b.norm();
+
+ c.sqr();
+ d.copy(&c);
+ d.add(&c);
+ c.add(&d);
+ c.norm();
+
+ self.b.conj();
+ self.b.dbl();
+ self.c.nconj();
+
+ self.c.dbl();
+ self.b.add(&b);
+ self.c.add(&c);
+ self.stype=DENSE;
+ self.reduce();
+ }
+
+ /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
+ pub fn sqr(&mut self) {
+ if self.stype==ONE {
+ return;
+ }
+
+ let mut a = FP4::new_copy(&self.a);
+ let mut b = FP4::new_copy(&self.b);
+ let mut c = FP4::new_copy(&self.c);
+ let mut d = FP4::new_copy(&self.a);
+
+ a.sqr();
+ b.mul(&self.c);
+ b.dbl();
+ b.norm();
+ c.sqr();
+ d.mul(&self.b);
+ d.dbl();
+
+ self.c.add(&self.a);
+ self.c.add(&self.b);
+ self.c.norm();
+ self.c.sqr();
+
+ self.a.copy(&a);
+ a.add(&b);
+ a.norm();
+ a.add(&c);
+ a.add(&d);
+ a.norm();
+
+ a.neg();
+ b.times_i();
+ c.times_i();
+
+ self.a.add(&b);
+
+ self.b.copy(&c);
+ self.b.add(&d);
+ self.c.add(&a);
+ if self.stype==SPARSER {
+ self.stype=SPARSE;
+ } else {
+ self.stype=DENSE;
+ }
+ self.norm();
+ }
+
+ /* FP12 full multiplication self=self*y */
+ pub fn mul(&mut self, y: &FP12) {
+ let mut z0 = FP4::new_copy(&self.a);
+ let mut z1 = FP4::new();
+ let mut z2 = FP4::new_copy(&mut self.b);
+ let mut z3 = FP4::new();
+ let mut t0 = FP4::new_copy(&self.a);
+ let mut t1 = FP4::new_copy(&y.a);
+
+ z0.mul(&y.a);
+ z2.mul(&y.b);
+
+ t0.add(&self.b);
+ t1.add(&y.b);
+
+ t0.norm();
+ t1.norm();
+
+ z1.copy(&t0);
+ z1.mul(&t1);
+ t0.copy(&self.b);
+ t0.add(&self.c);
+ t1.copy(&y.b);
+ t1.add(&y.c);
+
+ t0.norm();
+ t1.norm();
+
+ z3.copy(&t0);
+ z3.mul(&t1);
+
+ t0.copy(&z0);
+ t0.neg();
+ t1.copy(&z2);
+ t1.neg();
+
+ z1.add(&t0);
+ self.b.copy(&z1);
+ self.b.add(&t1);
+
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a);
+ t0.add(&self.c);
+ t0.norm();
+ t1.copy(&y.a);
+ t1.add(&y.c);
+ t1.norm();
+ t0.mul(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ t1.copy(&t0);
+ t1.neg();
+
+ self.c.copy(&z2);
+ self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+
+ z3.times_i();
+ self.a.copy(&z0);
+ self.a.add(&z3);
+ self.stype=DENSE;
+ self.norm();
+ }
+
+
+/* FP12 full multiplication w=w*y */
+/* Supports sparse multiplicands */
+/* Usually w is denser than y */
+ pub fn ssmul(&mut self, y: &FP12) {
+ if self.stype==ONE {
+ self.copy(&y);
+ return;
+ }
+ if y.stype==ONE {
+ return;
+ }
+ if y.stype>=SPARSE {
+ let mut z0=FP4::new_copy(&self.a);
+ let mut z1=FP4::new_int(0);
+ let mut z2=FP4::new_int(0);
+ let mut z3=FP4::new_int(0);
+ z0.mul(&y.a);
+
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+ if y.stype==SPARSE || self.stype==SPARSE {
+
+ let mut ga=FP2::new_int(0);
+ let mut gb=FP2::new_int(0);
+
+ gb.copy(&self.b.getb());
+ gb.mul(&y.b.getb());
+ ga.zero();
+ if y.stype!=SPARSE {
+ ga.copy(&self.b.getb());
+ ga.mul(&y.b.geta());
+ }
+ if self.stype!=SPARSE {
+ ga.copy(&self.b.geta());
+ ga.mul(&y.b.getb());
+ }
+ z2.set_fp2s(&ga,&gb);
+ z2.times_i();
+ } else {
+ z2.copy(&self.b);
+ z2.mul(&y.b);
+ }
+ } else {
+ z2.copy(&self.b);
+ z2.mul(&y.b);
+ }
+ let mut t0=FP4::new_copy(&self.a);
+ let mut t1=FP4::new_copy(&y.a);
+ t0.add(&self.b); t0.norm();
+ t1.add(&y.b); t1.norm();
+
+ z1.copy(&t0); z1.mul(&t1);
+ t0.copy(&self.b); t0.add(&self.c); t0.norm();
+ t1.copy(&y.b); t1.add(&y.c); t1.norm();
+
+ z3.copy(&t0); z3.mul(&t1);
+
+ t0.copy(&z0); t0.neg();
+ t1.copy(&z2); t1.neg();
+
+ z1.add(&t0);
+ self.b.copy(&z1); self.b.add(&t1);
+
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ t1.copy(&y.a); t1.add(&y.c); t1.norm();
+
+ t0.mul(&t1);
+ z2.add(&t0);
+
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE {
+ if y.stype==SPARSE || self.stype==SPARSE {
+
+ let mut ga=FP2::new_int(0);
+ let mut gb=FP2::new_int(0);
+
+ ga.copy(&self.c.geta());
+ ga.mul(&y.c.geta());
+ gb.zero();
+ if y.stype!=SPARSE {
+ gb.copy(&self.c.geta());
+ gb.mul(&y.c.getb());
+ }
+ if self.stype!=SPARSE {
+ gb.copy(&self.c.getb());
+ gb.mul(&y.c.geta());
+ }
+ t0.set_fp2s(&ga,&gb);
+ } else {
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ }
+ } else {
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ }
+ t1.copy(&t0); t1.neg();
+
+ self.c.copy(&z2); self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ } else {
+ if self.stype==SPARSER {
+ self.smul(&y);
+ return;
+ }
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE { // dense by sparser - 13m
+ let mut z0=FP4::new_copy(&self.a);
+ let mut z2=FP4::new_copy(&self.b);
+ let mut z3=FP4::new_copy(&self.b);
+ let mut t0=FP4::new_int(0);
+ let mut t1=FP4::new_copy(&y.a);
+
+ z0.mul(&y.a);
+ z2.pmul(&y.b.geta());
+ self.b.add(&self.a);
+ t1.padd(&y.b.geta());
+
+ t1.norm();
+ self.b.norm();
+ self.b.mul(&t1);
+ z3.add(&self.c);
+ z3.norm();
+ z3.pmul(&y.b.geta());
+
+ t0.copy(&z0); t0.neg();
+ t1.copy(&z2); t1.neg();
+
+ self.b.add(&t0);
+
+ self.b.add(&t1);
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ z3.norm();
+ t0.mul(&y.a);
+ self.c.copy(&z2); self.c.add(&t0);
+
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ }
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+
+ let mut z0 = FP4::new_copy(&self.a);
+ let mut z1 = FP4::new();
+ let mut z2 = FP4::new();
+ let mut z3 = FP4::new();
+ let mut t0 = FP4::new_copy(&self.a);
+ let mut t1 = FP4::new();
+
+ z0.mul(&y.a);
+ t0.add(&self.b); t0.norm();
+
+ z1.copy(&t0); z1.mul(&y.a);
+ t0.copy(&self.b); t0.add(&self.c);
+ t0.norm();
+
+ z3.copy(&t0);
+ z3.pmul(&y.c.getb());
+ z3.times_i();
+
+ t0.copy(&z0); t0.neg();
+ z1.add(&t0);
+ self.b.copy(&z1);
+ z2.copy(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ t1.copy(&y.a); t1.add(&y.c); t1.norm();
+
+ t0.mul(&t1);
+ z2.add(&t0);
+ t0.copy(&self.c);
+
+ t0.pmul(&y.c.getb());
+ t0.times_i();
+ t1.copy(&t0); t1.neg();
+
+ self.c.copy(&z2); self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ }
+ }
+ self.stype=DENSE;
+ self.norm();
+ }
+
+ /* Special case of multiplication arises from special form of ATE pairing line function */
+ pub fn smul(&mut self, y: &FP12) {
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE {
+ let mut w1=FP2::new_copy(&self.a.geta());
+ let mut w2=FP2::new_copy(&self.a.getb());
+ let mut w3=FP2::new_copy(&self.b.geta());
+
+ w1.mul(&y.a.geta());
+ w2.mul(&y.a.getb());
+ w3.mul(&y.b.geta());
+
+ let mut ta=FP2::new_copy(&self.a.geta());
+ let mut tb=FP2::new_copy(&y.a.geta());
+ ta.add(&self.a.getb()); ta.norm();
+ tb.add(&y.a.getb()); tb.norm();
+ let mut tc=FP2::new_copy(&ta);
+ tc.mul(&tb);
+ let mut t=FP2::new_copy(&w1);
+ t.add(&w2);
+ t.neg();
+ tc.add(&t);
+
+ ta.copy(&self.a.geta()); ta.add(&self.b.geta()); ta.norm();
+ tb.copy(&y.a.geta()); tb.add(&y.b.geta()); tb.norm();
+ let mut td=FP2::new_copy(&ta);
+ td.mul(&tb);
+ t.copy(&w1);
+ t.add(&w3);
+ t.neg();
+ td.add(&t);
+
+ ta.copy(&self.a.getb()); ta.add(&self.b.geta()); ta.norm();
+ tb.copy(&y.a.getb()); tb.add(&y.b.geta()); tb.norm();
+ let mut te=FP2::new_copy(&ta);
+ te.mul(&tb);
+ t.copy(&w2);
+ t.add(&w3);
+ t.neg();
+ te.add(&t);
+
+ w2.mul_ip();
+ w1.add(&w2);
+
+ self.a.set_fp2s(&w1,&tc);
+ self.b.set_fp2s(&td,&te);
+ self.c.set_fp2(&w3);
+
+ self.a.norm();
+ self.b.norm();
+ } else {
+ let mut w1=FP2::new_copy(&self.a.geta());
+ let mut w2=FP2::new_copy(&self.a.getb());
+ let mut w3=FP2::new_copy(&self.c.getb());
+
+ w1.mul(&y.a.geta());
+ w2.mul(&y.a.getb());
+ w3.mul(&y.c.getb());
+
+ let mut ta=FP2::new_copy(&self.a.geta());
+ let mut tb=FP2::new_copy(&y.a.geta());
+ ta.add(&self.a.getb()); ta.norm();
+ tb.add(&y.a.getb()); tb.norm();
+ let mut tc=FP2::new_copy(&ta);
+ tc.mul(&tb);
+ let mut t=FP2::new_copy(&w1);
+ t.add(&w2);
+ t.neg();
+ tc.add(&t);
+
+ ta.copy(&self.a.geta()); ta.add(&self.c.getb()); ta.norm();
+ tb.copy(&y.a.geta()); tb.add(&y.c.getb()); tb.norm();
+ let mut td=FP2::new_copy(&ta);
+ td.mul(&tb);
+ t.copy(&w1);
+ t.add(&w3);
+ t.neg();
+ td.add(&t);
+
+ ta.copy(&self.a.getb()); ta.add(&self.c.getb()); ta.norm();
+ tb.copy(&y.a.getb()); tb.add(&y.c.getb()); tb.norm();
+ let mut te=FP2::new_copy(&ta);
+ te.mul(&tb);
+ t.copy(&w2);
+ t.add(&w3);
+ t.neg();
+ te.add(&t);
+
+ w2.mul_ip();
+ w1.add(&w2);
+ self.a.set_fp2s(&w1,&tc);
+
+ w3.mul_ip();
+ w3.norm();
+ self.b.set_fp2h(&w3);
+
+ te.norm();
+ te.mul_ip();
+ self.c.set_fp2s(&te,&td);
+
+ self.a.norm();
+ self.c.norm();
+ }
+ self.stype=SPARSE;
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ let mut f0 = FP4::new_copy(&self.a);
+ let mut f1 = FP4::new_copy(&self.b);
+ let mut f2 = FP4::new_copy(&self.a);
+ let mut f3 = FP4::new();
+
+ self.norm();
+ f0.sqr();
+ f1.mul(&self.c);
+ f1.times_i();
+ f0.sub(&f1);
+ f0.norm();
+
+ f1.copy(&self.c);
+ f1.sqr();
+ f1.times_i();
+ f2.mul(&self.b);
+ f1.sub(&f2);
+ f1.norm();
+
+ f2.copy(&self.b);
+ f2.sqr();
+ f3.copy(&self.a);
+ f3.mul(&self.c);
+ f2.sub(&f3);
+ f2.norm();
+
+ f3.copy(&self.b);
+ f3.mul(&f2);
+ f3.times_i();
+ self.a.mul(&f0);
+ f3.add(&self.a);
+ self.c.mul(&f1);
+ self.c.times_i();
+
+ f3.add(&self.c);
+ f3.norm();
+ f3.inverse();
+ self.a.copy(&f0);
+ self.a.mul(&f3);
+ self.b.copy(&f1);
+ self.b.mul(&f3);
+ self.c.copy(&f2);
+ self.c.mul(&f3);
+ self.stype=DENSE;
+ }
+
+ /* self=self^p using Frobenius */
+ pub fn frob(&mut self, f: &FP2) {
+ let mut f2 = FP2::new_copy(f);
+ let mut f3 = FP2::new_copy(f);
+
+ f2.sqr();
+ f3.mul(&f2);
+
+ self.a.frob(&f3);
+ self.b.frob(&f3);
+ self.c.frob(&f3);
+
+ self.b.pmul(f);
+ self.c.pmul(&f2);
+ self.stype=DENSE;
+ }
+
+ /* trace function */
+ pub fn trace(&mut self) -> FP4 {
+ let mut t = FP4::new();
+ t.copy(&self.a);
+ t.imul(3);
+ t.reduce();
+ return t;
+ }
+
+ /* convert from byte array to FP12 */
+ pub fn frombytes(w: &[u8]) -> FP12 {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ for i in 0..mb {
+ t[i] = w[i]
+ }
+ let mut a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + mb]
+ }
+ let mut b = BIG::frombytes(&t);
+ let mut c = FP2::new_bigs(&a, &b);
+
+ for i in 0..mb {
+ t[i] = w[i + 2 * mb]
+ }
+ a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + 3 * mb]
+ }
+ b = BIG::frombytes(&t);
+ let mut d = FP2::new_bigs(&a, &b);
+
+ let e = FP4::new_fp2s(&c, &d);
+
+ for i in 0..mb {
+ t[i] = w[i + 4 * mb]
+ }
+ a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + 5 * mb]
+ }
+ b = BIG::frombytes(&t);
+ c = FP2::new_bigs(&a, &b);
+
+ for i in 0..mb {
+ t[i] = w[i + 6 * mb]
+ }
+ a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + 7 * mb]
+ }
+ b = BIG::frombytes(&t);
+ d = FP2::new_bigs(&a, &b);
+
+ let f = FP4::new_fp2s(&c, &d);
+
+ for i in 0..mb {
+ t[i] = w[i + 8 * mb]
+ }
+ a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + 9 * mb]
+ }
+ b = BIG::frombytes(&t);
+
+ c = FP2::new_bigs(&a, &b);
+
+ for i in 0..mb {
+ t[i] = w[i + 10 * mb]
+ }
+ a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + 11 * mb]
+ }
+ b = BIG::frombytes(&t);
+ d = FP2::new_bigs(&a, &b);
+
+ let g = FP4::new_fp2s(&c, &d);
+
+ return FP12::new_fp4s(&e, &f, &g);
+ }
+
+ /* convert this to byte array */
+ pub fn tobytes(&mut self, w: &mut [u8]) {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ self.a.geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i] = t[i]
+ }
+ self.a.geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + mb] = t[i]
+ }
+ self.a.getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 2 * mb] = t[i]
+ }
+ self.a.getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 3 * mb] = t[i]
+ }
+
+ self.b.geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 4 * mb] = t[i]
+ }
+ self.b.geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 5 * mb] = t[i]
+ }
+ self.b.getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 6 * mb] = t[i]
+ }
+ self.b.getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 7 * mb] = t[i]
+ }
+
+ self.c.geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 8 * mb] = t[i]
+ }
+ self.c.geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 9 * mb] = t[i]
+ }
+ self.c.getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 10 * mb] = t[i]
+ }
+ self.c.getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 11 * mb] = t[i]
+ }
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!(
+ "[{},{},{}]",
+ self.a.tostring(),
+ self.b.tostring(),
+ self.c.tostring()
+ );
+ }
+
+ pub fn to_hex(&self) -> String {
+ format!("{} {} {}", self.a.to_hex(), self.b.to_hex(), self.c.to_hex())
+ }
+
+ pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP12 {
+ FP12 {
+ a: FP4::from_hex_iter(iter),
+ b: FP4::from_hex_iter(iter),
+ c: FP4::from_hex_iter(iter),
+ stype: DENSE
+ }
+ }
+
+ pub fn from_hex(val: String) -> FP12 {
+ let mut iter = val.split_whitespace();
+ return FP12::from_hex_iter(&mut iter);
+ }
+
+ /* self=self^e */
+ pub fn pow(&self, e: &BIG) -> FP12 {
+ let mut r = FP12::new_copy(self);
+ r.norm();
+ let mut e1 = BIG::new_copy(e);
+ e1.norm();
+ let mut e3 = BIG::new_copy(&e1);
+ e3.pmul(3);
+ e3.norm();
+ let mut w = FP12::new_copy(&r);
+
+ let nb = e3.nbits();
+ for i in (1..nb - 1).rev() {
+ w.usqr();
+ let bt = e3.bit(i) - e1.bit(i);
+ if bt == 1 {
+ w.mul(&r);
+ }
+ if bt == -1 {
+ r.conj();
+ w.mul(&r);
+ r.conj();
+ }
+ }
+
+ w.reduce();
+ return w;
+ }
+
+ /* constant time powering by small integer of max length bts */
+ pub fn pinpow(&mut self, e: i32, bts: i32) {
+ let mut r: [FP12; 2] = [FP12::new_int(1), FP12::new_copy(self)];
+ let mut t = FP12::new();
+
+ for i in (0..bts).rev() {
+ let b: usize = ((e >> i) & 1) as usize;
+ t.copy(&r[b]);
+ r[1 - b].mul(&t);
+ r[b].usqr();
+ }
+ self.copy(&r[0]);
+ }
+
+ pub fn compow(&mut self, e: &BIG, r: &BIG) -> FP4 {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::MODULUS);
+
+ let mut g1 = FP12::new_copy(self);
+ let mut g2 = FP12::new_copy(self);
+
+ let mut m = BIG::new_copy(&q);
+ m.rmod(&r);
+
+ let mut a = BIG::new_copy(&e);
+ a.rmod(&mut m);
+
+ let mut b = BIG::new_copy(&e);
+ b.div(&mut m);
+
+ let mut c = g1.trace();
+
+ if b.iszilch() {
+ c = c.xtr_pow(&mut a);
+ return c;
+ }
+
+ g2.frob(&f);
+ let cp = g2.trace();
+ g1.conj();
+ g2.mul(&g1);
+ let cpm1 = g2.trace();
+ g2.mul(&g1);
+ let cpm2 = g2.trace();
+
+ c = c.xtr_pow2(&cp, &cpm1, &cpm2, &mut a, &mut b);
+
+ return c;
+ }
+
+ /* p=q0^u0.q1^u1.q2^u2.q3^u3 */
+ // Bos & Costello https://eprint.iacr.org/2013/458.pdf
+ // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
+ // Side channel attack secure
+ pub fn pow4(q: &[FP12], u: &[BIG]) -> FP12 {
+ let mut g: [FP12; 8] = [
+ FP12::new(),
+ FP12::new(),
+ FP12::new(),
+ FP12::new(),
+ FP12::new(),
+ FP12::new(),
+ FP12::new(),
+ FP12::new(),
+ ];
+
+ let mut r = FP12::new();
+ let mut p = FP12::new();
+ const CT: usize = 1 + big::NLEN * (big::BASEBITS as usize);
+ let mut w: [i8; CT] = [0; CT];
+ let mut s: [i8; CT] = [0; CT];
+
+ let mut mt = BIG::new();
+ let mut t: [BIG; 4] = [
+ BIG::new_copy(&u[0]),
+ BIG::new_copy(&u[1]),
+ BIG::new_copy(&u[2]),
+ BIG::new_copy(&u[3]),
+ ];
+
+ for i in 0..4 {
+ t[i].norm();
+ }
+
+ // precomputation
+ g[0].copy(&q[0]);
+ r.copy(&g[0]);
+ g[1].copy(&r);
+ g[1].mul(&q[1]); // q[0].q[1]
+ g[2].copy(&r);
+ g[2].mul(&q[2]);
+ r.copy(&g[1]); // q[0].q[2]
+ g[3].copy(&r);
+ g[3].mul(&q[2]);
+ r.copy(&g[0]); // q[0].q[1].q[2]
+ g[4].copy(&r);
+ g[4].mul(&q[3]);
+ r.copy(&g[1]); // q[0].q[3]
+ g[5].copy(&r);
+ g[5].mul(&q[3]);
+ r.copy(&g[2]); // q[0].q[1].q[3]
+ g[6].copy(&r);
+ g[6].mul(&q[3]);
+ r.copy(&g[3]); // q[0].q[2].q[3]
+ g[7].copy(&r);
+ g[7].mul(&q[3]); // q[0].q[1].q[2].q[3]
+
+ // Make it odd
+ let pb = 1 - t[0].parity();
+ t[0].inc(pb);
+ t[0].norm();
+
+ // Number of bits
+ mt.zero();
+ for i in 0..4 {
+ mt.or(&t[i]);
+ }
+
+ let nb = 1 + mt.nbits();
+
+ // Sign pivot
+ s[nb - 1] = 1;
+ for i in 0..nb - 1 {
+ t[0].fshr(1);
+ s[i] = (2 * t[0].parity() - 1) as i8;
+ //println!("s={}",s[i]);
+ }
+
+ // Recoded exponent
+ for i in 0..nb {
+ w[i] = 0;
+ let mut k = 1;
+ for j in 1..4 {
+ let bt = s[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+ }
+
+ // Main loop
+ p.selector(&g, (2 * w[nb - 1] + 1) as i32);
+ for i in (0..nb - 1).rev() {
+ p.usqr();
+ r.selector(&g, (2 * w[i] + s[i]) as i32);
+ p.mul(&r);
+ }
+
+ // apply correction
+ r.copy(&q[0]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb);
+ p.reduce();
+ return p;
+ }
+}
diff --git a/src/fp16.rs b/src/fp16.rs
new file mode 100644
index 0000000..c579db4
--- /dev/null
+++ b/src/fp16.rs
@@ -0,0 +1,602 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::fp2::FP2;
+use super::fp8::FP8;
+use super::big::BIG;
+//use std::str::SplitWhitespace;
+
+#[derive(Copy, Clone)]
+pub struct FP16 {
+ a: FP8,
+ b: FP8,
+}
+
+impl FP16 {
+ pub fn new() -> FP16 {
+ FP16 {
+ a: FP8::new(),
+ b: FP8::new(),
+ }
+ }
+
+ pub fn new_int(a: isize) -> FP16 {
+ let mut f = FP16::new();
+ f.a.copy(&FP8::new_int(a));
+ f.b.zero();
+ return f;
+ }
+
+ pub fn new_copy(x: &FP16) -> FP16 {
+ let mut f = FP16::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ return f;
+ }
+
+ pub fn new_fp8s(c: &FP8, d: &FP8) -> FP16 {
+ let mut f = FP16::new();
+ f.a.copy(c);
+ f.b.copy(d);
+ return f;
+ }
+
+ pub fn new_fp8(c: &FP8) -> FP16 {
+ let mut f = FP16::new();
+ f.a.copy(c);
+ f.b.zero();
+ return f;
+ }
+
+ pub fn set_fp8s(&mut self,c: &FP8, d: &FP8) {
+ self.a.copy(&c);
+ self.b.copy(&d);
+ }
+
+ pub fn set_fp8(&mut self,c: &FP8) {
+ self.a.copy(&c);
+ self.b.zero();
+ }
+
+ pub fn set_fp8h(&mut self,c: &FP8) {
+ self.b.copy(&c);
+ self.a.zero();
+ }
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ }
+
+ pub fn cmove(&mut self, g: &FP16, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ return self.a.iszilch() && self.b.iszilch();
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP8::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch();
+ }
+
+ /* test is w real? That is in a+ib test b is zero */
+ pub fn isreal(&mut self) -> bool {
+ return self.b.iszilch();
+ }
+ /* extract real part a */
+ pub fn real(&self) -> FP8 {
+ let f = FP8::new_copy(&self.a);
+ return f;
+ }
+
+ pub fn geta(&self) -> FP8 {
+ return self.a;
+// let f = FP8::new_copy(&self.a);
+// return f;
+ }
+ /* extract imaginary part b */
+ pub fn getb(&self) -> FP8 {
+ return self.b;
+// let f = FP8::new_copy(&self.b);
+// return f;
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP16) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b);
+ }
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP16) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ }
+
+ /* negate self mod Modulus */
+ pub fn neg(&mut self) {
+ self.norm();
+ let mut m = FP8::new_copy(&self.a);
+ let mut t = FP8::new();
+
+ m.add(&self.b);
+ m.neg();
+ t.copy(&m);
+ t.add(&self.b);
+ self.b.copy(&m);
+ self.b.add(&self.a);
+ self.a.copy(&t);
+ self.norm();
+ }
+
+ /* set to a-ib */
+ pub fn conj(&mut self) {
+ self.b.neg();
+ self.norm();
+ }
+
+ /* self=-conjugate(self) */
+ pub fn nconj(&mut self) {
+ self.a.neg();
+ self.norm();
+ }
+
+ /* self+=a */
+ pub fn add(&mut self, x: &FP16) {
+ self.a.add(&x.a);
+ self.b.add(&x.b);
+ }
+
+ pub fn padd(&mut self, x: &FP8) {
+ self.a.add(x);
+ }
+
+ pub fn dbl(&mut self) {
+ self.a.dbl();
+ self.b.dbl();
+ }
+
+ /* self-=a */
+ pub fn sub(&mut self, x: &FP16) {
+ let mut m = FP16::new_copy(x);
+ m.neg();
+ self.add(&m);
+ }
+
+ /* this-=x */
+ pub fn rsub(&mut self, x: &FP16) {
+ self.neg();
+ self.add(x);
+ }
+
+ /* self*=s, where s is an FP8 */
+ pub fn pmul(&mut self, s: &FP8) {
+ self.a.mul(s);
+ self.b.mul(s);
+ }
+
+ /* self*=s, where s is an FP2 */
+ pub fn qmul(&mut self, s: &FP2) {
+ self.a.qmul(s);
+ self.b.qmul(s);
+ }
+
+ /* self*=i, where i is an int */
+ pub fn imul(&mut self, c: isize) {
+ self.a.imul(c);
+ self.b.imul(c);
+ }
+
+ /* self*=self */
+
+ pub fn sqr(&mut self) {
+ let mut t1 = FP8::new_copy(&self.a);
+ let mut t2 = FP8::new_copy(&self.b);
+ let mut t3 = FP8::new_copy(&self.a);
+
+ t3.mul(&self.b);
+ t1.add(&self.b);
+ t2.times_i();
+
+ t2.add(&self.a);
+
+ t1.norm();
+ t2.norm();
+
+ self.a.copy(&t1);
+
+ self.a.mul(&t2);
+
+ t2.copy(&t3);
+ t2.times_i();
+ t2.add(&t3);
+ t2.norm();
+ t2.neg();
+ self.a.add(&t2);
+
+ t3.dbl();
+ self.b.copy(&t3);
+
+ self.norm();
+ }
+
+ /* self*=y */
+ pub fn mul(&mut self, y: &FP16) {
+ let mut t1 = FP8::new_copy(&self.a);
+ let mut t2 = FP8::new_copy(&self.b);
+ let mut t3 = FP8::new();
+ let mut t4 = FP8::new_copy(&self.b);
+
+ t1.mul(&y.a);
+ t2.mul(&y.b);
+ t3.copy(&y.b);
+ t3.add(&y.a);
+ t4.add(&self.a);
+
+ t3.norm();
+ t4.norm();
+
+ t4.mul(&t3);
+
+ t3.copy(&t1);
+ t3.neg();
+ t4.add(&t3);
+ t4.norm();
+
+ t3.copy(&t2);
+ t3.neg();
+ self.b.copy(&t4);
+ self.b.add(&t3);
+
+ t2.times_i();
+ self.a.copy(&t2);
+ self.a.add(&t1);
+
+ self.norm();
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!("[{},{}]", self.a.tostring(), self.b.tostring());
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ let mut t1 = FP8::new_copy(&self.a);
+ let mut t2 = FP8::new_copy(&self.b);
+
+ t1.sqr();
+ t2.sqr();
+ t2.times_i();
+ t2.norm();
+ t1.sub(&t2);
+ t1.norm();
+ t1.inverse();
+ self.a.mul(&t1);
+ t1.neg();
+ t1.norm();
+ self.b.mul(&t1);
+ }
+
+ /* self*=i where i = sqrt(-1+sqrt(-1)) */
+ pub fn times_i(&mut self) {
+ let mut s = FP8::new_copy(&self.b);
+ let t = FP8::new_copy(&self.a);
+ s.times_i();
+ self.a.copy(&s);
+ self.b.copy(&t);
+
+ self.norm();
+ }
+
+ pub fn times_i2(&mut self) {
+ self.a.times_i();
+ self.b.times_i();
+ }
+
+ pub fn times_i4(&mut self) {
+ self.a.times_i2();
+ self.b.times_i2();
+ }
+
+ /* self=self^p using Frobenius */
+ pub fn frob(&mut self, f: &FP2) {
+ let mut ff = FP2::new_copy(f);
+ ff.sqr();
+ ff.norm();
+ self.a.frob(&ff);
+ self.b.frob(&ff);
+ self.b.qmul(f);
+ self.b.times_i();
+ }
+
+ /* self=self^e */
+ pub fn pow(&self, e: &BIG) -> FP16 {
+ let mut w = FP16::new_copy(self);
+ w.norm();
+ let mut z = BIG::new_copy(&e);
+ let mut r = FP16::new_int(1);
+ z.norm();
+ loop {
+ let bt = z.parity();
+ z.fshr(1);
+ if bt == 1 {
+ r.mul(&mut w)
+ };
+ if z.iszilch() {
+ break;
+ }
+ w.sqr();
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* XTR xtr_a function */
+ pub fn xtr_a(&mut self, w: &FP16, y: &FP16, z: &FP16) {
+ let mut r = FP16::new_copy(w);
+ let mut t = FP16::new_copy(w);
+ r.sub(y);
+ r.norm();
+ r.pmul(&self.a);
+ t.add(y);
+ t.norm();
+ t.pmul(&self.b);
+ t.times_i();
+
+ self.copy(&r);
+ self.add(&t);
+ self.add(z);
+
+ self.norm();
+ }
+
+ /* XTR xtr_d function */
+ pub fn xtr_d(&mut self) {
+ let mut w = FP16::new_copy(self);
+ self.sqr();
+ w.conj();
+ w.dbl();
+ w.norm();
+ self.sub(&w);
+ self.reduce();
+ }
+
+ /* r=x^n using XTR method on traces of FP24s */
+ pub fn xtr_pow(&self, n: &BIG) -> FP16 {
+ let mut sf = FP16::new_copy(self);
+ sf.norm();
+ let mut a = FP16::new_int(3);
+ let mut b = FP16::new_copy(&sf);
+ let mut c = FP16::new_copy(&b);
+ c.xtr_d();
+ let mut t = FP16::new();
+ let mut r = FP16::new();
+
+ let par = n.parity();
+ let mut v = BIG::new_copy(n);
+ v.norm();
+ v.fshr(1);
+ if par == 0 {
+ v.dec(1);
+ v.norm();
+ }
+
+ let nb = v.nbits();
+ for i in (0..nb).rev() {
+ if v.bit(i) != 1 {
+ t.copy(&b);
+ sf.conj();
+ c.conj();
+ b.xtr_a(&a, &sf, &c);
+ sf.conj();
+ c.copy(&t);
+ c.xtr_d();
+ a.xtr_d();
+ } else {
+ t.copy(&a);
+ t.conj();
+ a.copy(&b);
+ a.xtr_d();
+ b.xtr_a(&c, &sf, &t);
+ c.xtr_d();
+ }
+ }
+ if par == 0 {
+ r.copy(&c)
+ } else {
+ r.copy(&b)
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
+ pub fn xtr_pow2(&mut self, ck: &FP16, ckml: &FP16, ckm2l: &FP16, a: &BIG, b: &BIG) -> FP16 {
+ let mut e = BIG::new_copy(a);
+ let mut d = BIG::new_copy(b);
+ let mut w = BIG::new();
+ d.norm();
+ e.norm();
+
+ let mut cu = FP16::new_copy(ck); // can probably be passed in w/o copying
+ let mut cv = FP16::new_copy(self);
+ let mut cumv = FP16::new_copy(ckml);
+ let mut cum2v = FP16::new_copy(ckm2l);
+ let mut r = FP16::new();
+ let mut t = FP16::new();
+
+ let mut f2: usize = 0;
+ while d.parity() == 0 && e.parity() == 0 {
+ d.fshr(1);
+ e.fshr(1);
+ f2 += 1;
+ }
+
+ while BIG::comp(&d, &e) != 0 {
+ if BIG::comp(&d, &e) > 0 {
+ w.copy(&e);
+ w.imul(4);
+ w.norm();
+ if BIG::comp(&d, &w) <= 0 {
+ w.copy(&d);
+ d.copy(&e);
+ e.rsub(&w);
+ e.norm();
+
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cum2v.copy(&cumv);
+ cum2v.conj();
+ cumv.copy(&cv);
+ cv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if d.parity() == 0 {
+ d.fshr(1);
+ r.copy(&cum2v);
+ r.conj();
+ t.copy(&cumv);
+ t.xtr_a(&cu, &cv, &r);
+ cum2v.copy(&cumv);
+ cum2v.xtr_d();
+ cumv.copy(&t);
+ cu.xtr_d();
+ } else {
+ if e.parity() == 1 {
+ d.sub(&e);
+ d.norm();
+ d.fshr(1);
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cu.xtr_d();
+ cum2v.copy(&cv);
+ cum2v.xtr_d();
+ cum2v.conj();
+ cv.copy(&t);
+ } else {
+ w.copy(&d);
+ d.copy(&e);
+ d.fshr(1);
+ e.copy(&w);
+ t.copy(&cumv);
+ t.xtr_d();
+ cumv.copy(&cum2v);
+ cumv.conj();
+ cum2v.copy(&t);
+ cum2v.conj();
+ t.copy(&cv);
+ t.xtr_d();
+ cv.copy(&cu);
+ cu.copy(&t);
+ }
+ }
+ }
+ }
+ if BIG::comp(&d, &e) < 0 {
+ w.copy(&d);
+ w.imul(4);
+ w.norm();
+ if BIG::comp(&e, &w) <= 0 {
+ e.sub(&d);
+ e.norm();
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cum2v.copy(&cumv);
+ cumv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if e.parity() == 0 {
+ w.copy(&d);
+ d.copy(&e);
+ d.fshr(1);
+ e.copy(&w);
+ t.copy(&cumv);
+ t.xtr_d();
+ cumv.copy(&cum2v);
+ cumv.conj();
+ cum2v.copy(&t);
+ cum2v.conj();
+ t.copy(&cv);
+ t.xtr_d();
+ cv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if d.parity() == 1 {
+ w.copy(&e);
+ e.copy(&d);
+ w.sub(&d);
+ w.norm();
+ d.copy(&w);
+ d.fshr(1);
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cumv.conj();
+ cum2v.copy(&cu);
+ cum2v.xtr_d();
+ cum2v.conj();
+ cu.copy(&cv);
+ cu.xtr_d();
+ cv.copy(&t);
+ } else {
+ d.fshr(1);
+ r.copy(&cum2v);
+ r.conj();
+ t.copy(&cumv);
+ t.xtr_a(&cu, &cv, &r);
+ cum2v.copy(&cumv);
+ cum2v.xtr_d();
+ cumv.copy(&t);
+ cu.xtr_d();
+ }
+ }
+ }
+ }
+ }
+ r.copy(&cv);
+ r.xtr_a(&cu, &cumv, &cum2v);
+ for _ in 0..f2 {
+ r.xtr_d()
+ }
+ r = r.xtr_pow(&mut d);
+ return r;
+ }
+}
diff --git a/src/fp2.rs b/src/fp2.rs
new file mode 100644
index 0000000..c848f19
--- /dev/null
+++ b/src/fp2.rs
@@ -0,0 +1,407 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::fp;
+use super::fp::FP;
+use super::big::BIG;
+use super::dbig::DBIG;
+use super::rom;
+use std::str::SplitWhitespace;
+use std::fmt;
+
+#[derive(Copy, Clone)]
+pub struct FP2 {
+ a: FP,
+ b: FP,
+}
+
+impl PartialEq for FP2 {
+ fn eq(&self, other: &FP2) -> bool {
+ self.equals(other)
+ }
+}
+
+impl fmt::Display for FP2 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "FP2: [ {}, {} ]", self.a, self.b)
+ }
+}
+
+impl fmt::Debug for FP2 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "FP2: [ {}, {} ]", self.a, self.b)
+ }
+}
+
+impl FP2 {
+ pub fn new() -> FP2 {
+ FP2 {
+ a: FP::new(),
+ b: FP::new(),
+ }
+ }
+
+ pub fn new_int(a: isize) -> FP2 {
+ let mut f = FP2::new();
+ f.a.copy(&FP::new_int(a));
+ f.b.zero();
+ return f;
+ }
+
+ pub fn new_copy(x: &FP2) -> FP2 {
+ let mut f = FP2::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ return f;
+ }
+
+ pub fn new_fps(c: &FP, d: &FP) -> FP2 {
+ let mut f = FP2::new();
+ f.a.copy(c);
+ f.b.copy(d);
+ return f;
+ }
+
+ pub fn new_bigs(c: &BIG, d: &BIG) -> FP2 {
+ let mut f = FP2::new();
+ f.a.copy(&FP::new_big(c));
+ f.b.copy(&FP::new_big(d));
+ return f;
+ }
+
+ pub fn new_fp(c: &FP) -> FP2 {
+ let mut f = FP2::new();
+ f.a.copy(c);
+ f.b.zero();
+ return f;
+ }
+
+ pub fn new_big(c: &BIG) -> FP2 {
+ let mut f = FP2::new();
+ f.a.copy(&FP::new_big(c));
+ f.b.zero();
+ return f;
+ }
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ return self.a.iszilch() && self.b.iszilch();
+ }
+
+ pub fn cmove(&mut self, g: &FP2, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch();
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP2) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b);
+ }
+
+ /* extract a */
+ pub fn geta(&mut self) -> BIG {
+ return self.a.redc();
+ }
+
+ /* extract b */
+ pub fn getb(&mut self) -> BIG {
+ return self.b.redc();
+ }
+
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP2) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ }
+
+ /* negate self mod Modulus */
+ pub fn neg(&mut self) {
+ let mut m = FP::new_copy(&self.a);
+ let mut t = FP::new();
+
+ m.add(&self.b);
+ m.neg();
+ t.copy(&m);
+ t.add(&self.b);
+ self.b.copy(&m);
+ self.b.add(&self.a);
+ self.a.copy(&t);
+ }
+
+ /* set to a-ib */
+ pub fn conj(&mut self) {
+ self.b.neg();
+ self.b.norm();
+ }
+
+ /* self+=a */
+ pub fn add(&mut self, x: &FP2) {
+ self.a.add(&x.a);
+ self.b.add(&x.b);
+ }
+
+ pub fn dbl(&mut self) {
+ self.a.dbl();
+ self.b.dbl();
+ }
+
+ /* self-=a */
+ pub fn sub(&mut self, x: &FP2) {
+ let mut m = FP2::new_copy(x);
+ m.neg();
+ self.add(&m);
+ }
+
+ /* self=a-self */
+ pub fn rsub(&mut self, x: &FP2) {
+ self.neg();
+ self.add(x);
+ }
+
+ /* self*=s, where s is an FP */
+ pub fn pmul(&mut self, s: &FP) {
+ self.a.mul(s);
+ self.b.mul(s);
+ }
+
+ /* self*=i, where i is an int */
+ pub fn imul(&mut self, c: isize) {
+ self.a.imul(c);
+ self.b.imul(c);
+ }
+
+ /* self*=self */
+ pub fn sqr(&mut self) {
+ let mut w1 = FP::new_copy(&self.a);
+ let mut w3 = FP::new_copy(&self.a);
+ let mut mb = FP::new_copy(&self.b);
+
+ w1.add(&self.b);
+
+ w3.add(&self.a);
+ w3.norm();
+ self.b.mul(&w3);
+
+ mb.neg();
+ self.a.add(&mb);
+
+ w1.norm();
+ self.a.norm();
+
+ self.a.mul(&w1);
+ }
+
+ /* this*=y */
+ pub fn mul(&mut self, y: &FP2) {
+ if ((self.a.xes + self.b.xes) as i64) * ((y.a.xes + y.b.xes) as i64) > fp::FEXCESS as i64 {
+ if self.a.xes > 1 {
+ self.a.reduce()
+ }
+ if self.b.xes > 1 {
+ self.b.reduce()
+ }
+ }
+
+ let p = BIG::new_ints(&rom::MODULUS);
+ let mut pr = DBIG::new();
+
+ pr.ucopy(&p);
+
+ let mut c = BIG::new_copy(&(self.a.x));
+ let mut d = BIG::new_copy(&(y.a.x));
+
+ let mut a = BIG::mul(&self.a.x, &y.a.x);
+ let mut b = BIG::mul(&self.b.x, &y.b.x);
+
+ c.add(&self.b.x);
+ c.norm();
+ d.add(&y.b.x);
+ d.norm();
+
+ let mut e = BIG::mul(&c, &d);
+ let mut f = DBIG::new_copy(&a);
+ f.add(&b);
+ b.rsub(&pr);
+
+ a.add(&b);
+ a.norm();
+ e.sub(&f);
+ e.norm();
+
+ self.a.x.copy(&FP::modulo(&mut a));
+ self.a.xes = 3;
+ self.b.x.copy(&FP::modulo(&mut e));
+ self.b.xes = 2;
+ }
+
+ /* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */
+ /* returns true if this is QR */
+ pub fn sqrt(&mut self) -> bool {
+ if self.iszilch() {
+ return true;
+ }
+ let mut w1 = FP::new_copy(&self.b);
+ let mut w2 = FP::new_copy(&self.a);
+ w1.sqr();
+ w2.sqr();
+ w1.add(&w2);
+ if w1.jacobi() != 1 {
+ self.zero();
+ return false;
+ }
+ w2.copy(&w1.sqrt());
+ w1.copy(&w2);
+ w2.copy(&self.a);
+ w2.add(&w1);
+ w2.norm();
+ w2.div2();
+ if w2.jacobi() != 1 {
+ w2.copy(&self.a);
+ w2.sub(&w1);
+ w2.norm();
+ w2.div2();
+ if w2.jacobi() != 1 {
+ self.zero();
+ return false;
+ }
+ }
+ w1.copy(&w2.sqrt());
+ self.a.copy(&w1);
+ w1.dbl();
+ w1.inverse();
+ self.b.mul(&w1);
+ return true;
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!("[{},{}]", self.a.tostring(), self.b.tostring());
+ }
+
+ pub fn to_hex(&self) -> String {
+ format!("{} {}", self.a.to_hex(), self.b.to_hex())
+ }
+
+ pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP2 {
+ FP2 {
+ a: FP::from_hex_iter(iter),
+ b: FP::from_hex_iter(iter)
+ }
+ }
+
+ pub fn from_hex(val: String) -> FP2 {
+ let mut iter = val.split_whitespace();
+ return FP2::from_hex_iter(&mut iter);
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ self.norm();
+ let mut w1 = FP::new_copy(&self.a);
+ let mut w2 = FP::new_copy(&self.b);
+
+ w1.sqr();
+ w2.sqr();
+ w1.add(&w2);
+ w1.inverse();
+ self.a.mul(&w1);
+ w1.neg();
+ w1.norm();
+ self.b.mul(&w1);
+ }
+
+ /* self/=2 */
+ pub fn div2(&mut self) {
+ self.a.div2();
+ self.b.div2();
+ }
+
+ /* self*=sqrt(-1) */
+ pub fn times_i(&mut self) {
+ let z = FP::new_copy(&self.a);
+ self.a.copy(&self.b);
+ self.a.neg();
+ self.b.copy(&z);
+ }
+
+ /* w*=(1+sqrt(-1)) */
+ /* where X*2-(1+sqrt(-1)) is irreducible for FP4, assumes p=3 mod 8 */
+ pub fn mul_ip(&mut self) {
+ let t = FP2::new_copy(self);
+ let z = FP::new_copy(&self.a);
+ self.a.copy(&self.b);
+ self.a.neg();
+ self.b.copy(&z);
+ self.add(&t);
+ }
+
+ pub fn div_ip2(&mut self) {
+ let mut t = FP2::new();
+ self.norm();
+ t.a.copy(&self.a);
+ t.a.add(&self.b);
+ t.b.copy(&self.b);
+ t.b.sub(&self.a);
+ t.norm();
+ self.copy(&t);
+ }
+
+ /* w/=(1+sqrt(-1)) */
+ pub fn div_ip(&mut self) {
+ let mut t = FP2::new();
+ self.norm();
+ t.a.copy(&self.a);
+ t.a.add(&self.b);
+ t.b.copy(&self.b);
+ t.b.sub(&self.a);
+ t.norm();
+ self.copy(&t);
+ self.div2();
+ }
+}
diff --git a/src/fp24.rs b/src/fp24.rs
new file mode 100644
index 0000000..5f154b3
--- /dev/null
+++ b/src/fp24.rs
@@ -0,0 +1,1268 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::big;
+use super::ecp;
+use super::fp2::FP2;
+use super::fp4::FP4;
+use super::fp8::FP8;
+use super::big::BIG;
+use super::rom;
+use types::{SexticTwist};
+//use std::str::SplitWhitespace;
+
+pub const ZERO: usize=0;
+pub const ONE: usize=1;
+pub const SPARSER: usize=2;
+pub const SPARSE: usize=3;
+pub const DENSE: usize=4;
+
+#[derive(Copy, Clone)]
+pub struct FP24 {
+ a: FP8,
+ b: FP8,
+ c: FP8,
+ stype: usize,
+}
+
+impl FP24 {
+ pub fn new() -> FP24 {
+ FP24 {
+ a: FP8::new(),
+ b: FP8::new(),
+ c: FP8::new(),
+ stype: ZERO,
+ }
+ }
+
+ pub fn settype(&mut self,t: usize) {
+ self.stype = t;
+ }
+
+ pub fn gettype(&self) -> usize {
+ return self.stype;
+ }
+
+ pub fn new_int(a: isize) -> FP24 {
+ let mut f = FP24::new();
+ f.a.copy(&FP8::new_int(a));
+ f.b.zero();
+ f.c.zero();
+ if a == 1 {
+ f.stype=ONE;
+ } else {
+ f.stype=SPARSER;
+ }
+ return f;
+ }
+
+ pub fn new_copy(x: &FP24) -> FP24 {
+ let mut f = FP24::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ f.c.copy(&x.c);
+ f.stype=x.stype;
+ return f;
+ }
+
+ pub fn new_fp8s(d: &FP8, e: &FP8, f: &FP8) -> FP24 {
+ let mut g = FP24::new();
+ g.a.copy(d);
+ g.b.copy(e);
+ g.c.copy(f);
+ g.stype=DENSE;
+ return g;
+ }
+
+ pub fn new_fp8(d: &FP8) -> FP24 {
+ let mut g = FP24::new();
+ g.a.copy(d);
+ g.b.zero();
+ g.c.zero();
+ g.stype=SPARSER;
+ return g;
+ }
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ self.c.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ self.c.norm();
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ return self.a.iszilch() && self.b.iszilch() && self.c.iszilch();
+ }
+
+ /* Conditional move of g to self dependant on d */
+ pub fn cmove(&mut self, g: &FP24, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ self.c.cmove(&g.c, d);
+ let mut u=d as usize;
+ u=!(u-1);
+ self.stype^=(self.stype^g.stype)&u;
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* Constant time select from pre-computed table */
+ pub fn selector(&mut self, g: &[FP24], b: i32) {
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&g[0], FP24::teq(babs, 0)); // conditional move
+ self.cmove(&g[1], FP24::teq(babs, 1));
+ self.cmove(&g[2], FP24::teq(babs, 2));
+ self.cmove(&g[3], FP24::teq(babs, 3));
+ self.cmove(&g[4], FP24::teq(babs, 4));
+ self.cmove(&g[5], FP24::teq(babs, 5));
+ self.cmove(&g[6], FP24::teq(babs, 6));
+ self.cmove(&g[7], FP24::teq(babs, 7));
+
+ let mut invf = FP24::new_copy(self);
+ invf.conj();
+ self.cmove(&invf, (m & 1) as isize);
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP8::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch() && self.c.iszilch();
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP24) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b) && self.c.equals(&x.c);
+ }
+
+ pub fn geta(&mut self) -> FP8 {
+ return self.a;
+// let f = FP8::new_copy(&self.a);
+// return f;
+ }
+
+ pub fn getb(&mut self) -> FP8 {
+ return self.b;
+// let f = FP8::new_copy(&self.b);
+// return f;
+ }
+
+ pub fn getc(&mut self) -> FP8 {
+ return self.c;
+// let f = FP8::new_copy(&self.c);
+// return f;
+ }
+
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP24) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ self.c.copy(&x.c);
+ self.stype=x.stype;
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ self.c.zero();
+ self.stype=ONE;
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ self.c.zero();
+ self.stype=ZERO;
+ }
+
+ /* this=conj(this) */
+ pub fn conj(&mut self) {
+ self.a.conj();
+ self.b.nconj();
+ self.c.conj();
+ }
+
+ /* Granger-Scott Unitary Squaring */
+ pub fn usqr(&mut self) {
+ let mut a = FP8::new_copy(&self.a);
+ let mut b = FP8::new_copy(&self.c);
+ let mut c = FP8::new_copy(&self.b);
+ let mut d = FP8::new();
+
+ self.a.sqr();
+ d.copy(&self.a);
+ d.add(&self.a);
+ self.a.add(&d);
+
+ self.a.norm();
+ a.nconj();
+
+ a.dbl();
+ self.a.add(&a);
+ b.sqr();
+ b.times_i();
+
+ d.copy(&b);
+ d.add(&b);
+ b.add(&d);
+ b.norm();
+
+ c.sqr();
+ d.copy(&c);
+ d.add(&c);
+ c.add(&d);
+ c.norm();
+
+ self.b.conj();
+ self.b.dbl();
+ self.c.nconj();
+
+ self.c.dbl();
+ self.b.add(&b);
+ self.c.add(&c);
+ self.stype=DENSE;
+ self.reduce();
+ }
+
+ /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
+ pub fn sqr(&mut self) {
+ if self.stype==ONE {
+ return;
+ }
+ let mut a = FP8::new_copy(&self.a);
+ let mut b = FP8::new_copy(&self.b);
+ let mut c = FP8::new_copy(&self.c);
+ let mut d = FP8::new_copy(&self.a);
+
+ a.sqr();
+ b.mul(&self.c);
+ b.dbl();
+ b.norm();
+ c.sqr();
+ d.mul(&self.b);
+ d.dbl();
+
+ self.c.add(&self.a);
+ self.c.add(&self.b);
+ self.c.norm();
+ self.c.sqr();
+
+ self.a.copy(&a);
+ a.add(&b);
+ a.norm();
+ a.add(&c);
+ a.add(&d);
+ a.norm();
+
+ a.neg();
+ b.times_i();
+ c.times_i();
+
+ self.a.add(&b);
+
+ self.b.copy(&c);
+ self.b.add(&d);
+ self.c.add(&a);
+ if self.stype==SPARSER {
+ self.stype=SPARSE;
+ } else {
+ self.stype=DENSE;
+ }
+ self.norm();
+ }
+
+ /* FP24 full multiplication self=self*y */
+ pub fn mul(&mut self, y: &FP24) {
+ let mut z0 = FP8::new_copy(&self.a);
+ let mut z1 = FP8::new();
+ let mut z2 = FP8::new_copy(&mut self.b);
+ let mut z3 = FP8::new();
+ let mut t0 = FP8::new_copy(&self.a);
+ let mut t1 = FP8::new_copy(&y.a);
+
+ z0.mul(&y.a);
+ z2.mul(&y.b);
+
+ t0.add(&self.b);
+ t1.add(&y.b);
+
+ t0.norm();
+ t1.norm();
+
+ z1.copy(&t0);
+ z1.mul(&t1);
+ t0.copy(&self.b);
+ t0.add(&self.c);
+ t1.copy(&y.b);
+ t1.add(&y.c);
+
+ t0.norm();
+ t1.norm();
+
+ z3.copy(&t0);
+ z3.mul(&t1);
+
+ t0.copy(&z0);
+ t0.neg();
+ t1.copy(&z2);
+ t1.neg();
+
+ z1.add(&t0);
+ //z1.norm();
+ self.b.copy(&z1);
+ self.b.add(&t1);
+
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a);
+ t0.add(&self.c);
+ t0.norm();
+ t1.copy(&y.a);
+ t1.add(&y.c);
+ t1.norm();
+ t0.mul(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ t1.copy(&t0);
+ t1.neg();
+
+ self.c.copy(&z2);
+ self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+
+ z3.times_i();
+ self.a.copy(&z0);
+ self.a.add(&z3);
+ self.stype=DENSE;
+ self.norm();
+ }
+
+/* FP24 full multiplication w=w*y */
+/* Supports sparse multiplicands */
+/* Usually w is denser than y */
+ pub fn ssmul(&mut self, y: &FP24) {
+ if self.stype==ONE {
+ self.copy(&y);
+ return;
+ }
+ if y.stype==ONE {
+ return;
+ }
+ if y.stype>=SPARSE {
+ let mut z0=FP8::new_copy(&self.a);
+ let mut z1=FP8::new_int(0);
+ let mut z2=FP8::new_int(0);
+ let mut z3=FP8::new_int(0);
+ z0.mul(&y.a);
+
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+ if y.stype==SPARSE || self.stype==SPARSE {
+
+ let mut ga=FP4::new_int(0);
+ let mut gb=FP4::new_int(0);
+
+ gb.copy(&self.b.getb());
+ gb.mul(&y.b.getb());
+ ga.zero();
+ if y.stype!=SPARSE {
+ ga.copy(&self.b.getb());
+ ga.mul(&y.b.geta());
+ }
+ if self.stype!=SPARSE {
+ ga.copy(&self.b.geta());
+ ga.mul(&y.b.getb());
+ }
+ z2.set_fp4s(&ga,&gb);
+ z2.times_i();
+ } else {
+ z2.copy(&self.b);
+ z2.mul(&y.b);
+ }
+ } else {
+ z2.copy(&self.b);
+ z2.mul(&y.b);
+ }
+ let mut t0=FP8::new_copy(&self.a);
+ let mut t1=FP8::new_copy(&y.a);
+ t0.add(&self.b); t0.norm();
+ t1.add(&y.b); t1.norm();
+
+ z1.copy(&t0); z1.mul(&t1);
+ t0.copy(&self.b); t0.add(&self.c); t0.norm();
+ t1.copy(&y.b); t1.add(&y.c); t1.norm();
+
+ z3.copy(&t0); z3.mul(&t1);
+
+ t0.copy(&z0); t0.neg();
+ t1.copy(&z2); t1.neg();
+
+ z1.add(&t0);
+ self.b.copy(&z1); self.b.add(&t1);
+
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ t1.copy(&y.a); t1.add(&y.c); t1.norm();
+
+ t0.mul(&t1);
+ z2.add(&t0);
+
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE {
+ if y.stype==SPARSE || self.stype==SPARSE {
+
+ let mut ga=FP4::new_int(0);
+ let mut gb=FP4::new_int(0);
+
+ ga.copy(&self.c.geta());
+ ga.mul(&y.c.geta());
+ gb.zero();
+ if y.stype!=SPARSE {
+ gb.copy(&self.c.geta());
+ gb.mul(&y.c.getb());
+ }
+ if self.stype!=SPARSE {
+ gb.copy(&self.c.getb());
+ gb.mul(&y.c.geta());
+ }
+ t0.set_fp4s(&ga,&gb);
+ } else {
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ }
+ } else {
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ }
+ t1.copy(&t0); t1.neg();
+
+ self.c.copy(&z2); self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ } else {
+ if self.stype==SPARSER {
+ self.smul(&y);
+ return;
+ }
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE { // dense by sparser - 13m
+ let mut z0=FP8::new_copy(&self.a);
+ let mut z2=FP8::new_copy(&self.b);
+ let mut z3=FP8::new_copy(&self.b);
+ let mut t0=FP8::new_int(0);
+ let mut t1=FP8::new_copy(&y.a);
+
+ z0.mul(&y.a);
+ z2.pmul(&y.b.geta());
+ self.b.add(&self.a);
+ t1.padd(&y.b.geta());
+
+ t1.norm();
+ self.b.norm();
+ self.b.mul(&t1);
+ z3.add(&self.c);
+ z3.norm();
+ z3.pmul(&y.b.geta());
+
+ t0.copy(&z0); t0.neg();
+ t1.copy(&z2); t1.neg();
+
+ self.b.add(&t0);
+
+ self.b.add(&t1);
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ z3.norm();
+ t0.mul(&y.a);
+ self.c.copy(&z2); self.c.add(&t0);
+
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ }
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+
+ let mut z0 = FP8::new_copy(&self.a);
+ let mut z1 = FP8::new();
+ let mut z2 = FP8::new();
+ let mut z3 = FP8::new();
+ let mut t0 = FP8::new_copy(&self.a);
+ let mut t1 = FP8::new();
+
+ z0.mul(&y.a);
+ t0.add(&self.b); t0.norm();
+
+ z1.copy(&t0); z1.mul(&y.a);
+ t0.copy(&self.b); t0.add(&self.c);
+ t0.norm();
+
+ z3.copy(&t0);
+ z3.pmul(&y.c.getb());
+ z3.times_i();
+
+ t0.copy(&z0); t0.neg();
+ z1.add(&t0);
+ self.b.copy(&z1);
+ z2.copy(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ t1.copy(&y.a); t1.add(&y.c); t1.norm();
+
+ t0.mul(&t1);
+ z2.add(&t0);
+ t0.copy(&self.c);
+
+ t0.pmul(&y.c.getb());
+ t0.times_i();
+ t1.copy(&t0); t1.neg();
+
+ self.c.copy(&z2); self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ }
+ }
+ self.stype=DENSE;
+ self.norm();
+ }
+
+
+ /* Special case of multiplication arises from special form of ATE pairing line function */
+ pub fn smul(&mut self, y: &FP24) {
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE {
+ let mut w1=FP4::new_copy(&self.a.geta());
+ let mut w2=FP4::new_copy(&self.a.getb());
+ let mut w3=FP4::new_copy(&self.b.geta());
+
+ w1.mul(&y.a.geta());
+ w2.mul(&y.a.getb());
+ w3.mul(&y.b.geta());
+
+ let mut ta=FP4::new_copy(&self.a.geta());
+ let mut tb=FP4::new_copy(&y.a.geta());
+ ta.add(&self.a.getb()); ta.norm();
+ tb.add(&y.a.getb()); tb.norm();
+ let mut tc=FP4::new_copy(&ta);
+ tc.mul(&tb);
+ let mut t=FP4::new_copy(&w1);
+ t.add(&w2);
+ t.neg();
+ tc.add(&t);
+
+ ta.copy(&self.a.geta()); ta.add(&self.b.geta()); ta.norm();
+ tb.copy(&y.a.geta()); tb.add(&y.b.geta()); tb.norm();
+ let mut td=FP4::new_copy(&ta);
+ td.mul(&tb);
+ t.copy(&w1);
+ t.add(&w3);
+ t.neg();
+ td.add(&t);
+
+ ta.copy(&self.a.getb()); ta.add(&self.b.geta()); ta.norm();
+ tb.copy(&y.a.getb()); tb.add(&y.b.geta()); tb.norm();
+ let mut te=FP4::new_copy(&ta);
+ te.mul(&tb);
+ t.copy(&w2);
+ t.add(&w3);
+ t.neg();
+ te.add(&t);
+
+ w2.times_i();
+ w1.add(&w2);
+
+ self.a.set_fp4s(&w1,&tc);
+ self.b.set_fp4s(&td,&te);
+ self.c.set_fp4(&w3);
+
+ self.a.norm();
+ self.b.norm();
+ } else {
+ let mut w1=FP4::new_copy(&self.a.geta());
+ let mut w2=FP4::new_copy(&self.a.getb());
+ let mut w3=FP4::new_copy(&self.c.getb());
+
+ w1.mul(&y.a.geta());
+ w2.mul(&y.a.getb());
+ w3.mul(&y.c.getb());
+
+ let mut ta=FP4::new_copy(&self.a.geta());
+ let mut tb=FP4::new_copy(&y.a.geta());
+ ta.add(&self.a.getb()); ta.norm();
+ tb.add(&y.a.getb()); tb.norm();
+ let mut tc=FP4::new_copy(&ta);
+ tc.mul(&tb);
+ let mut t=FP4::new_copy(&w1);
+ t.add(&w2);
+ t.neg();
+ tc.add(&t);
+
+ ta.copy(&self.a.geta()); ta.add(&self.c.getb()); ta.norm();
+ tb.copy(&y.a.geta()); tb.add(&y.c.getb()); tb.norm();
+ let mut td=FP4::new_copy(&ta);
+ td.mul(&tb);
+ t.copy(&w1);
+ t.add(&w3);
+ t.neg();
+ td.add(&t);
+
+ ta.copy(&self.a.getb()); ta.add(&self.c.getb()); ta.norm();
+ tb.copy(&y.a.getb()); tb.add(&y.c.getb()); tb.norm();
+ let mut te=FP4::new_copy(&ta);
+ te.mul(&tb);
+ t.copy(&w2);
+ t.add(&w3);
+ t.neg();
+ te.add(&t);
+
+ w2.times_i();
+ w1.add(&w2);
+ self.a.set_fp4s(&w1,&tc);
+
+ w3.times_i();
+ w3.norm();
+ self.b.set_fp4h(&w3);
+
+ te.norm();
+ te.times_i();
+ self.c.set_fp4s(&te,&td);
+
+ self.a.norm();
+ self.c.norm();
+ }
+ self.stype=SPARSE;
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ let mut f0 = FP8::new_copy(&self.a);
+ let mut f1 = FP8::new_copy(&self.b);
+ let mut f2 = FP8::new_copy(&self.a);
+ let mut f3 = FP8::new();
+
+ //self.norm();
+ f0.sqr();
+ f1.mul(&self.c);
+ f1.times_i();
+ f0.sub(&f1);
+ f0.norm();
+
+ f1.copy(&self.c);
+ f1.sqr();
+ f1.times_i();
+ f2.mul(&self.b);
+ f1.sub(&f2);
+ f1.norm();
+
+ f2.copy(&self.b);
+ f2.sqr();
+ f3.copy(&self.a);
+ f3.mul(&self.c);
+ f2.sub(&f3);
+ f2.norm();
+
+ f3.copy(&self.b);
+ f3.mul(&f2);
+ f3.times_i();
+ self.a.mul(&f0);
+ f3.add(&self.a);
+ self.c.mul(&f1);
+ self.c.times_i();
+
+ f3.add(&self.c);
+ f3.norm();
+ f3.inverse();
+ self.a.copy(&f0);
+ self.a.mul(&f3);
+ self.b.copy(&f1);
+ self.b.mul(&f3);
+ self.c.copy(&f2);
+ self.c.mul(&f3);
+ self.stype=DENSE;
+ }
+
+ /* self=self^p using Frobenius */
+ pub fn frob(&mut self, f: &FP2, n: isize) {
+ let mut f2 = FP2::new_copy(f);
+ let mut f3 = FP2::new_copy(f);
+
+ f2.sqr();
+ f3.mul(&f2);
+
+ f3.mul_ip();
+ f3.norm();
+
+ for _i in 0..n {
+ self.a.frob(&f3);
+ self.b.frob(&f3);
+ self.c.frob(&f3);
+
+ self.b.qmul(f);
+ self.b.times_i2();
+ self.c.qmul(&f2);
+ self.c.times_i2();
+ self.c.times_i2();
+ }
+ self.stype=DENSE;
+ }
+
+ /* trace function */
+ pub fn trace(&mut self) -> FP8 {
+ let mut t = FP8::new();
+ t.copy(&self.a);
+ t.imul(3);
+ t.reduce();
+ return t;
+ }
+
+ /* convert from byte array to FP24 */
+ pub fn frombytes(w: &[u8]) -> FP24 {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ for i in 0..mb {
+ t[i] = w[i]
+ }
+ let mut a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + mb]
+ }
+ let mut b = BIG::frombytes(&t);
+ let mut c = FP2::new_bigs(&a, &b);
+
+ for i in 0..mb {
+ t[i] = w[i + 2 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 3 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ let mut d = FP2::new_bigs(&a, &b);
+
+ let mut ea = FP4::new_fp2s(&c, &d);
+
+ for i in 0..mb {
+ t[i] = w[i + 4 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 5 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 6 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 7 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ let mut eb = FP4::new_fp2s(&c, &d);
+
+ let e = FP8::new_fp4s(&ea, &eb);
+
+ for i in 0..mb {
+ t[i] = w[i + 8 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 9 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 10 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 11 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 12 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 13 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 14 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 15 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ let f = FP8::new_fp4s(&ea, &eb);
+
+ for i in 0..mb {
+ t[i] = w[i + 16 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 17 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 18 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 19 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 20 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 21 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 22 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 23 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ let g = FP8::new_fp4s(&ea, &eb);
+
+ return FP24::new_fp8s(&e, &f, &g);
+ }
+
+ /* convert this to byte array */
+ pub fn tobytes(&mut self, w: &mut [u8]) {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ self.a.geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i] = t[i]
+ }
+ self.a.geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + mb] = t[i]
+ }
+ self.a.geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 2 * mb] = t[i]
+ }
+ self.a.geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 3 * mb] = t[i]
+ }
+
+ self.a.getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 4 * mb] = t[i]
+ }
+ self.a.getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 5 * mb] = t[i]
+ }
+ self.a.getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 6 * mb] = t[i]
+ }
+ self.a.getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 7 * mb] = t[i]
+ }
+
+ self.b.geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 8 * mb] = t[i]
+ }
+ self.b.geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 9 * mb] = t[i]
+ }
+ self.b.geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 10 * mb] = t[i]
+ }
+ self.b.geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 11 * mb] = t[i]
+ }
+
+ self.b.getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 12 * mb] = t[i]
+ }
+ self.b.getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 13 * mb] = t[i]
+ }
+ self.b.getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 14 * mb] = t[i]
+ }
+ self.b.getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 15 * mb] = t[i]
+ }
+
+ self.c.geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 16 * mb] = t[i]
+ }
+ self.c.geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 17 * mb] = t[i]
+ }
+ self.c.geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 18 * mb] = t[i]
+ }
+ self.c.geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 19 * mb] = t[i]
+ }
+
+ self.c.getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 20 * mb] = t[i]
+ }
+ self.c.getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 21 * mb] = t[i]
+ }
+ self.c.getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 22 * mb] = t[i]
+ }
+ self.c.getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 23 * mb] = t[i]
+ }
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!(
+ "[{},{},{}]",
+ self.a.tostring(),
+ self.b.tostring(),
+ self.c.tostring()
+ );
+ }
+
+ /* self=self^e */
+ pub fn pow(&self, e: &BIG) -> FP24 {
+ let mut r = FP24::new_copy(self);
+ r.norm();
+ let mut e1 = BIG::new_copy(e);
+ e1.norm();
+ let mut e3 = BIG::new_copy(&e1);
+ e3.pmul(3);
+ e3.norm();
+ let mut w = FP24::new_copy(&r);
+
+ let nb = e3.nbits();
+ for i in (1..nb - 1).rev() {
+ w.usqr();
+ let bt = e3.bit(i) - e1.bit(i);
+ if bt == 1 {
+ w.mul(&r);
+ }
+ if bt == -1 {
+ r.conj();
+ w.mul(&r);
+ r.conj();
+ }
+ }
+
+ w.reduce();
+ return w;
+ }
+
+ /* constant time powering by small integer of max length bts */
+ pub fn pinpow(&mut self, e: i32, bts: i32) {
+ let mut r: [FP24; 2] = [FP24::new_int(1), FP24::new_copy(self)];
+ let mut t = FP24::new();
+
+ for i in (0..bts).rev() {
+ let b: usize = ((e >> i) & 1) as usize;
+ t.copy(&r[b]);
+ r[1 - b].mul(&t);
+ r[b].usqr();
+ }
+ self.copy(&r[0]);
+ }
+
+ pub fn compow(&mut self, e: &BIG, r: &BIG) -> FP8 {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::MODULUS);
+
+ let mut g1 = FP24::new_copy(self);
+ let mut g2 = FP24::new_copy(self);
+
+ let mut m = BIG::new_copy(&q);
+ m.rmod(&r);
+
+ let mut a = BIG::new_copy(&e);
+ a.rmod(&mut m);
+
+ let mut b = BIG::new_copy(&e);
+ b.div(&mut m);
+
+ let mut c = g1.trace();
+
+ if b.iszilch() {
+ c = c.xtr_pow(&mut a);
+ return c;
+ }
+
+ g2.frob(&f, 1);
+ let cp = g2.trace();
+ g1.conj();
+ g2.mul(&g1);
+ let cpm1 = g2.trace();
+ g2.mul(&g1);
+ let cpm2 = g2.trace();
+
+ c = c.xtr_pow2(&cp, &cpm1, &cpm2, &mut a, &mut b);
+
+ return c;
+ }
+
+ /* p=q0^u0.q1^u1.q2^u2.q3^u3... */
+ // Bos & Costello https://eprint.iacr.org/2013/458.pdf
+ // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
+ // Side channel attack secure
+ pub fn pow8(q: &[FP24], u: &[BIG]) -> FP24 {
+ let mut g1: [FP24; 8] = [
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ ];
+ let mut g2: [FP24; 8] = [
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ ];
+
+ let mut r = FP24::new();
+ let mut p = FP24::new();
+ const CT: usize = 1 + big::NLEN * (big::BASEBITS as usize);
+ let mut w1: [i8; CT] = [0; CT];
+ let mut s1: [i8; CT] = [0; CT];
+ let mut w2: [i8; CT] = [0; CT];
+ let mut s2: [i8; CT] = [0; CT];
+
+ let mut mt = BIG::new();
+ let mut t: [BIG; 8] = [
+ BIG::new_copy(&u[0]),
+ BIG::new_copy(&u[1]),
+ BIG::new_copy(&u[2]),
+ BIG::new_copy(&u[3]),
+ BIG::new_copy(&u[4]),
+ BIG::new_copy(&u[5]),
+ BIG::new_copy(&u[6]),
+ BIG::new_copy(&u[7]),
+ ];
+
+ for i in 0..8 {
+ t[i].norm();
+ }
+
+ // precomputation
+ g1[0].copy(&q[0]);
+ r.copy(&g1[0]);
+ g1[1].copy(&r);
+ g1[1].mul(&q[1]); // q[0].q[1]
+ g1[2].copy(&r);
+ g1[2].mul(&q[2]);
+ r.copy(&g1[1]); // q[0].q[2]
+ g1[3].copy(&r);
+ g1[3].mul(&q[2]);
+ r.copy(&g1[0]); // q[0].q[1].q[2]
+ g1[4].copy(&r);
+ g1[4].mul(&q[3]);
+ r.copy(&g1[1]); // q[0].q[3]
+ g1[5].copy(&r);
+ g1[5].mul(&q[3]);
+ r.copy(&g1[2]); // q[0].q[1].q[3]
+ g1[6].copy(&r);
+ g1[6].mul(&q[3]);
+ r.copy(&g1[3]); // q[0].q[2].q[3]
+ g1[7].copy(&r);
+ g1[7].mul(&q[3]); // q[0].q[1].q[2].q[3]
+
+ // Use Frobenius
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ for i in 0..8 {
+ g2[i].copy(&g1[i]);
+ g2[i].frob(&f, 4);
+ }
+
+ // Make it odd
+ let pb1 = 1 - t[0].parity();
+ t[0].inc(pb1);
+ t[0].norm();
+
+ let pb2 = 1 - t[4].parity();
+ t[4].inc(pb2);
+ t[4].norm();
+
+ // Number of bits
+ mt.zero();
+ for i in 0..8 {
+ mt.or(&t[i]);
+ }
+
+ let nb = 1 + mt.nbits();
+
+ // Sign pivot
+
+ s1[nb - 1] = 1;
+ s2[nb - 1] = 1;
+ for i in 0..nb - 1 {
+ t[0].fshr(1);
+ s1[i] = (2 * t[0].parity() - 1) as i8;
+ t[4].fshr(1);
+ s2[i] = (2 * t[4].parity() - 1) as i8;
+ }
+
+ // Recoded exponent
+ for i in 0..nb {
+ w1[i] = 0;
+ let mut k = 1;
+ for j in 1..4 {
+ let bt = s1[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w1[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w2[i] = 0;
+ k = 1;
+ for j in 5..8 {
+ let bt = s2[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w2[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+ }
+
+ // Main loop
+ p.selector(&g1, (2 * w1[nb - 1] + 1) as i32);
+ r.selector(&g2, (2 * w2[nb - 1] + 1) as i32);
+ p.mul(&r);
+ for i in (0..nb - 1).rev() {
+ p.usqr();
+ r.selector(&g1, (2 * w1[i] + s1[i]) as i32);
+ p.mul(&r);
+ r.selector(&g2, (2 * w2[i] + s2[i]) as i32);
+ p.mul(&r);
+ }
+
+ // apply correction
+ r.copy(&q[0]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb1);
+
+ r.copy(&q[4]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb2);
+
+ p.reduce();
+ return p;
+ }
+}
diff --git a/src/fp4.rs b/src/fp4.rs
new file mode 100644
index 0000000..1db4b73
--- /dev/null
+++ b/src/fp4.rs
@@ -0,0 +1,697 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::fp::FP;
+use super::fp2::FP2;
+use super::big::BIG;
+use std::str::SplitWhitespace;
+
+#[derive(Copy, Clone)]
+pub struct FP4 {
+ a: FP2,
+ b: FP2,
+}
+
+impl PartialEq for FP4 {
+ fn eq(&self, other: &FP4) -> bool {
+ self.equals(other)
+ }
+}
+
+impl FP4 {
+ pub fn new() -> FP4 {
+ FP4 {
+ a: FP2::new(),
+ b: FP2::new(),
+ }
+ }
+
+ pub fn new_int(a: isize) -> FP4 {
+ let mut f = FP4::new();
+ f.a.copy(&FP2::new_int(a));
+ f.b.zero();
+ return f;
+ }
+
+ pub fn new_copy(x: &FP4) -> FP4 {
+ let mut f = FP4::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ return f;
+ }
+
+ pub fn new_fp2s(c: &FP2, d: &FP2) -> FP4 {
+ let mut f = FP4::new();
+ f.a.copy(c);
+ f.b.copy(d);
+ return f;
+ }
+
+ pub fn new_fp2(c: &FP2) -> FP4 {
+ let mut f = FP4::new();
+ f.a.copy(c);
+ f.b.zero();
+ return f;
+ }
+
+ pub fn set_fp2s(&mut self,c: &FP2, d: &FP2) {
+ self.a.copy(&c);
+ self.b.copy(&d);
+ }
+
+ pub fn set_fp2(&mut self,c: &FP2) {
+ self.a.copy(&c);
+ self.b.zero();
+ }
+
+ pub fn set_fp2h(&mut self,c: &FP2) {
+ self.b.copy(&c);
+ self.a.zero();
+ }
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ }
+
+ pub fn cmove(&mut self, g: &FP4, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ return self.a.iszilch() && self.b.iszilch();
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP2::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch();
+ }
+
+ /* test is w real? That is in a+ib test b is zero */
+ pub fn isreal(&mut self) -> bool {
+ return self.b.iszilch();
+ }
+ /* extract real part a */
+ pub fn real(&self) -> FP2 {
+ let f = FP2::new_copy(&self.a);
+ return f;
+ }
+
+ pub fn geta(&self) -> FP2 {
+ return self.a;
+// let f = FP2::new_copy(&self.a);
+// return f;
+ }
+ /* extract imaginary part b */
+ pub fn getb(&self) -> FP2 {
+ return self.b;
+// let f = FP2::new_copy(&self.b);
+// return f;
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP4) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b);
+ }
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP4) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ }
+
+ /* negate self mod Modulus */
+ pub fn neg(&mut self) {
+ self.norm();
+ let mut m = FP2::new_copy(&self.a);
+ let mut t = FP2::new();
+
+ m.add(&self.b);
+ m.neg();
+ t.copy(&m);
+ t.add(&self.b);
+ self.b.copy(&m);
+ self.b.add(&self.a);
+ self.a.copy(&t);
+ self.norm();
+ }
+
+ /* set to a-ib */
+ pub fn conj(&mut self) {
+ self.b.neg();
+ self.norm();
+ }
+
+ /* self=-conjugate(self) */
+ pub fn nconj(&mut self) {
+ self.a.neg();
+ self.norm();
+ }
+
+ /* self+=a */
+ pub fn add(&mut self, x: &FP4) {
+ self.a.add(&x.a);
+ self.b.add(&x.b);
+ }
+
+ pub fn padd(&mut self, x: &FP2) {
+ self.a.add(x);
+ }
+
+ pub fn dbl(&mut self) {
+ self.a.dbl();
+ self.b.dbl();
+ }
+
+ /* self-=a */
+ pub fn sub(&mut self, x: &FP4) {
+ let mut m = FP4::new_copy(x);
+ m.neg();
+ self.add(&m);
+ }
+
+ /* self-=a */
+ pub fn rsub(&mut self, x: &FP4) {
+ self.neg();
+ self.add(x);
+ }
+
+ /* self*=s, where s is an FP2 */
+ pub fn pmul(&mut self, s: &FP2) {
+ self.a.mul(s);
+ self.b.mul(s);
+ }
+
+ /* self*=s, where s is an FP */
+ pub fn qmul(&mut self, s: &FP) {
+ self.a.pmul(s);
+ self.b.pmul(s);
+ }
+
+ /* self*=i, where i is an int */
+ pub fn imul(&mut self, c: isize) {
+ self.a.imul(c);
+ self.b.imul(c);
+ }
+
+ /* self*=self */
+
+ pub fn sqr(&mut self) {
+ let mut t1 = FP2::new_copy(&self.a);
+ let mut t2 = FP2::new_copy(&self.b);
+ let mut t3 = FP2::new_copy(&self.a);
+
+ t3.mul(&self.b);
+ t1.add(&self.b);
+ t2.mul_ip();
+
+ t2.add(&self.a);
+
+ t1.norm();
+ t2.norm();
+
+ self.a.copy(&t1);
+
+ self.a.mul(&t2);
+
+ t2.copy(&t3);
+ t2.mul_ip();
+ t2.add(&t3);
+ t2.norm();
+ t2.neg();
+ self.a.add(&t2);
+
+ t3.dbl();
+ self.b.copy(&t3);
+
+ self.norm();
+ }
+
+ /* self*=y */
+ pub fn mul(&mut self, y: &FP4) {
+ //self.norm();
+
+ let mut t1 = FP2::new_copy(&self.a);
+ let mut t2 = FP2::new_copy(&self.b);
+ let mut t3 = FP2::new();
+ let mut t4 = FP2::new_copy(&self.b);
+
+ t1.mul(&y.a);
+ t2.mul(&y.b);
+ t3.copy(&y.b);
+ t3.add(&y.a);
+ t4.add(&self.a);
+
+ t3.norm();
+ t4.norm();
+
+ t4.mul(&t3);
+
+ t3.copy(&t1);
+ t3.neg();
+ t4.add(&t3);
+ t4.norm();
+
+ t3.copy(&t2);
+ t3.neg();
+ self.b.copy(&t4);
+ self.b.add(&t3);
+
+ t2.mul_ip();
+ self.a.copy(&t2);
+ self.a.add(&t1);
+
+ self.norm();
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!("[{},{}]", self.a.tostring(), self.b.tostring());
+ }
+
+ pub fn to_hex(&self) -> String {
+ format!("{} {}", self.a.to_hex(), self.b.to_hex())
+ }
+
+ pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP4 {
+ FP4 {
+ a: FP2::from_hex_iter(iter),
+ b: FP2::from_hex_iter(iter)
+ }
+ }
+
+ pub fn from_hex(val: String) -> FP4 {
+ let mut iter = val.split_whitespace();
+ return FP4::from_hex_iter(&mut iter);
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ //self.norm();
+
+ let mut t1 = FP2::new_copy(&self.a);
+ let mut t2 = FP2::new_copy(&self.b);
+
+ t1.sqr();
+ t2.sqr();
+ t2.mul_ip();
+ t2.norm();
+ t1.sub(&t2);
+ t1.inverse();
+ self.a.mul(&t1);
+ t1.neg();
+ t1.norm();
+ self.b.mul(&t1);
+ }
+
+ /* self*=i where i = sqrt(-1+sqrt(-1)) */
+ pub fn times_i(&mut self) {
+ let mut s = FP2::new_copy(&self.b);
+ let mut t = FP2::new_copy(&self.b);
+ s.times_i();
+ t.add(&s);
+ self.b.copy(&self.a);
+ self.a.copy(&t);
+ self.norm();
+ }
+
+ /* self=self^p using Frobenius */
+ pub fn frob(&mut self, f: &FP2) {
+ self.a.conj();
+ self.b.conj();
+ self.b.mul(f);
+ }
+
+ /* self=self^e */
+ pub fn pow(&self, e: &BIG) -> FP4 {
+ let mut w = FP4::new_copy(self);
+ w.norm();
+ let mut z = BIG::new_copy(&e);
+ let mut r = FP4::new_int(1);
+ z.norm();
+ loop {
+ let bt = z.parity();
+ z.fshr(1);
+ if bt == 1 {
+ r.mul(&mut w)
+ };
+ if z.iszilch() {
+ break;
+ }
+ w.sqr();
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* XTR xtr_a function */
+ pub fn xtr_a(&mut self, w: &FP4, y: &FP4, z: &FP4) {
+ let mut r = FP4::new_copy(w);
+ let mut t = FP4::new_copy(w);
+ r.sub(y);
+ r.norm();
+ r.pmul(&self.a);
+ t.add(y);
+ t.norm();
+ t.pmul(&self.b);
+ t.times_i();
+
+ self.copy(&r);
+ self.add(&t);
+ self.add(z);
+
+ self.norm();
+ }
+
+ /* XTR xtr_d function */
+ pub fn xtr_d(&mut self) {
+ let mut w = FP4::new_copy(self);
+ self.sqr();
+ w.conj();
+ w.dbl();
+ w.norm();
+ self.sub(&w);
+ self.reduce();
+ }
+
+ /* r=x^n using XTR method on traces of FP12s */
+ pub fn xtr_pow(&self, n: &BIG) -> FP4 {
+ let mut sf = FP4::new_copy(self);
+ sf.norm();
+ let mut a = FP4::new_int(3);
+ let mut b = FP4::new_copy(&sf);
+ let mut c = FP4::new_copy(&b);
+ c.xtr_d();
+ let mut t = FP4::new();
+ let mut r = FP4::new();
+
+ let par = n.parity();
+ let mut v = BIG::new_copy(n);
+ v.norm();
+ v.fshr(1);
+ if par == 0 {
+ v.dec(1);
+ v.norm();
+ }
+
+ let nb = v.nbits();
+ for i in (0..nb).rev() {
+ if v.bit(i) != 1 {
+ t.copy(&b);
+ sf.conj();
+ c.conj();
+ b.xtr_a(&a, &sf, &c);
+ sf.conj();
+ c.copy(&t);
+ c.xtr_d();
+ a.xtr_d();
+ } else {
+ t.copy(&a);
+ t.conj();
+ a.copy(&b);
+ a.xtr_d();
+ b.xtr_a(&c, &sf, &t);
+ c.xtr_d();
+ }
+ }
+ if par == 0 {
+ r.copy(&c)
+ } else {
+ r.copy(&b)
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
+ pub fn xtr_pow2(&mut self, ck: &FP4, ckml: &FP4, ckm2l: &FP4, a: &BIG, b: &BIG) -> FP4 {
+ let mut e = BIG::new_copy(a);
+ let mut d = BIG::new_copy(b);
+ let mut w = BIG::new();
+ e.norm();
+ d.norm();
+
+ let mut cu = FP4::new_copy(ck); // can probably be passed in w/o copying
+ let mut cv = FP4::new_copy(self);
+ let mut cumv = FP4::new_copy(ckml);
+ let mut cum2v = FP4::new_copy(ckm2l);
+ let mut r = FP4::new();
+ let mut t = FP4::new();
+
+ let mut f2: usize = 0;
+ while d.parity() == 0 && e.parity() == 0 {
+ d.fshr(1);
+ e.fshr(1);
+ f2 += 1;
+ }
+
+ while BIG::comp(&d, &e) != 0 {
+ if BIG::comp(&d, &e) > 0 {
+ w.copy(&e);
+ w.imul(4);
+ w.norm();
+ if BIG::comp(&d, &w) <= 0 {
+ w.copy(&d);
+ d.copy(&e);
+ e.rsub(&w);
+ e.norm();
+
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cum2v.copy(&cumv);
+ cum2v.conj();
+ cumv.copy(&cv);
+ cv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if d.parity() == 0 {
+ d.fshr(1);
+ r.copy(&cum2v);
+ r.conj();
+ t.copy(&cumv);
+ t.xtr_a(&cu, &cv, &r);
+ cum2v.copy(&cumv);
+ cum2v.xtr_d();
+ cumv.copy(&t);
+ cu.xtr_d();
+ } else {
+ if e.parity() == 1 {
+ d.sub(&e);
+ d.norm();
+ d.fshr(1);
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cu.xtr_d();
+ cum2v.copy(&cv);
+ cum2v.xtr_d();
+ cum2v.conj();
+ cv.copy(&t);
+ } else {
+ w.copy(&d);
+ d.copy(&e);
+ d.fshr(1);
+ e.copy(&w);
+ t.copy(&cumv);
+ t.xtr_d();
+ cumv.copy(&cum2v);
+ cumv.conj();
+ cum2v.copy(&t);
+ cum2v.conj();
+ t.copy(&cv);
+ t.xtr_d();
+ cv.copy(&cu);
+ cu.copy(&t);
+ }
+ }
+ }
+ }
+ if BIG::comp(&d, &e) < 0 {
+ w.copy(&d);
+ w.imul(4);
+ w.norm();
+ if BIG::comp(&e, &w) <= 0 {
+ e.sub(&d);
+ e.norm();
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cum2v.copy(&cumv);
+ cumv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if e.parity() == 0 {
+ w.copy(&d);
+ d.copy(&e);
+ d.fshr(1);
+ e.copy(&w);
+ t.copy(&cumv);
+ t.xtr_d();
+ cumv.copy(&cum2v);
+ cumv.conj();
+ cum2v.copy(&t);
+ cum2v.conj();
+ t.copy(&cv);
+ t.xtr_d();
+ cv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if d.parity() == 1 {
+ w.copy(&e);
+ e.copy(&d);
+ w.sub(&d);
+ w.norm();
+ d.copy(&w);
+ d.fshr(1);
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cumv.conj();
+ cum2v.copy(&cu);
+ cum2v.xtr_d();
+ cum2v.conj();
+ cu.copy(&cv);
+ cu.xtr_d();
+ cv.copy(&t);
+ } else {
+ d.fshr(1);
+ r.copy(&cum2v);
+ r.conj();
+ t.copy(&cumv);
+ t.xtr_a(&cu, &cv, &r);
+ cum2v.copy(&cumv);
+ cum2v.xtr_d();
+ cumv.copy(&t);
+ cu.xtr_d();
+ }
+ }
+ }
+ }
+ }
+ r.copy(&cv);
+ r.xtr_a(&cu, &cumv, &cum2v);
+ for _ in 0..f2 {
+ r.xtr_d()
+ }
+ r = r.xtr_pow(&mut d);
+ return r;
+ }
+
+ /* this/=2 */
+ pub fn div2(&mut self) {
+ self.a.div2();
+ self.b.div2();
+ }
+
+ pub fn div_i(&mut self) {
+ let mut u = FP2::new_copy(&self.a);
+ let v = FP2::new_copy(&self.b);
+ u.div_ip();
+ self.a.copy(&v);
+ self.b.copy(&u);
+ }
+
+ pub fn div_2i(&mut self) {
+ let mut u = FP2::new_copy(&self.a);
+ let mut v = FP2::new_copy(&self.b);
+ u.div_ip2();
+ v.dbl();
+ v.norm();
+ self.a.copy(&v);
+ self.b.copy(&u);
+ }
+
+ /* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */
+ /* returns true if this is QR */
+ pub fn sqrt(&mut self) -> bool {
+ if self.iszilch() {
+ return true;
+ }
+
+ let mut a = FP2::new_copy(&self.a);
+ let mut s = FP2::new_copy(&self.b);
+ let mut t = FP2::new_copy(&self.a);
+
+ if s.iszilch() {
+ if t.sqrt() {
+ self.a.copy(&t);
+ self.b.zero();
+ } else {
+ t.div_ip();
+ t.sqrt();
+ self.b.copy(&t);
+ self.a.zero();
+ }
+ return true;
+ }
+ s.sqr();
+ a.sqr();
+ s.mul_ip();
+ s.norm();
+ a.sub(&s);
+
+ s.copy(&a);
+ if !s.sqrt() {
+ return false;
+ }
+
+ a.copy(&t);
+ a.add(&s);
+ a.norm();
+ a.div2();
+
+ if !a.sqrt() {
+ a.copy(&t);
+ a.sub(&s);
+ a.norm();
+ a.div2();
+ if !a.sqrt() {
+ return false;
+ }
+ }
+ t.copy(&self.b);
+ s.copy(&a);
+ s.add(&a);
+ s.inverse();
+
+ t.mul(&s);
+ self.a.copy(&a);
+ self.b.copy(&t);
+
+ return true;
+ }
+}
diff --git a/src/fp48.rs b/src/fp48.rs
new file mode 100644
index 0000000..c72ee4c
--- /dev/null
+++ b/src/fp48.rs
@@ -0,0 +1,1610 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::big;
+use super::ecp;
+use super::fp2::FP2;
+use super::fp4::FP4;
+use super::fp8::FP8;
+use super::fp16::FP16;
+use super::big::BIG;
+use super::rom;
+use types::SexticTwist;
+//use std::str::SplitWhitespace;
+
+pub const ZERO: usize=0;
+pub const ONE: usize=1;
+pub const SPARSER: usize=2;
+pub const SPARSE: usize=3;
+pub const DENSE: usize=4;
+
+#[derive(Copy, Clone)]
+pub struct FP48 {
+ a: FP16,
+ b: FP16,
+ c: FP16,
+ stype: usize,
+}
+
+impl FP48 {
+ pub fn new() -> FP48 {
+ FP48 {
+ a: FP16::new(),
+ b: FP16::new(),
+ c: FP16::new(),
+ stype: ZERO,
+ }
+ }
+
+ pub fn settype(&mut self,t: usize) {
+ self.stype = t;
+ }
+
+ pub fn gettype(&self) -> usize {
+ return self.stype;
+ }
+
+ pub fn new_int(a: isize) -> FP48 {
+ let mut f = FP48::new();
+ f.a.copy(&FP16::new_int(a));
+ f.b.zero();
+ f.c.zero();
+ if a == 1 {
+ f.stype=ONE;
+ } else {
+ f.stype=SPARSER;
+ }
+ return f;
+ }
+
+ pub fn new_copy(x: &FP48) -> FP48 {
+ let mut f = FP48::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ f.c.copy(&x.c);
+ f.stype=x.stype;
+ return f;
+ }
+
+ pub fn new_fp16s(d: &FP16, e: &FP16, f: &FP16) -> FP48 {
+ let mut g = FP48::new();
+ g.a.copy(d);
+ g.b.copy(e);
+ g.c.copy(f);
+ g.stype=DENSE;
+ return g;
+ }
+
+ pub fn new_fp16(d: &FP16) -> FP48 {
+ let mut g = FP48::new();
+ g.a.copy(d);
+ g.b.zero();
+ g.c.zero();
+ g.stype=SPARSER;
+ return g;
+ }
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ self.c.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ self.c.norm();
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ return self.a.iszilch() && self.b.iszilch() && self.c.iszilch();
+ }
+
+ /* Conditional move of g to self dependant on d */
+ pub fn cmove(&mut self, g: &FP48, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ self.c.cmove(&g.c, d);
+ let mut u=d as usize;
+ u=!(u-1);
+ self.stype^=(self.stype^g.stype)&u;
+ }
+
+ /* return 1 if b==c, no branching */
+ fn teq(b: i32, c: i32) -> isize {
+ let mut x = b ^ c;
+ x -= 1; // if x=0, x now -1
+ return ((x >> 31) & 1) as isize;
+ }
+
+ /* Constant time select from pre-computed table */
+ pub fn selector(&mut self, g: &[FP48], b: i32) {
+ let m = b >> 31;
+ let mut babs = (b ^ m) - m;
+
+ babs = (babs - 1) / 2;
+
+ self.cmove(&g[0], FP48::teq(babs, 0)); // conditional move
+ self.cmove(&g[1], FP48::teq(babs, 1));
+ self.cmove(&g[2], FP48::teq(babs, 2));
+ self.cmove(&g[3], FP48::teq(babs, 3));
+ self.cmove(&g[4], FP48::teq(babs, 4));
+ self.cmove(&g[5], FP48::teq(babs, 5));
+ self.cmove(&g[6], FP48::teq(babs, 6));
+ self.cmove(&g[7], FP48::teq(babs, 7));
+
+ let mut invf = FP48::new_copy(self);
+ invf.conj();
+ self.cmove(&invf, (m & 1) as isize);
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP16::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch() && self.c.iszilch();
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP48) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b) && self.c.equals(&x.c);
+ }
+
+ pub fn geta(&mut self) -> FP16 {
+ return self.a;
+// let f = FP16::new_copy(&self.a);
+// return f;
+ }
+
+ pub fn getb(&mut self) -> FP16 {
+ return self.b;
+// let f = FP16::new_copy(&self.b);
+// return f;
+ }
+
+ pub fn getc(&mut self) -> FP16 {
+ return self.c;
+// let f = FP16::new_copy(&self.c);
+// return f;
+ }
+
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP48) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ self.c.copy(&x.c);
+ self.stype=x.stype;
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ self.c.zero();
+ self.stype=ONE;
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ self.c.zero();
+ self.stype=ZERO;
+ }
+
+ /* this=conj(this) */
+ pub fn conj(&mut self) {
+ self.a.conj();
+ self.b.nconj();
+ self.c.conj();
+ }
+
+ /* Granger-Scott Unitary Squaring */
+ pub fn usqr(&mut self) {
+ let mut a = FP16::new_copy(&self.a);
+ let mut b = FP16::new_copy(&self.c);
+ let mut c = FP16::new_copy(&self.b);
+ let mut d = FP16::new();
+
+ self.a.sqr();
+ d.copy(&self.a);
+ d.add(&self.a);
+ self.a.add(&d);
+
+ self.a.norm();
+ a.nconj();
+
+ a.dbl();
+ self.a.add(&a);
+ b.sqr();
+ b.times_i();
+
+ d.copy(&b);
+ d.add(&b);
+ b.add(&d);
+ b.norm();
+
+ c.sqr();
+ d.copy(&c);
+ d.add(&c);
+ c.add(&d);
+ c.norm();
+
+ self.b.conj();
+ self.b.dbl();
+ self.c.nconj();
+
+ self.c.dbl();
+ self.b.add(&b);
+ self.c.add(&c);
+ self.stype=DENSE;
+ self.reduce();
+ }
+
+ /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
+ pub fn sqr(&mut self) {
+ if self.stype==ONE {
+ return;
+ }
+ let mut a = FP16::new_copy(&self.a);
+ let mut b = FP16::new_copy(&self.b);
+ let mut c = FP16::new_copy(&self.c);
+ let mut d = FP16::new_copy(&self.a);
+
+ a.sqr();
+ b.mul(&self.c);
+ b.dbl();
+ b.norm();
+ c.sqr();
+ d.mul(&self.b);
+ d.dbl();
+
+ self.c.add(&self.a);
+ self.c.add(&self.b);
+ self.c.norm();
+ self.c.sqr();
+
+ self.a.copy(&a);
+ a.add(&b);
+ a.norm();
+ a.add(&c);
+ a.add(&d);
+ a.norm();
+
+ a.neg();
+ b.times_i();
+ c.times_i();
+
+ self.a.add(&b);
+
+ self.b.copy(&c);
+ self.b.add(&d);
+ self.c.add(&a);
+ if self.stype==SPARSER {
+ self.stype=SPARSE;
+ } else {
+ self.stype=DENSE;
+ }
+ self.norm();
+ }
+
+ /* FP48 full multiplication self=self*y */
+ pub fn mul(&mut self, y: &FP48) {
+ let mut z0 = FP16::new_copy(&self.a);
+ let mut z1 = FP16::new();
+ let mut z2 = FP16::new_copy(&mut self.b);
+ let mut z3 = FP16::new();
+ let mut t0 = FP16::new_copy(&self.a);
+ let mut t1 = FP16::new_copy(&y.a);
+
+ z0.mul(&y.a);
+ z2.mul(&y.b);
+
+ t0.add(&self.b);
+ t1.add(&y.b);
+
+ t0.norm();
+ t1.norm();
+
+ z1.copy(&t0);
+ z1.mul(&t1);
+ t0.copy(&self.b);
+ t0.add(&self.c);
+ t1.copy(&y.b);
+ t1.add(&y.c);
+
+ t0.norm();
+ t1.norm();
+
+ z3.copy(&t0);
+ z3.mul(&t1);
+
+ t0.copy(&z0);
+ t0.neg();
+ t1.copy(&z2);
+ t1.neg();
+
+ z1.add(&t0);
+ self.b.copy(&z1);
+ self.b.add(&t1);
+
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a);
+ t0.add(&self.c);
+ t0.norm();
+ t1.copy(&y.a);
+ t1.add(&y.c);
+ t1.norm();
+ t0.mul(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ t1.copy(&t0);
+ t1.neg();
+
+ self.c.copy(&z2);
+ self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+
+ z3.times_i();
+ self.a.copy(&z0);
+ self.a.add(&z3);
+ self.stype=DENSE;
+ self.norm();
+ }
+
+/* FP48 full multiplication w=w*y */
+/* Supports sparse multiplicands */
+/* Usually w is denser than y */
+ pub fn ssmul(&mut self, y: &FP48) {
+ if self.stype==ONE {
+ self.copy(&y);
+ return;
+ }
+ if y.stype==ONE {
+ return;
+ }
+ if y.stype>=SPARSE {
+ let mut z0=FP16::new_copy(&self.a);
+ let mut z1=FP16::new_int(0);
+ let mut z2=FP16::new_int(0);
+ let mut z3=FP16::new_int(0);
+ z0.mul(&y.a);
+
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+ if y.stype==SPARSE || self.stype==SPARSE {
+
+ let mut ga=FP8::new_int(0);
+ let mut gb=FP8::new_int(0);
+
+ gb.copy(&self.b.getb());
+ gb.mul(&y.b.getb());
+ ga.zero();
+ if y.stype!=SPARSE {
+ ga.copy(&self.b.getb());
+ ga.mul(&y.b.geta());
+ }
+ if self.stype!=SPARSE {
+ ga.copy(&self.b.geta());
+ ga.mul(&y.b.getb());
+ }
+ z2.set_fp8s(&ga,&gb);
+ z2.times_i();
+ } else {
+ z2.copy(&self.b);
+ z2.mul(&y.b);
+ }
+ } else {
+ z2.copy(&self.b);
+ z2.mul(&y.b);
+ }
+ let mut t0=FP16::new_copy(&self.a);
+ let mut t1=FP16::new_copy(&y.a);
+ t0.add(&self.b); t0.norm();
+ t1.add(&y.b); t1.norm();
+
+ z1.copy(&t0); z1.mul(&t1);
+ t0.copy(&self.b); t0.add(&self.c); t0.norm();
+ t1.copy(&y.b); t1.add(&y.c); t1.norm();
+
+ z3.copy(&t0); z3.mul(&t1);
+
+ t0.copy(&z0); t0.neg();
+ t1.copy(&z2); t1.neg();
+
+ z1.add(&t0);
+ self.b.copy(&z1); self.b.add(&t1);
+
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ t1.copy(&y.a); t1.add(&y.c); t1.norm();
+
+ t0.mul(&t1);
+ z2.add(&t0);
+
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE {
+ if y.stype==SPARSE || self.stype==SPARSE {
+
+ let mut ga=FP8::new_int(0);
+ let mut gb=FP8::new_int(0);
+
+ ga.copy(&self.c.geta());
+ ga.mul(&y.c.geta());
+ gb.zero();
+ if y.stype!=SPARSE {
+ gb.copy(&self.c.geta());
+ gb.mul(&y.c.getb());
+ }
+ if self.stype!=SPARSE {
+ gb.copy(&self.c.getb());
+ gb.mul(&y.c.geta());
+ }
+ t0.set_fp8s(&ga,&gb);
+ } else {
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ }
+ } else {
+ t0.copy(&self.c);
+ t0.mul(&y.c);
+ }
+ t1.copy(&t0); t1.neg();
+
+ self.c.copy(&z2); self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ } else {
+ if self.stype==SPARSER {
+ self.smul(&y);
+ return;
+ }
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE { // dense by sparser - 13m
+ let mut z0=FP16::new_copy(&self.a);
+ let mut z2=FP16::new_copy(&self.b);
+ let mut z3=FP16::new_copy(&self.b);
+ let mut t0=FP16::new_int(0);
+ let mut t1=FP16::new_copy(&y.a);
+
+ z0.mul(&y.a);
+ z2.pmul(&y.b.geta());
+ self.b.add(&self.a);
+ t1.padd(&y.b.geta());
+
+ t1.norm();
+ self.b.norm();
+ self.b.mul(&t1);
+ z3.add(&self.c);
+ z3.norm();
+ z3.pmul(&y.b.geta());
+
+ t0.copy(&z0); t0.neg();
+ t1.copy(&z2); t1.neg();
+
+ self.b.add(&t0);
+
+ self.b.add(&t1);
+ z3.add(&t1);
+ z2.add(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ z3.norm();
+ t0.mul(&y.a);
+ self.c.copy(&z2); self.c.add(&t0);
+
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ }
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+
+ let mut z0 = FP16::new_copy(&self.a);
+ let mut z1 = FP16::new();
+ let mut z2 = FP16::new();
+ let mut z3 = FP16::new();
+ let mut t0 = FP16::new_copy(&self.a);
+ let mut t1 = FP16::new();
+
+ z0.mul(&y.a);
+ t0.add(&self.b); t0.norm();
+
+ z1.copy(&t0); z1.mul(&y.a);
+ t0.copy(&self.b); t0.add(&self.c);
+ t0.norm();
+
+ z3.copy(&t0);
+ z3.pmul(&y.c.getb());
+ z3.times_i();
+
+ t0.copy(&z0); t0.neg();
+ z1.add(&t0);
+ self.b.copy(&z1);
+ z2.copy(&t0);
+
+ t0.copy(&self.a); t0.add(&self.c); t0.norm();
+ t1.copy(&y.a); t1.add(&y.c); t1.norm();
+
+ t0.mul(&t1);
+ z2.add(&t0);
+ t0.copy(&self.c);
+
+ t0.pmul(&y.c.getb());
+ t0.times_i();
+ t1.copy(&t0); t1.neg();
+
+ self.c.copy(&z2); self.c.add(&t1);
+ z3.add(&t1);
+ t0.times_i();
+ self.b.add(&t0);
+ z3.norm();
+ z3.times_i();
+ self.a.copy(&z0); self.a.add(&z3);
+ }
+ }
+ self.stype=DENSE;
+ self.norm();
+ }
+
+
+ /* Special case of multiplication arises from special form of ATE pairing line function */
+ pub fn smul(&mut self, y: &FP48) {
+ if ecp::SEXTIC_TWIST==SexticTwist::D_TYPE {
+ let mut w1=FP8::new_copy(&self.a.geta());
+ let mut w2=FP8::new_copy(&self.a.getb());
+ let mut w3=FP8::new_copy(&self.b.geta());
+
+ w1.mul(&y.a.geta());
+ w2.mul(&y.a.getb());
+ w3.mul(&y.b.geta());
+
+ let mut ta=FP8::new_copy(&self.a.geta());
+ let mut tb=FP8::new_copy(&y.a.geta());
+ ta.add(&self.a.getb()); ta.norm();
+ tb.add(&y.a.getb()); tb.norm();
+ let mut tc=FP8::new_copy(&ta);
+ tc.mul(&tb);
+ let mut t=FP8::new_copy(&w1);
+ t.add(&w2);
+ t.neg();
+ tc.add(&t);
+
+ ta.copy(&self.a.geta()); ta.add(&self.b.geta()); ta.norm();
+ tb.copy(&y.a.geta()); tb.add(&y.b.geta()); tb.norm();
+ let mut td=FP8::new_copy(&ta);
+ td.mul(&tb);
+ t.copy(&w1);
+ t.add(&w3);
+ t.neg();
+ td.add(&t);
+
+ ta.copy(&self.a.getb()); ta.add(&self.b.geta()); ta.norm();
+ tb.copy(&y.a.getb()); tb.add(&y.b.geta()); tb.norm();
+ let mut te=FP8::new_copy(&ta);
+ te.mul(&tb);
+ t.copy(&w2);
+ t.add(&w3);
+ t.neg();
+ te.add(&t);
+
+ w2.times_i();
+ w1.add(&w2);
+
+ self.a.set_fp8s(&w1,&tc);
+ self.b.set_fp8s(&td,&te);
+ self.c.set_fp8(&w3);
+
+ self.a.norm();
+ self.b.norm();
+ } else {
+ let mut w1=FP8::new_copy(&self.a.geta());
+ let mut w2=FP8::new_copy(&self.a.getb());
+ let mut w3=FP8::new_copy(&self.c.getb());
+
+ w1.mul(&y.a.geta());
+ w2.mul(&y.a.getb());
+ w3.mul(&y.c.getb());
+
+ let mut ta=FP8::new_copy(&self.a.geta());
+ let mut tb=FP8::new_copy(&y.a.geta());
+ ta.add(&self.a.getb()); ta.norm();
+ tb.add(&y.a.getb()); tb.norm();
+ let mut tc=FP8::new_copy(&ta);
+ tc.mul(&tb);
+ let mut t=FP8::new_copy(&w1);
+ t.add(&w2);
+ t.neg();
+ tc.add(&t);
+
+ ta.copy(&self.a.geta()); ta.add(&self.c.getb()); ta.norm();
+ tb.copy(&y.a.geta()); tb.add(&y.c.getb()); tb.norm();
+ let mut td=FP8::new_copy(&ta);
+ td.mul(&tb);
+ t.copy(&w1);
+ t.add(&w3);
+ t.neg();
+ td.add(&t);
+
+ ta.copy(&self.a.getb()); ta.add(&self.c.getb()); ta.norm();
+ tb.copy(&y.a.getb()); tb.add(&y.c.getb()); tb.norm();
+ let mut te=FP8::new_copy(&ta);
+ te.mul(&tb);
+ t.copy(&w2);
+ t.add(&w3);
+ t.neg();
+ te.add(&t);
+
+ w2.times_i();
+ w1.add(&w2);
+ self.a.set_fp8s(&w1,&tc);
+
+ w3.times_i();
+ w3.norm();
+ self.b.set_fp8h(&w3);
+
+ te.norm();
+ te.times_i();
+ self.c.set_fp8s(&te,&td);
+
+ self.a.norm();
+ self.c.norm();
+ }
+ self.stype=SPARSE;
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ let mut f0 = FP16::new_copy(&self.a);
+ let mut f1 = FP16::new_copy(&self.b);
+ let mut f2 = FP16::new_copy(&self.a);
+ let mut f3 = FP16::new();
+
+ //self.norm();
+ f0.sqr();
+ f1.mul(&self.c);
+ f1.times_i();
+ f0.sub(&f1);
+ f0.norm();
+
+ f1.copy(&self.c);
+ f1.sqr();
+ f1.times_i();
+ f2.mul(&self.b);
+ f1.sub(&f2);
+ f1.norm();
+
+ f2.copy(&self.b);
+ f2.sqr();
+ f3.copy(&self.a);
+ f3.mul(&self.c);
+ f2.sub(&f3);
+ f2.norm();
+
+ f3.copy(&self.b);
+ f3.mul(&f2);
+ f3.times_i();
+ self.a.mul(&f0);
+ f3.add(&self.a);
+ self.c.mul(&f1);
+ self.c.times_i();
+
+ f3.add(&self.c);
+ f3.norm();
+ f3.inverse();
+ self.a.copy(&f0);
+ self.a.mul(&f3);
+ self.b.copy(&f1);
+ self.b.mul(&f3);
+ self.c.copy(&f2);
+ self.c.mul(&f3);
+ self.stype=DENSE;
+ }
+
+ /* self=self^p using Frobenius */
+ pub fn frob(&mut self, f: &FP2, n: isize) {
+ let mut f2 = FP2::new_copy(f);
+ let mut f3 = FP2::new_copy(f);
+
+ f2.sqr();
+ f3.mul(&f2);
+
+ f3.mul_ip();
+ f3.norm();
+ f3.mul_ip();
+ f3.norm();
+
+ for _i in 0..n {
+ self.a.frob(&f3);
+ self.b.frob(&f3);
+ self.c.frob(&f3);
+
+ self.b.qmul(f);
+ self.b.times_i4();
+ self.b.times_i2();
+ self.c.qmul(&f2);
+ self.c.times_i4();
+ self.c.times_i4();
+ self.c.times_i4();
+ }
+ self.stype=DENSE;
+ }
+
+ /* trace function */
+ pub fn trace(&mut self) -> FP16 {
+ let mut t = FP16::new();
+ t.copy(&self.a);
+ t.imul(3);
+ t.reduce();
+ return t;
+ }
+
+ /* convert from byte array to FP48 */
+ pub fn frombytes(w: &[u8]) -> FP48 {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ for i in 0..mb {
+ t[i] = w[i]
+ }
+ let mut a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + mb]
+ }
+ let mut b = BIG::frombytes(&t);
+ let mut c = FP2::new_bigs(&a, &b);
+
+ for i in 0..mb {
+ t[i] = w[i + 2 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 3 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ let mut d = FP2::new_bigs(&a, &b);
+
+ let mut ea = FP4::new_fp2s(&c, &d);
+
+ for i in 0..mb {
+ t[i] = w[i + 4 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 5 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 6 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 7 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ let mut eb = FP4::new_fp2s(&c, &d);
+
+ let mut ea8 = FP8::new_fp4s(&ea, &eb);
+
+ for i in 0..mb {
+ t[i] = w[i + 8 * mb]
+ }
+ let mut a = BIG::frombytes(&t);
+ for i in 0..mb {
+ t[i] = w[i + 9 * mb]
+ }
+ let mut b = BIG::frombytes(&t);
+ let mut c = FP2::new_bigs(&a, &b);
+
+ for i in 0..mb {
+ t[i] = w[i + 10 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 11 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ let mut d = FP2::new_bigs(&a, &b);
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 12 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 13 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 14 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 15 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ let mut eb8 = FP8::new_fp4s(&ea, &eb);
+
+ let e = FP16::new_fp8s(&ea8, &eb8);
+
+ for i in 0..mb {
+ t[i] = w[i + 16 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 17 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 18 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 19 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 20 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 21 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 22 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 23 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ ea8.copy(&FP8::new_fp4s(&ea, &eb));
+
+ for i in 0..mb {
+ t[i] = w[i + 24 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 25 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 26 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 27 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 28 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 29 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 30 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 31 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ eb8.copy(&FP8::new_fp4s(&ea, &eb));
+
+ let f = FP16::new_fp8s(&ea8, &eb8);
+
+ for i in 0..mb {
+ t[i] = w[i + 32 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 33 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 34 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 35 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 36 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 37 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 38 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 39 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ ea8.copy(&FP8::new_fp4s(&ea, &eb));
+
+ for i in 0..mb {
+ t[i] = w[i + 40 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 41 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 42 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 43 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ ea.copy(&FP4::new_fp2s(&c, &d));
+
+ for i in 0..mb {
+ t[i] = w[i + 44 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 45 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+
+ c.copy(&FP2::new_bigs(&a, &b));
+
+ for i in 0..mb {
+ t[i] = w[i + 46 * mb]
+ }
+ a.copy(&BIG::frombytes(&t));
+ for i in 0..mb {
+ t[i] = w[i + 47 * mb]
+ }
+ b.copy(&BIG::frombytes(&t));
+ d.copy(&FP2::new_bigs(&a, &b));
+
+ eb.copy(&FP4::new_fp2s(&c, &d));
+
+ eb8.copy(&FP8::new_fp4s(&ea, &eb));
+
+ let g = FP16::new_fp8s(&ea8, &eb8);
+
+ return FP48::new_fp16s(&e, &f, &g);
+ }
+
+ /* convert this to byte array */
+ pub fn tobytes(&mut self, w: &mut [u8]) {
+ let mut t: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
+ let mb = big::MODBYTES as usize;
+
+ self.a.geta().geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i] = t[i]
+ }
+ self.a.geta().geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + mb] = t[i]
+ }
+ self.a.geta().geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 2 * mb] = t[i]
+ }
+ self.a.geta().geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 3 * mb] = t[i]
+ }
+
+ self.a.geta().getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 4 * mb] = t[i]
+ }
+ self.a.geta().getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 5 * mb] = t[i]
+ }
+ self.a.geta().getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 6 * mb] = t[i]
+ }
+ self.a.geta().getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 7 * mb] = t[i]
+ }
+
+ self.a.getb().geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 8 * mb] = t[i]
+ }
+ self.a.getb().geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 9 * mb] = t[i]
+ }
+ self.a.getb().geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 10 * mb] = t[i]
+ }
+ self.a.getb().geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 11 * mb] = t[i]
+ }
+
+ self.a.getb().getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 12 * mb] = t[i]
+ }
+ self.a.getb().getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 13 * mb] = t[i]
+ }
+ self.a.getb().getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 14 * mb] = t[i]
+ }
+ self.a.getb().getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 15 * mb] = t[i]
+ }
+
+ self.b.geta().geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 16 * mb] = t[i]
+ }
+ self.b.geta().geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 17 * mb] = t[i]
+ }
+ self.b.geta().geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 18 * mb] = t[i]
+ }
+ self.b.geta().geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 19 * mb] = t[i]
+ }
+
+ self.b.geta().getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 20 * mb] = t[i]
+ }
+ self.b.geta().getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 21 * mb] = t[i]
+ }
+ self.b.geta().getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 22 * mb] = t[i]
+ }
+ self.b.geta().getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 23 * mb] = t[i]
+ }
+
+ self.b.getb().geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 24 * mb] = t[i]
+ }
+ self.b.getb().geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 25 * mb] = t[i]
+ }
+ self.b.getb().geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 26 * mb] = t[i]
+ }
+ self.b.getb().geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 27 * mb] = t[i]
+ }
+
+ self.b.getb().getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 28 * mb] = t[i]
+ }
+ self.b.getb().getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 29 * mb] = t[i]
+ }
+ self.b.getb().getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 30 * mb] = t[i]
+ }
+ self.b.getb().getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 31 * mb] = t[i]
+ }
+
+ self.c.geta().geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 32 * mb] = t[i]
+ }
+ self.c.geta().geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 33 * mb] = t[i]
+ }
+ self.c.geta().geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 34 * mb] = t[i]
+ }
+ self.c.geta().geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 35 * mb] = t[i]
+ }
+
+ self.c.geta().getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 36 * mb] = t[i]
+ }
+ self.c.geta().getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 37 * mb] = t[i]
+ }
+ self.c.geta().getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 38 * mb] = t[i]
+ }
+ self.c.geta().getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 39 * mb] = t[i]
+ }
+
+ self.c.getb().geta().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 40 * mb] = t[i]
+ }
+ self.c.getb().geta().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 41 * mb] = t[i]
+ }
+ self.c.getb().geta().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 42 * mb] = t[i]
+ }
+ self.c.getb().geta().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 43 * mb] = t[i]
+ }
+
+ self.c.getb().getb().geta().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 44 * mb] = t[i]
+ }
+ self.c.getb().getb().geta().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 45 * mb] = t[i]
+ }
+ self.c.getb().getb().getb().geta().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 46 * mb] = t[i]
+ }
+ self.c.getb().getb().getb().getb().tobytes(&mut t);
+ for i in 0..mb {
+ w[i + 47 * mb] = t[i]
+ }
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!(
+ "[{},{},{}]",
+ self.a.tostring(),
+ self.b.tostring(),
+ self.c.tostring()
+ );
+ }
+
+ /* self=self^e */
+ pub fn pow(&self, e: &BIG) -> FP48 {
+ let mut r = FP48::new_copy(self);
+ r.norm();
+ let mut e1 = BIG::new_copy(e);
+ e1.norm();
+ let mut e3 = BIG::new_copy(&e1);
+ e3.pmul(3);
+ e3.norm();
+ let mut w = FP48::new_copy(&r);
+
+ let nb = e3.nbits();
+ for i in (1..nb - 1).rev() {
+ w.usqr();
+ let bt = e3.bit(i) - e1.bit(i);
+ if bt == 1 {
+ w.mul(&r);
+ }
+ if bt == -1 {
+ r.conj();
+ w.mul(&r);
+ r.conj();
+ }
+ }
+
+ w.reduce();
+ return w;
+ }
+
+ /* constant time powering by small integer of max length bts */
+ pub fn pinpow(&mut self, e: i32, bts: i32) {
+ let mut r: [FP48; 2] = [FP48::new_int(1), FP48::new_copy(self)];
+ let mut t = FP48::new();
+
+ for i in (0..bts).rev() {
+ let b: usize = ((e >> i) & 1) as usize;
+ t.copy(&r[b]);
+ r[1 - b].mul(&t);
+ r[b].usqr();
+ }
+ self.copy(&r[0]);
+ }
+
+ pub fn compow(&mut self, e: &BIG, r: &BIG) -> FP16 {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::MODULUS);
+
+ let mut g1 = FP48::new_copy(self);
+ let mut g2 = FP48::new_copy(self);
+
+ let mut m = BIG::new_copy(&q);
+ m.rmod(&r);
+
+ let mut a = BIG::new_copy(&e);
+ a.rmod(&mut m);
+
+ let mut b = BIG::new_copy(&e);
+ b.div(&mut m);
+
+ let mut c = g1.trace();
+
+ if b.iszilch() {
+ c = c.xtr_pow(&mut a);
+ return c;
+ }
+
+ g2.frob(&f, 1);
+ let cp = g2.trace();
+ g1.conj();
+ g2.mul(&g1);
+ let cpm1 = g2.trace();
+ g2.mul(&g1);
+ let cpm2 = g2.trace();
+
+ c = c.xtr_pow2(&cp, &cpm1, &cpm2, &mut a, &mut b);
+
+ return c;
+ }
+
+ /* p=q0^u0.q1^u1.q2^u2.q3^u3... */
+ // Bos & Costello https://eprint.iacr.org/2013/458.pdf
+ // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
+ // Side channel attack secure
+ pub fn pow16(q: &[FP48], u: &[BIG]) -> FP48 {
+ let mut g1: [FP48; 8] = [
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ ];
+ let mut g2: [FP48; 8] = [
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ ];
+ let mut g3: [FP48; 8] = [
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ ];
+ let mut g4: [FP48; 8] = [
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ ];
+
+ let mut r = FP48::new();
+ let mut p = FP48::new();
+ const CT: usize = 1 + big::NLEN * (big::BASEBITS as usize);
+ let mut w1: [i8; CT] = [0; CT];
+ let mut s1: [i8; CT] = [0; CT];
+ let mut w2: [i8; CT] = [0; CT];
+ let mut s2: [i8; CT] = [0; CT];
+ let mut w3: [i8; CT] = [0; CT];
+ let mut s3: [i8; CT] = [0; CT];
+ let mut w4: [i8; CT] = [0; CT];
+ let mut s4: [i8; CT] = [0; CT];
+
+ let mut mt = BIG::new();
+ let mut t: [BIG; 16] = [
+ BIG::new_copy(&u[0]),
+ BIG::new_copy(&u[1]),
+ BIG::new_copy(&u[2]),
+ BIG::new_copy(&u[3]),
+ BIG::new_copy(&u[4]),
+ BIG::new_copy(&u[5]),
+ BIG::new_copy(&u[6]),
+ BIG::new_copy(&u[7]),
+ BIG::new_copy(&u[8]),
+ BIG::new_copy(&u[9]),
+ BIG::new_copy(&u[10]),
+ BIG::new_copy(&u[11]),
+ BIG::new_copy(&u[12]),
+ BIG::new_copy(&u[13]),
+ BIG::new_copy(&u[14]),
+ BIG::new_copy(&u[15]),
+ ];
+
+ for i in 0..16 {
+ t[i].norm();
+ }
+
+ // precomputation
+ g1[0].copy(&q[0]);
+ r.copy(&g1[0]);
+ g1[1].copy(&r);
+ g1[1].mul(&q[1]); // q[0].q[1]
+ g1[2].copy(&r);
+ g1[2].mul(&q[2]);
+ r.copy(&g1[1]); // q[0].q[2]
+ g1[3].copy(&r);
+ g1[3].mul(&q[2]);
+ r.copy(&g1[0]); // q[0].q[1].q[2]
+ g1[4].copy(&r);
+ g1[4].mul(&q[3]);
+ r.copy(&g1[1]); // q[0].q[3]
+ g1[5].copy(&r);
+ g1[5].mul(&q[3]);
+ r.copy(&g1[2]); // q[0].q[1].q[3]
+ g1[6].copy(&r);
+ g1[6].mul(&q[3]);
+ r.copy(&g1[3]); // q[0].q[2].q[3]
+ g1[7].copy(&r);
+ g1[7].mul(&q[3]); // q[0].q[1].q[2].q[3]
+
+ // Use Frobenius
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ for i in 0..8 {
+ g2[i].copy(&g1[i]);
+ g2[i].frob(&f, 4);
+ g3[i].copy(&g2[i]);
+ g3[i].frob(&f, 4);
+ g4[i].copy(&g3[i]);
+ g4[i].frob(&f, 4);
+ }
+
+ // Make it odd
+ let pb1 = 1 - t[0].parity();
+ t[0].inc(pb1);
+ t[0].norm();
+
+ let pb2 = 1 - t[4].parity();
+ t[4].inc(pb2);
+ t[4].norm();
+
+ let pb3 = 1 - t[8].parity();
+ t[8].inc(pb3);
+ t[8].norm();
+
+ let pb4 = 1 - t[12].parity();
+ t[12].inc(pb4);
+ t[12].norm();
+
+ // Number of bits
+ mt.zero();
+ for i in 0..16 {
+ mt.or(&t[i]);
+ }
+
+ let nb = 1 + mt.nbits();
+
+ // Sign pivot
+
+ s1[nb - 1] = 1;
+ s2[nb - 1] = 1;
+ s3[nb - 1] = 1;
+ s4[nb - 1] = 1;
+ for i in 0..nb - 1 {
+ t[0].fshr(1);
+ s1[i] = (2 * t[0].parity() - 1) as i8;
+ t[4].fshr(1);
+ s2[i] = (2 * t[4].parity() - 1) as i8;
+ t[8].fshr(1);
+ s3[i] = (2 * t[8].parity() - 1) as i8;
+ t[12].fshr(1);
+ s4[i] = (2 * t[12].parity() - 1) as i8;
+ }
+
+ // Recoded exponent
+ for i in 0..nb {
+ w1[i] = 0;
+ let mut k = 1;
+ for j in 1..4 {
+ let bt = s1[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w1[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w2[i] = 0;
+ k = 1;
+ for j in 5..8 {
+ let bt = s2[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w2[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w3[i] = 0;
+ k = 1;
+ for j in 9..12 {
+ let bt = s3[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w3[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+
+ w4[i] = 0;
+ k = 1;
+ for j in 13..16 {
+ let bt = s4[i] * (t[j].parity() as i8);
+ t[j].fshr(1);
+ t[j].dec((bt >> 1) as isize);
+ t[j].norm();
+ w4[i] += bt * (k as i8);
+ k = 2 * k;
+ }
+ }
+
+ // Main loop
+ p.selector(&g1, (2 * w1[nb - 1] + 1) as i32);
+ r.selector(&g2, (2 * w2[nb - 1] + 1) as i32);
+ p.mul(&r);
+ r.selector(&g3, (2 * w3[nb - 1] + 1) as i32);
+ p.mul(&r);
+ r.selector(&g4, (2 * w4[nb - 1] + 1) as i32);
+ p.mul(&r);
+ for i in (0..nb - 1).rev() {
+ p.usqr();
+ r.selector(&g1, (2 * w1[i] + s1[i]) as i32);
+ p.mul(&r);
+ r.selector(&g2, (2 * w2[i] + s2[i]) as i32);
+ p.mul(&r);
+ r.selector(&g3, (2 * w3[i] + s3[i]) as i32);
+ p.mul(&r);
+ r.selector(&g4, (2 * w4[i] + s4[i]) as i32);
+ p.mul(&r);
+ }
+
+ // apply correction
+ r.copy(&q[0]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb1);
+
+ r.copy(&q[4]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb2);
+
+ r.copy(&q[8]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb3);
+
+ r.copy(&q[12]);
+ r.conj();
+ r.mul(&p);
+ p.cmove(&r, pb4);
+
+ p.reduce();
+ return p;
+ }
+}
diff --git a/src/fp8.rs b/src/fp8.rs
new file mode 100644
index 0000000..dfc84d1
--- /dev/null
+++ b/src/fp8.rs
@@ -0,0 +1,701 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::fp::FP;
+use super::fp2::FP2;
+use super::fp4::FP4;
+use super::big::BIG;
+//use std::str::SplitWhitespace;
+
+#[derive(Copy, Clone)]
+pub struct FP8 {
+ a: FP4,
+ b: FP4,
+}
+
+impl FP8 {
+ pub fn new() -> FP8 {
+ FP8 {
+ a: FP4::new(),
+ b: FP4::new(),
+ }
+ }
+
+ pub fn new_int(a: isize) -> FP8 {
+ let mut f = FP8::new();
+ f.a.copy(&FP4::new_int(a));
+ f.b.zero();
+ return f;
+ }
+
+ pub fn new_copy(x: &FP8) -> FP8 {
+ let mut f = FP8::new();
+ f.a.copy(&x.a);
+ f.b.copy(&x.b);
+ return f;
+ }
+
+ pub fn new_fp4s(c: &FP4, d: &FP4) -> FP8 {
+ let mut f = FP8::new();
+ f.a.copy(c);
+ f.b.copy(d);
+ return f;
+ }
+
+ pub fn new_fp4(c: &FP4) -> FP8 {
+ let mut f = FP8::new();
+ f.a.copy(c);
+ f.b.zero();
+ return f;
+ }
+
+ pub fn set_fp4s(&mut self,c: &FP4, d: &FP4) {
+ self.a.copy(&c);
+ self.b.copy(&d);
+ }
+
+ pub fn set_fp4(&mut self,c: &FP4) {
+ self.a.copy(&c);
+ self.b.zero();
+ }
+
+ pub fn set_fp4h(&mut self,c: &FP4) {
+ self.b.copy(&c);
+ self.a.zero();
+ }
+
+
+ /* reduce components mod Modulus */
+ pub fn reduce(&mut self) {
+ self.a.reduce();
+ self.b.reduce();
+ }
+
+ /* normalise components of w */
+ pub fn norm(&mut self) {
+ self.a.norm();
+ self.b.norm();
+ }
+
+ pub fn cmove(&mut self, g: &FP8, d: isize) {
+ self.a.cmove(&g.a, d);
+ self.b.cmove(&g.b, d);
+ }
+
+ /* test self=0 ? */
+ pub fn iszilch(&self) -> bool {
+ return self.a.iszilch() && self.b.iszilch();
+ }
+
+ /* test self=1 ? */
+ pub fn isunity(&self) -> bool {
+ let one = FP4::new_int(1);
+ return self.a.equals(&one) && self.b.iszilch();
+ }
+
+ /* test is w real? That is in a+ib test b is zero */
+ pub fn isreal(&mut self) -> bool {
+ return self.b.iszilch();
+ }
+ /* extract real part a */
+ pub fn real(&self) -> FP4 {
+ let f = FP4::new_copy(&self.a);
+ return f;
+ }
+
+ pub fn geta(&self) -> FP4 {
+ return self.a;
+// let f = FP4::new_copy(&self.a);
+// return f;
+ }
+ /* extract imaginary part b */
+ pub fn getb(&self) -> FP4 {
+ return self.b;
+// let f = FP4::new_copy(&self.b);
+// return f;
+ }
+
+ /* test self=x */
+ pub fn equals(&self, x: &FP8) -> bool {
+ return self.a.equals(&x.a) && self.b.equals(&x.b);
+ }
+ /* copy self=x */
+ pub fn copy(&mut self, x: &FP8) {
+ self.a.copy(&x.a);
+ self.b.copy(&x.b);
+ }
+
+ /* set self=0 */
+ pub fn zero(&mut self) {
+ self.a.zero();
+ self.b.zero();
+ }
+
+ /* set self=1 */
+ pub fn one(&mut self) {
+ self.a.one();
+ self.b.zero();
+ }
+
+ /* negate self mod Modulus */
+ pub fn neg(&mut self) {
+ self.norm();
+ let mut m = FP4::new_copy(&self.a);
+ let mut t = FP4::new();
+
+ m.add(&self.b);
+ m.neg();
+
+ t.copy(&m);
+ t.add(&self.b);
+ self.b.copy(&m);
+ self.b.add(&self.a);
+ self.a.copy(&t);
+ self.norm();
+ }
+
+ /* set to a-ib */
+ pub fn conj(&mut self) {
+ self.b.neg();
+ self.norm();
+ }
+
+ /* self=-conjugate(self) */
+ pub fn nconj(&mut self) {
+ self.a.neg();
+ self.norm();
+ }
+
+ /* self+=a */
+ pub fn add(&mut self, x: &FP8) {
+ self.a.add(&x.a);
+ self.b.add(&x.b);
+ }
+
+ pub fn padd(&mut self, x: &FP4) {
+ self.a.add(x);
+ }
+
+ pub fn dbl(&mut self) {
+ self.a.dbl();
+ self.b.dbl();
+ }
+
+ /* self-=a */
+ pub fn sub(&mut self, x: &FP8) {
+ let mut m = FP8::new_copy(x);
+ m.neg();
+ self.add(&m);
+ }
+
+ /* this-=x */
+ pub fn rsub(&mut self, x: &FP8) {
+ self.neg();
+ self.add(x);
+ }
+
+ /* self*=s, where s is an FP4 */
+ pub fn pmul(&mut self, s: &FP4) {
+ self.a.mul(s);
+ self.b.mul(s);
+ }
+
+ /* self*=s, where s is an FP2 */
+ pub fn qmul(&mut self, s: &FP2) {
+ self.a.pmul(s);
+ self.b.pmul(s);
+ }
+
+ /* self*=s, where s is an FP */
+ pub fn tmul(&mut self, s: &FP) {
+ self.a.qmul(s);
+ self.b.qmul(s);
+ }
+
+ /* self*=i, where i is an int */
+ pub fn imul(&mut self, c: isize) {
+ self.a.imul(c);
+ self.b.imul(c);
+ }
+
+ /* self*=self */
+
+ pub fn sqr(&mut self) {
+ let mut t1 = FP4::new_copy(&self.a);
+ let mut t2 = FP4::new_copy(&self.b);
+ let mut t3 = FP4::new_copy(&self.a);
+
+ t3.mul(&self.b);
+ t1.add(&self.b);
+ t2.times_i();
+
+ t2.add(&self.a);
+
+ t1.norm();
+ t2.norm();
+
+ self.a.copy(&t1);
+
+ self.a.mul(&t2);
+
+ t2.copy(&t3);
+ t2.times_i();
+ t2.add(&t3);
+ t2.norm();
+ t2.neg();
+ self.a.add(&t2);
+
+ t3.dbl();
+ self.b.copy(&t3);
+
+ self.norm();
+ }
+
+ /* self*=y */
+ pub fn mul(&mut self, y: &FP8) {
+ //self.norm();
+
+ let mut t1 = FP4::new_copy(&self.a);
+ let mut t2 = FP4::new_copy(&self.b);
+ let mut t3 = FP4::new();
+ let mut t4 = FP4::new_copy(&self.b);
+
+ t1.mul(&y.a);
+ t2.mul(&y.b);
+ t3.copy(&y.b);
+ t3.add(&y.a);
+ t4.add(&self.a);
+
+ t3.norm();
+ t4.norm();
+
+ t4.mul(&t3);
+
+ t3.copy(&t1);
+ t3.neg();
+ t4.add(&t3);
+ t4.norm();
+
+ t3.copy(&t2);
+ t3.neg();
+ self.b.copy(&t4);
+ self.b.add(&t3);
+
+ t2.times_i();
+ self.a.copy(&t2);
+ self.a.add(&t1);
+
+ self.norm();
+ }
+
+ /* output to hex string */
+ pub fn tostring(&mut self) -> String {
+ return format!("[{},{}]", self.a.tostring(), self.b.tostring());
+ }
+
+ /* self=1/self */
+ pub fn inverse(&mut self) {
+ //self.norm();
+
+ let mut t1 = FP4::new_copy(&self.a);
+ let mut t2 = FP4::new_copy(&self.b);
+
+ t1.sqr();
+ t2.sqr();
+ t2.times_i();
+ t2.norm();
+ t1.sub(&t2);
+ t1.norm();
+ t1.inverse();
+ self.a.mul(&t1);
+ t1.neg();
+ t1.norm();
+ self.b.mul(&t1);
+ }
+
+ /* self*=i where i = sqrt(-1+sqrt(-1)) */
+ pub fn times_i(&mut self) {
+ let mut s = FP4::new_copy(&self.b);
+ let t = FP4::new_copy(&self.a);
+ s.times_i();
+ self.a.copy(&s);
+ self.b.copy(&t);
+
+ self.norm();
+ }
+
+ pub fn times_i2(&mut self) {
+ self.a.times_i();
+ self.b.times_i();
+ }
+
+ /* self=self^p using Frobenius */
+ pub fn frob(&mut self, f: &FP2) {
+ let mut ff = FP2::new_copy(f);
+ ff.sqr();
+ ff.mul_ip();
+ ff.norm();
+ self.a.frob(&ff);
+ self.b.frob(&ff);
+ self.b.pmul(f);
+ self.b.times_i();
+ }
+
+ /* self=self^e */
+ pub fn pow(&self, e: &BIG) -> FP8 {
+ let mut w = FP8::new_copy(self);
+ w.norm();
+ let mut z = BIG::new_copy(&e);
+ let mut r = FP8::new_int(1);
+ z.norm();
+ loop {
+ let bt = z.parity();
+ z.fshr(1);
+ if bt == 1 {
+ r.mul(&mut w)
+ };
+ if z.iszilch() {
+ break;
+ }
+ w.sqr();
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* XTR xtr_a function */
+ pub fn xtr_a(&mut self, w: &FP8, y: &FP8, z: &FP8) {
+ let mut r = FP8::new_copy(w);
+ let mut t = FP8::new_copy(w);
+
+ r.sub(y);
+ r.norm();
+ r.pmul(&self.a);
+ t.add(y);
+ t.norm();
+ t.pmul(&self.b);
+ t.times_i();
+
+ self.copy(&r);
+ self.add(&t);
+ self.add(z);
+
+ self.norm();
+ }
+
+ /* XTR xtr_d function */
+ pub fn xtr_d(&mut self) {
+ let mut w = FP8::new_copy(self);
+ self.sqr();
+ w.conj();
+ w.dbl();
+ w.norm();
+ self.sub(&w);
+ self.reduce();
+ }
+
+ /* r=x^n using XTR method on traces of FP24s */
+ pub fn xtr_pow(&self, n: &BIG) -> FP8 {
+ let mut sf = FP8::new_copy(self);
+ sf.norm();
+ let mut a = FP8::new_int(3);
+ let mut b = FP8::new_copy(&sf);
+ let mut c = FP8::new_copy(&b);
+ c.xtr_d();
+ let mut t = FP8::new();
+ let mut r = FP8::new();
+
+ let par = n.parity();
+ let mut v = BIG::new_copy(n);
+ v.norm();
+ v.fshr(1);
+ if par == 0 {
+ v.dec(1);
+ v.norm();
+ }
+
+ let nb = v.nbits();
+ for i in (0..nb).rev() {
+ if v.bit(i) != 1 {
+ t.copy(&b);
+ sf.conj();
+ c.conj();
+ b.xtr_a(&a, &sf, &c);
+ sf.conj();
+ c.copy(&t);
+ c.xtr_d();
+ a.xtr_d();
+ } else {
+ t.copy(&a);
+ t.conj();
+ a.copy(&b);
+ a.xtr_d();
+ b.xtr_a(&c, &sf, &t);
+ c.xtr_d();
+ }
+ }
+ if par == 0 {
+ r.copy(&c)
+ } else {
+ r.copy(&b)
+ }
+ r.reduce();
+ return r;
+ }
+
+ /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
+ pub fn xtr_pow2(&mut self, ck: &FP8, ckml: &FP8, ckm2l: &FP8, a: &BIG, b: &BIG) -> FP8 {
+ let mut e = BIG::new_copy(a);
+ let mut d = BIG::new_copy(b);
+ let mut w = BIG::new();
+ e.norm();
+ d.norm();
+
+ let mut cu = FP8::new_copy(ck); // can probably be passed in w/o copying
+ let mut cv = FP8::new_copy(self);
+ let mut cumv = FP8::new_copy(ckml);
+ let mut cum2v = FP8::new_copy(ckm2l);
+ let mut r = FP8::new();
+ let mut t = FP8::new();
+
+ let mut f2: usize = 0;
+ while d.parity() == 0 && e.parity() == 0 {
+ d.fshr(1);
+ e.fshr(1);
+ f2 += 1;
+ }
+
+ while BIG::comp(&d, &e) != 0 {
+ if BIG::comp(&d, &e) > 0 {
+ w.copy(&e);
+ w.imul(4);
+ w.norm();
+ if BIG::comp(&d, &w) <= 0 {
+ w.copy(&d);
+ d.copy(&e);
+ e.rsub(&w);
+ e.norm();
+
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cum2v.copy(&cumv);
+ cum2v.conj();
+ cumv.copy(&cv);
+ cv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if d.parity() == 0 {
+ d.fshr(1);
+ r.copy(&cum2v);
+ r.conj();
+ t.copy(&cumv);
+ t.xtr_a(&cu, &cv, &r);
+ cum2v.copy(&cumv);
+ cum2v.xtr_d();
+ cumv.copy(&t);
+ cu.xtr_d();
+ } else {
+ if e.parity() == 1 {
+ d.sub(&e);
+ d.norm();
+ d.fshr(1);
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cu.xtr_d();
+ cum2v.copy(&cv);
+ cum2v.xtr_d();
+ cum2v.conj();
+ cv.copy(&t);
+ } else {
+ w.copy(&d);
+ d.copy(&e);
+ d.fshr(1);
+ e.copy(&w);
+ t.copy(&cumv);
+ t.xtr_d();
+ cumv.copy(&cum2v);
+ cumv.conj();
+ cum2v.copy(&t);
+ cum2v.conj();
+ t.copy(&cv);
+ t.xtr_d();
+ cv.copy(&cu);
+ cu.copy(&t);
+ }
+ }
+ }
+ }
+ if BIG::comp(&d, &e) < 0 {
+ w.copy(&d);
+ w.imul(4);
+ w.norm();
+ if BIG::comp(&e, &w) <= 0 {
+ e.sub(&d);
+ e.norm();
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cum2v.copy(&cumv);
+ cumv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if e.parity() == 0 {
+ w.copy(&d);
+ d.copy(&e);
+ d.fshr(1);
+ e.copy(&w);
+ t.copy(&cumv);
+ t.xtr_d();
+ cumv.copy(&cum2v);
+ cumv.conj();
+ cum2v.copy(&t);
+ cum2v.conj();
+ t.copy(&cv);
+ t.xtr_d();
+ cv.copy(&cu);
+ cu.copy(&t);
+ } else {
+ if d.parity() == 1 {
+ w.copy(&e);
+ e.copy(&d);
+ w.sub(&d);
+ w.norm();
+ d.copy(&w);
+ d.fshr(1);
+ t.copy(&cv);
+ t.xtr_a(&cu, &cumv, &cum2v);
+ cumv.conj();
+ cum2v.copy(&cu);
+ cum2v.xtr_d();
+ cum2v.conj();
+ cu.copy(&cv);
+ cu.xtr_d();
+ cv.copy(&t);
+ } else {
+ d.fshr(1);
+ r.copy(&cum2v);
+ r.conj();
+ t.copy(&cumv);
+ t.xtr_a(&cu, &cv, &r);
+ cum2v.copy(&cumv);
+ cum2v.xtr_d();
+ cumv.copy(&t);
+ cu.xtr_d();
+ }
+ }
+ }
+ }
+ }
+ r.copy(&cv);
+ r.xtr_a(&cu, &cumv, &cum2v);
+ for _ in 0..f2 {
+ r.xtr_d()
+ }
+ r = r.xtr_pow(&mut d);
+ return r;
+ }
+
+ /* this/=2 */
+ pub fn div2(&mut self) {
+ self.a.div2();
+ self.b.div2();
+ }
+
+ pub fn div_i(&mut self) {
+ let mut u = FP4::new_copy(&self.a);
+ let v = FP4::new_copy(&self.b);
+ u.div_i();
+ self.a.copy(&v);
+ self.b.copy(&u);
+ }
+
+ pub fn div_i2(&mut self) {
+ self.a.div_i();
+ self.b.div_i();
+ }
+
+ pub fn div_2i(&mut self) {
+ let mut u = FP4::new_copy(&self.a);
+ let mut v = FP4::new_copy(&self.b);
+ u.div_2i();
+ v.dbl();
+ v.norm();
+ self.a.copy(&v);
+ self.b.copy(&u);
+ }
+
+ /* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */
+ /* returns true if this is QR */
+ pub fn sqrt(&mut self) -> bool {
+ if self.iszilch() {
+ return true;
+ }
+
+ let mut a = FP4::new_copy(&self.a);
+ let mut s = FP4::new_copy(&self.b);
+ let mut t = FP4::new_copy(&self.a);
+
+ if s.iszilch() {
+ if t.sqrt() {
+ self.a.copy(&t);
+ self.b.zero();
+ } else {
+ t.div_i();
+ t.sqrt();
+ self.b.copy(&t);
+ self.a.zero();
+ }
+ return true;
+ }
+ s.sqr();
+ a.sqr();
+ s.times_i();
+ s.norm();
+ a.sub(&s);
+
+ s.copy(&a);
+ if !s.sqrt() {
+ return false;
+ }
+
+ a.copy(&t);
+ a.add(&s);
+ a.norm();
+ a.div2();
+
+ if !a.sqrt() {
+ a.copy(&t);
+ a.sub(&s);
+ a.norm();
+ a.div2();
+ if !a.sqrt() {
+ return false;
+ }
+ }
+ t.copy(&self.b);
+ s.copy(&a);
+ s.add(&a);
+ s.inverse();
+
+ t.mul(&s);
+ self.a.copy(&a);
+ self.b.copy(&t);
+
+ return true;
+ }
+}
diff --git a/src/gcm.rs b/src/gcm.rs
new file mode 100644
index 0000000..b2c293f
--- /dev/null
+++ b/src/gcm.rs
@@ -0,0 +1,481 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+const GCM_NB: usize = 4;
+const GCM_ACCEPTING_HEADER: usize = 0;
+const GCM_ACCEPTING_CIPHER: usize = 1;
+const GCM_NOT_ACCEPTING_MORE: usize = 2;
+const GCM_FINISHED: usize = 3;
+const GCM_ENCRYPTING: usize = 0;
+const GCM_DECRYPTING: usize = 1;
+
+use crate::aes;
+use crate::aes::AES;
+
+pub struct GCM {
+ table: [[u32; 4]; 128],
+ statex: [u8; 16],
+ y_0: [u8; 16],
+ // counter: usize,
+ lena: [u32; 2],
+ lenc: [u32; 2],
+ status: usize,
+ a: AES,
+}
+
+impl GCM {
+ fn pack(b: [u8; 4]) -> u32 {
+ /* pack bytes into a 32-bit Word */
+ return ((((b[0]) & 0xff) as u32) << 24)
+ | ((((b[1]) & 0xff) as u32) << 16)
+ | ((((b[2]) & 0xff) as u32) << 8)
+ | (((b[3]) & 0xff) as u32);
+ }
+
+ fn unpack(a: u32) -> [u8; 4] {
+ /* unpack bytes from a word */
+ let b: [u8; 4] = [
+ ((a >> 24) & 0xff) as u8,
+ ((a >> 16) & 0xff) as u8,
+ ((a >> 8) & 0xff) as u8,
+ (a & 0xff) as u8,
+ ];
+ return b;
+ }
+
+ fn precompute(&mut self, h: &[u8]) {
+ let mut b: [u8; 4] = [0; 4];
+ let mut j = 0;
+ for i in 0..GCM_NB {
+ b[0] = h[j];
+ b[1] = h[j + 1];
+ b[2] = h[j + 2];
+ b[3] = h[j + 3];
+ self.table[0][i] = GCM::pack(b);
+ j += 4;
+ }
+ for i in 1..128 {
+ let mut c: u32 = 0;
+ for j in 0..GCM_NB {
+ self.table[i][j] = c | (self.table[i - 1][j]) >> 1;
+ c = self.table[i - 1][j] << 31;
+ }
+ if c != 0 {
+ self.table[i][0] ^= 0xE1000000
+ } /* irreducible polynomial */
+ }
+ }
+
+ fn gf2mul(&mut self) {
+ /* gf2m mul - Z=H*X mod 2^128 */
+ let mut p: [u32; 4] = [0; 4];
+
+ for i in 0..4 {
+ p[i] = 0
+ }
+ let mut j: usize = 8;
+ let mut m = 0;
+ for i in 0..128 {
+ j -= 1;
+ let mut c = ((self.statex[m] >> j) & 1) as u32;
+ c = (!c) + 1;
+ for k in 0..GCM_NB {
+ p[k] ^= self.table[i][k] & c
+ }
+ if j == 0 {
+ j = 8;
+ m += 1;
+ if m == 16 {
+ break;
+ }
+ }
+ }
+ j = 0;
+ for i in 0..GCM_NB {
+ let b = GCM::unpack(p[i]);
+ self.statex[j] = b[0];
+ self.statex[j + 1] = b[1];
+ self.statex[j + 2] = b[2];
+ self.statex[j + 3] = b[3];
+ j += 4;
+ }
+ }
+
+ fn wrap(&mut self) {
+ /* Finish off GHASH */
+ let mut f: [u32; 4] = [0; 4];
+ let mut el: [u8; 16] = [0; 16];
+
+ /* convert lengths from bytes to bits */
+ f[0] = (self.lena[0] << 3) | (self.lena[1] & 0xE0000000) >> 29;
+ f[1] = self.lena[1] << 3;
+ f[2] = (self.lenc[0] << 3) | (self.lenc[1] & 0xE0000000) >> 29;
+ f[3] = self.lenc[1] << 3;
+ let mut j = 0;
+ for i in 0..GCM_NB {
+ let b = GCM::unpack(f[i]);
+ el[j] = b[0];
+ el[j + 1] = b[1];
+ el[j + 2] = b[2];
+ el[j + 3] = b[3];
+ j += 4;
+ }
+ for i in 0..16 {
+ self.statex[i] ^= el[i]
+ }
+ self.gf2mul();
+ }
+
+ fn ghash(&mut self, plain: &[u8], len: usize) -> bool {
+ if self.status == GCM_ACCEPTING_HEADER {
+ self.status = GCM_ACCEPTING_CIPHER
+ }
+ if self.status != GCM_ACCEPTING_CIPHER {
+ return false;
+ }
+
+ let mut j = 0;
+ while j < len {
+ for i in 0..16 {
+ if j >= len {
+ break;
+ }
+ self.statex[i] ^= plain[j];
+ j += 1;
+ self.lenc[1] += 1;
+ if self.lenc[1] == 0 {
+ self.lenc[0] += 1
+ }
+ }
+ self.gf2mul();
+ }
+ if len % 16 != 0 {
+ self.status = GCM_NOT_ACCEPTING_MORE
+ }
+ return true;
+ }
+
+ /* Initialize GCM mode */
+ pub fn init(&mut self, nk: usize, key: &[u8], niv: usize, iv: &[u8]) {
+ /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */
+ let mut h: [u8; 16] = [0; 16];
+
+ for i in 0..16 {
+ h[i] = 0;
+ self.statex[i] = 0
+ }
+
+ self.a = AES::new();
+
+ self.a.init(aes::ECB, nk, key, None);
+ self.a.ecb_encrypt(&mut h); /* E(K,0) */
+ self.precompute(&h);
+
+ self.lena[0] = 0;
+ self.lenc[0] = 0;
+ self.lena[1] = 0;
+ self.lenc[1] = 0;
+ if niv == 12 {
+ for i in 0..12 {
+ self.a.f[i] = iv[i]
+ }
+ let b = GCM::unpack(1);
+ self.a.f[12] = b[0];
+ self.a.f[13] = b[1];
+ self.a.f[14] = b[2];
+ self.a.f[15] = b[3]; /* initialise IV */
+ for i in 0..16 {
+ self.y_0[i] = self.a.f[i]
+ }
+ } else {
+ self.status = GCM_ACCEPTING_CIPHER;
+ self.ghash(iv, niv); /* GHASH(H,0,IV) */
+ self.wrap();
+ for i in 0..16 {
+ self.a.f[i] = self.statex[i];
+ self.y_0[i] = self.a.f[i];
+ self.statex[i] = 0
+ }
+ self.lena[0] = 0;
+ self.lenc[0] = 0;
+ self.lena[1] = 0;
+ self.lenc[1] = 0;
+ }
+ self.status = GCM_ACCEPTING_HEADER;
+ }
+
+ pub fn new() -> GCM {
+ GCM {
+ table: [[0; 4]; 128],
+ statex: [0; 16],
+ y_0: [0; 16],
+ //counter:0,
+ lena: [0; 2],
+ lenc: [0; 2],
+ status: 0,
+ a: AES::new(),
+ }
+ }
+
+ /* Add Header data - included but not encrypted */
+ pub fn add_header(&mut self, header: &[u8], len: usize) -> bool {
+ /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */
+ if self.status != GCM_ACCEPTING_HEADER {
+ return false;
+ }
+ let mut j = 0;
+ while j < len {
+ for i in 0..16 {
+ if j >= len {
+ break;
+ }
+ self.statex[i] ^= header[j];
+ j += 1;
+ self.lena[1] += 1;
+ if self.lena[1] == 0 {
+ self.lena[0] += 1
+ }
+ }
+ self.gf2mul();
+ }
+ if len % 16 != 0 {
+ self.status = GCM_ACCEPTING_CIPHER
+ }
+ return true;
+ }
+
+ /* Add Plaintext - included and encrypted */
+ pub fn add_plain(&mut self, cipher: &mut [u8], plain: &[u8], len: usize) -> bool {
+ let mut cb: [u8; 16] = [0; 16];
+ let mut b: [u8; 4] = [0; 4];
+
+ let mut counter: u32;
+ if self.status == GCM_ACCEPTING_HEADER {
+ self.status = GCM_ACCEPTING_CIPHER
+ }
+ if self.status != GCM_ACCEPTING_CIPHER {
+ return false;
+ }
+
+ let mut j = 0;
+ while j < len {
+ b[0] = self.a.f[12];
+ b[1] = self.a.f[13];
+ b[2] = self.a.f[14];
+ b[3] = self.a.f[15];
+ counter = GCM::pack(b);
+ counter += 1;
+ b = GCM::unpack(counter);
+ self.a.f[12] = b[0];
+ self.a.f[13] = b[1];
+ self.a.f[14] = b[2];
+ self.a.f[15] = b[3]; /* increment counter */
+ for i in 0..16 {
+ cb[i] = self.a.f[i]
+ }
+ self.a.ecb_encrypt(&mut cb); /* encrypt it */
+
+ for i in 0..16 {
+ if j >= len {
+ break;
+ }
+ cipher[j] = plain[j] ^ cb[i];
+ self.statex[i] ^= cipher[j];
+ j += 1;
+ self.lenc[1] += 1;
+ if self.lenc[1] == 0 {
+ self.lenc[0] += 1
+ }
+ }
+ self.gf2mul()
+ }
+ if len % 16 != 0 {
+ self.status = GCM_NOT_ACCEPTING_MORE
+ }
+ return true;
+ }
+
+ /* Add Ciphertext - decrypts to plaintext */
+ pub fn add_cipher(&mut self, plain: &mut [u8], cipher: &[u8], len: usize) -> bool {
+ let mut cb: [u8; 16] = [0; 16];
+ let mut b: [u8; 4] = [0; 4];
+
+ let mut counter: u32;
+
+ if self.status == GCM_ACCEPTING_HEADER {
+ self.status = GCM_ACCEPTING_CIPHER
+ }
+ if self.status != GCM_ACCEPTING_CIPHER {
+ return false;
+ }
+
+ let mut j = 0;
+ while j < len {
+ b[0] = self.a.f[12];
+ b[1] = self.a.f[13];
+ b[2] = self.a.f[14];
+ b[3] = self.a.f[15];
+ counter = GCM::pack(b);
+ counter += 1;
+ b = GCM::unpack(counter);
+ self.a.f[12] = b[0];
+ self.a.f[13] = b[1];
+ self.a.f[14] = b[2];
+ self.a.f[15] = b[3]; /* increment counter */
+ for i in 0..16 {
+ cb[i] = self.a.f[i]
+ }
+ self.a.ecb_encrypt(&mut cb); /* encrypt it */
+ for i in 0..16 {
+ if j >= len {
+ break;
+ }
+ let oc = cipher[j];
+ plain[j] = cipher[j] ^ cb[i];
+ self.statex[i] ^= oc;
+ j += 1;
+ self.lenc[1] += 1;
+ if self.lenc[1] == 0 {
+ self.lenc[0] += 1
+ }
+ }
+ self.gf2mul()
+ }
+ if len % 16 != 0 {
+ self.status = GCM_NOT_ACCEPTING_MORE
+ }
+ return true;
+ }
+
+ /* Finish and extract Tag */
+ pub fn finish(&mut self, extract: bool) -> [u8; 16] {
+ /* Finish off GHASH and extract tag (MAC) */
+ let mut tag: [u8; 16] = [0; 16];
+
+ self.wrap();
+ /* extract tag */
+ if extract {
+ self.a.ecb_encrypt(&mut (self.y_0)); /* E(K,Y0) */
+ for i in 0..16 {
+ self.y_0[i] ^= self.statex[i]
+ }
+ for i in 0..16 {
+ tag[i] = self.y_0[i];
+ self.y_0[i] = 0;
+ self.statex[i] = 0
+ }
+ }
+ self.status = GCM_FINISHED;
+ self.a.end();
+ return tag;
+ }
+
+ pub fn hex2bytes(hex: &[u8], bin: &mut [u8]) {
+ let len = hex.len();
+
+ for i in 0..len / 2 {
+ let mut v: u8;
+ let mut c = hex[2 * i];
+ if c >= b'0' && c <= b'9' {
+ v = c - b'0';
+ } else if c >= b'A' && c <= b'F' {
+ v = c - b'A' + 10;
+ } else if c >= b'a' && c <= b'f' {
+ v = c - b'a' + 10;
+ } else {
+ v = 0;
+ }
+ v <<= 4;
+ c = hex[2 * i + 1];
+ if c >= b'0' && c <= b'9' {
+ v += c - b'0';
+ } else if c >= b'A' && c <= b'F' {
+ v += c - b'A' + 10;
+ } else if c >= b'a' && c <= b'f' {
+ v += c - b'a' + 10;
+ } else {
+ v = 0;
+ }
+ bin[i] = v;
+ }
+ }
+}
+/*
+fn main()
+{
+ let kt=b"feffe9928665731c6d6a8f9467308308";
+ let mt=b"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
+ let ht=b"feedfacedeadbeeffeedfacedeadbeefabaddad2";
+ let nt=b"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b";
+// Tag should be 619cc5aefffe0bfa462af43c1699d050
+
+ let mut gcm=GCM::new();
+
+ let len=mt.len()/2;
+ let lenh=ht.len()/2;
+ let lenk=kt.len()/2;
+ let leniv=nt.len()/2;
+
+ //let mut t:[u8;16]=[0;16]; // Tag
+ let mut k:[u8;16]=[0;16]; // AES Key
+ let mut h:[u8;64]=[0;64]; // Header - to be included in Authentication, but not encrypted
+ let mut n:[u8;100]=[0;100]; // IV - Initialisation vector
+ let mut m:[u8;100]=[0;100]; // Plaintext to be encrypted/authenticated
+ let mut c:[u8;100]=[0;100]; // Ciphertext
+ let mut p:[u8;100]=[0;100]; // Recovered Plaintext
+
+ GCM::hex2bytes(mt,&mut m);
+ GCM::hex2bytes(ht,&mut h);
+ GCM::hex2bytes(kt,&mut k);
+ GCM::hex2bytes(nt,&mut n);
+
+ println!("Plaintext=");
+ for i in 0..len {print!("{:02x}",m[i])}
+ println!("");
+
+ gcm.init(lenk,&k,leniv,&n);
+
+ gcm.add_header(&h,lenh);
+ gcm.add_plain(&mut c,&m,len);
+ let mut t=gcm.finish(true);
+
+ println!("Ciphertext=");
+ for i in 0..len {print!("{:02x}",c[i])}
+ println!("");
+
+ println!("Tag=");
+ for i in 0..16 {print!("{:02x}",t[i])}
+ println!("");
+
+ gcm.init(lenk,&k,leniv,&n);
+
+ gcm.add_header(&h,lenh);
+ gcm.add_cipher(&mut p,&c,len);
+ t=gcm.finish(true);
+
+ println!("Plaintext=");
+ for i in 0..len {print!("{:02x}",p[i])}
+ println!("");
+
+ println!("Tag=");
+ for i in 0..16 {print!("{:02x}",t[i])}
+ println!("");
+
+}
+*/
diff --git a/src/hash256.rs b/src/hash256.rs
new file mode 100644
index 0000000..e8d6260
--- /dev/null
+++ b/src/hash256.rs
@@ -0,0 +1,216 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+const HASH256_H0: u32 = 0x6A09E667;
+const HASH256_H1: u32 = 0xBB67AE85;
+const HASH256_H2: u32 = 0x3C6EF372;
+const HASH256_H3: u32 = 0xA54FF53A;
+const HASH256_H4: u32 = 0x510E527F;
+const HASH256_H5: u32 = 0x9B05688C;
+const HASH256_H6: u32 = 0x1F83D9AB;
+const HASH256_H7: u32 = 0x5BE0CD19;
+
+const HASH256_K: [u32; 64] = [
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+];
+
+pub struct HASH256 {
+ length: [u32; 2],
+ h: [u32; 8],
+ w: [u32; 64],
+}
+
+impl HASH256 {
+ fn s(n: u32, x: u32) -> u32 {
+ return ((x) >> n) | ((x) << (32 - n));
+ }
+ fn r(n: u32, x: u32) -> u32 {
+ return (x) >> n;
+ }
+
+ fn ch(x: u32, y: u32, z: u32) -> u32 {
+ return (x & y) ^ (!(x) & z);
+ }
+
+ fn maj(x: u32, y: u32, z: u32) -> u32 {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+ fn sig0(x: u32) -> u32 {
+ return HASH256::s(2, x) ^ HASH256::s(13, x) ^ HASH256::s(22, x);
+ }
+
+ fn sig1(x: u32) -> u32 {
+ return HASH256::s(6, x) ^ HASH256::s(11, x) ^ HASH256::s(25, x);
+ }
+
+ fn theta0(x: u32) -> u32 {
+ return HASH256::s(7, x) ^ HASH256::s(18, x) ^ HASH256::r(3, x);
+ }
+
+ fn theta1(x: u32) -> u32 {
+ return HASH256::s(17, x) ^ HASH256::s(19, x) ^ HASH256::r(10, x);
+ }
+
+ fn transform(&mut self) {
+ /* basic transformation step */
+ for j in 16..64 {
+ self.w[j] = HASH256::theta1(self.w[j - 2])
+ .wrapping_add(self.w[j - 7])
+ .wrapping_add(HASH256::theta0(self.w[j - 15]))
+ .wrapping_add(self.w[j - 16]);
+ }
+ let mut a = self.h[0];
+ let mut b = self.h[1];
+ let mut c = self.h[2];
+ let mut d = self.h[3];
+ let mut e = self.h[4];
+ let mut f = self.h[5];
+ let mut g = self.h[6];
+ let mut hh = self.h[7];
+ for j in 0..64 {
+ /* 64 times - mush it up */
+ let t1 = hh
+ .wrapping_add(HASH256::sig1(e))
+ .wrapping_add(HASH256::ch(e, f, g))
+ .wrapping_add(HASH256_K[j])
+ .wrapping_add(self.w[j]);
+ let t2 = HASH256::sig0(a).wrapping_add(HASH256::maj(a, b, c));
+ hh = g;
+ g = f;
+ f = e;
+ e = d.wrapping_add(t1);
+ d = c;
+ c = b;
+ b = a;
+ a = t1.wrapping_add(t2);
+ }
+ self.h[0] = self.h[0].wrapping_add(a);
+ self.h[1] = self.h[1].wrapping_add(b);
+ self.h[2] = self.h[2].wrapping_add(c);
+ self.h[3] = self.h[3].wrapping_add(d);
+ self.h[4] = self.h[4].wrapping_add(e);
+ self.h[5] = self.h[5].wrapping_add(f);
+ self.h[6] = self.h[6].wrapping_add(g);
+ self.h[7] = self.h[7].wrapping_add(hh);
+ }
+
+ /* Initialise Hash function */
+ pub fn init(&mut self) {
+ /* initialise */
+ for i in 0..64 {
+ self.w[i] = 0
+ }
+ self.length[0] = 0;
+ self.length[1] = 0;
+ self.h[0] = HASH256_H0;
+ self.h[1] = HASH256_H1;
+ self.h[2] = HASH256_H2;
+ self.h[3] = HASH256_H3;
+ self.h[4] = HASH256_H4;
+ self.h[5] = HASH256_H5;
+ self.h[6] = HASH256_H6;
+ self.h[7] = HASH256_H7;
+ }
+
+ pub fn new() -> HASH256 {
+ let mut nh = HASH256 {
+ length: [0; 2],
+ h: [0; 8],
+ w: [0; 64],
+ };
+ nh.init();
+ return nh;
+ }
+
+ /* process a single byte */
+ pub fn process(&mut self, byt: u8) {
+ /* process the next message byte */
+ let cnt = ((self.length[0] / 32) % 16) as usize;
+ self.w[cnt] <<= 8;
+ self.w[cnt] |= (byt & 0xFF) as u32;
+ self.length[0] += 8;
+ if self.length[0] == 0 {
+ self.length[1] += 1;
+ self.length[0] = 0
+ }
+ if (self.length[0] % 512) == 0 {
+ self.transform()
+ }
+ }
+
+ /* process an array of bytes */
+
+ pub fn process_array(&mut self, b: &[u8]) {
+ for i in 0..b.len() {
+ self.process(b[i])
+ }
+ }
+
+ /* process a 32-bit integer */
+ pub fn process_num(&mut self, n: i32) {
+ self.process(((n >> 24) & 0xff) as u8);
+ self.process(((n >> 16) & 0xff) as u8);
+ self.process(((n >> 8) & 0xff) as u8);
+ self.process((n & 0xff) as u8);
+ }
+
+ /* Generate 32-byte Hash */
+ pub fn hash(&mut self) -> [u8; 32] {
+ /* pad message and finish - supply digest */
+ let mut digest: [u8; 32] = [0; 32];
+ let len0 = self.length[0];
+ let len1 = self.length[1];
+ self.process(0x80);
+ while (self.length[0] % 512) != 448 {
+ self.process(0)
+ }
+ self.w[14] = len1;
+ self.w[15] = len0;
+ self.transform();
+ for i in 0..32 {
+ /* convert to bytes */
+ digest[i] = ((self.h[i / 4] >> (8 * (3 - i % 4))) & 0xff) as u8;
+ }
+ self.init();
+ return digest;
+ }
+}
+
+//248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
+/*
+fn main() {
+ let s = String::from("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+ let test = s.into_bytes();
+ let mut sh=HASH256::new();
+
+ for i in 0..test.len(){
+ sh.process(test[i]);
+ }
+
+ let digest=sh.hash();
+ for i in 0..32 {print!("{:02x}",digest[i])}
+}
+*/
diff --git a/src/hash384.rs b/src/hash384.rs
new file mode 100644
index 0000000..2e3729e
--- /dev/null
+++ b/src/hash384.rs
@@ -0,0 +1,288 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+const HASH384_H0: u64 = 0xcbbb9d5dc1059ed8;
+const HASH384_H1: u64 = 0x629a292a367cd507;
+const HASH384_H2: u64 = 0x9159015a3070dd17;
+const HASH384_H3: u64 = 0x152fecd8f70e5939;
+const HASH384_H4: u64 = 0x67332667ffc00b31;
+const HASH384_H5: u64 = 0x8eb44a8768581511;
+const HASH384_H6: u64 = 0xdb0c2e0d64f98fa7;
+const HASH384_H7: u64 = 0x47b5481dbefa4fa4;
+
+const HASH384_K: [u64; 80] = [
+ 0x428a2f98d728ae22,
+ 0x7137449123ef65cd,
+ 0xb5c0fbcfec4d3b2f,
+ 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538,
+ 0x59f111f1b605d019,
+ 0x923f82a4af194f9b,
+ 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242,
+ 0x12835b0145706fbe,
+ 0x243185be4ee4b28c,
+ 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f,
+ 0x80deb1fe3b1696b1,
+ 0x9bdc06a725c71235,
+ 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2,
+ 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5,
+ 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275,
+ 0x4a7484aa6ea6e483,
+ 0x5cb0a9dcbd41fbd4,
+ 0x76f988da831153b5,
+ 0x983e5152ee66dfab,
+ 0xa831c66d2db43210,
+ 0xb00327c898fb213f,
+ 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2,
+ 0xd5a79147930aa725,
+ 0x06ca6351e003826f,
+ 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc,
+ 0x2e1b21385c26c926,
+ 0x4d2c6dfc5ac42aed,
+ 0x53380d139d95b3df,
+ 0x650a73548baf63de,
+ 0x766a0abb3c77b2a8,
+ 0x81c2c92e47edaee6,
+ 0x92722c851482353b,
+ 0xa2bfe8a14cf10364,
+ 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791,
+ 0xc76c51a30654be30,
+ 0xd192e819d6ef5218,
+ 0xd69906245565a910,
+ 0xf40e35855771202a,
+ 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8,
+ 0x1e376c085141ab53,
+ 0x2748774cdf8eeb99,
+ 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63,
+ 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373,
+ 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc,
+ 0x78a5636f43172f60,
+ 0x84c87814a1f0ab72,
+ 0x8cc702081a6439ec,
+ 0x90befffa23631e28,
+ 0xa4506cebde82bde9,
+ 0xbef9a3f7b2c67915,
+ 0xc67178f2e372532b,
+ 0xca273eceea26619c,
+ 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e,
+ 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba,
+ 0x0a637dc5a2c898a6,
+ 0x113f9804bef90dae,
+ 0x1b710b35131c471b,
+ 0x28db77f523047d84,
+ 0x32caab7b40c72493,
+ 0x3c9ebe0a15c9bebc,
+ 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6,
+ 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec,
+ 0x6c44198c4a475817,
+];
+
+pub struct HASH384 {
+ length: [u64; 2],
+ h: [u64; 8],
+ w: [u64; 80],
+}
+
+impl HASH384 {
+ fn s(n: u64, x: u64) -> u64 {
+ return ((x) >> n) | ((x) << (64 - n));
+ }
+ fn r(n: u64, x: u64) -> u64 {
+ return (x) >> n;
+ }
+
+ fn ch(x: u64, y: u64, z: u64) -> u64 {
+ return (x & y) ^ (!(x) & z);
+ }
+
+ fn maj(x: u64, y: u64, z: u64) -> u64 {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ fn sig0(x: u64) -> u64 {
+ return HASH384::s(28, x) ^ HASH384::s(34, x) ^ HASH384::s(39, x);
+ }
+
+ fn sig1(x: u64) -> u64 {
+ return HASH384::s(14, x) ^ HASH384::s(18, x) ^ HASH384::s(41, x);
+ }
+
+ fn theta0(x: u64) -> u64 {
+ return HASH384::s(1, x) ^ HASH384::s(8, x) ^ HASH384::r(7, x);
+ }
+
+ fn theta1(x: u64) -> u64 {
+ return HASH384::s(19, x) ^ HASH384::s(61, x) ^ HASH384::r(6, x);
+ }
+
+ fn transform(&mut self) {
+ /* basic transformation step */
+ for j in 16..80 {
+ self.w[j] = HASH384::theta1(self.w[j - 2])
+ .wrapping_add(self.w[j - 7])
+ .wrapping_add(HASH384::theta0(self.w[j - 15]))
+ .wrapping_add(self.w[j - 16]);
+ }
+ let mut a = self.h[0];
+ let mut b = self.h[1];
+ let mut c = self.h[2];
+ let mut d = self.h[3];
+ let mut e = self.h[4];
+ let mut f = self.h[5];
+ let mut g = self.h[6];
+ let mut hh = self.h[7];
+ for j in 0..80 {
+ /* 64 times - mush it up */
+ let t1 = hh
+ .wrapping_add(HASH384::sig1(e))
+ .wrapping_add(HASH384::ch(e, f, g))
+ .wrapping_add(HASH384_K[j])
+ .wrapping_add(self.w[j]);
+ let t2 = HASH384::sig0(a).wrapping_add(HASH384::maj(a, b, c));
+ hh = g;
+ g = f;
+ f = e;
+ e = d.wrapping_add(t1);
+ d = c;
+ c = b;
+ b = a;
+ a = t1.wrapping_add(t2);
+ }
+ self.h[0] = self.h[0].wrapping_add(a);
+ self.h[1] = self.h[1].wrapping_add(b);
+ self.h[2] = self.h[2].wrapping_add(c);
+ self.h[3] = self.h[3].wrapping_add(d);
+ self.h[4] = self.h[4].wrapping_add(e);
+ self.h[5] = self.h[5].wrapping_add(f);
+ self.h[6] = self.h[6].wrapping_add(g);
+ self.h[7] = self.h[7].wrapping_add(hh);
+ }
+
+ /* Initialise Hash function */
+ pub fn init(&mut self) {
+ /* initialise */
+ for i in 0..64 {
+ self.w[i] = 0
+ }
+ self.length[0] = 0;
+ self.length[1] = 0;
+ self.h[0] = HASH384_H0;
+ self.h[1] = HASH384_H1;
+ self.h[2] = HASH384_H2;
+ self.h[3] = HASH384_H3;
+ self.h[4] = HASH384_H4;
+ self.h[5] = HASH384_H5;
+ self.h[6] = HASH384_H6;
+ self.h[7] = HASH384_H7;
+ }
+
+ pub fn new() -> HASH384 {
+ let mut nh = HASH384 {
+ length: [0; 2],
+ h: [0; 8],
+ w: [0; 80],
+ };
+ nh.init();
+ return nh;
+ }
+
+ /* process a single byte */
+ pub fn process(&mut self, byt: u8) {
+ /* process the next message byte */
+ let cnt = ((self.length[0] / 64) % 16) as usize;
+ self.w[cnt] <<= 8;
+ self.w[cnt] |= (byt & 0xFF) as u64;
+ self.length[0] += 8;
+ if self.length[0] == 0 {
+ self.length[1] += 1;
+ self.length[0] = 0
+ }
+ if (self.length[0] % 1024) == 0 {
+ self.transform()
+ }
+ }
+
+ /* process an array of bytes */
+
+ pub fn process_array(&mut self, b: &[u8]) {
+ for i in 0..b.len() {
+ self.process(b[i])
+ }
+ }
+
+ /* process a 32-bit integer */
+ pub fn process_num(&mut self, n: i32) {
+ self.process(((n >> 24) & 0xff) as u8);
+ self.process(((n >> 16) & 0xff) as u8);
+ self.process(((n >> 8) & 0xff) as u8);
+ self.process((n & 0xff) as u8);
+ }
+
+ /* Generate 48-byte Hash */
+ pub fn hash(&mut self) -> [u8; 48] {
+ /* pad message and finish - supply digest */
+ let mut digest: [u8; 48] = [0; 48];
+ let len0 = self.length[0];
+ let len1 = self.length[1];
+ self.process(0x80);
+ while (self.length[0] % 1024) != 896 {
+ self.process(0)
+ }
+ self.w[14] = len1;
+ self.w[15] = len0;
+ self.transform();
+ for i in 0..48 {
+ /* convert to bytes */
+ digest[i] = ((self.h[i / 8] >> (8 * (7 - i % 8))) & 0xff) as u8;
+ }
+ self.init();
+ return digest;
+ }
+}
+
+//09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712 fcc7c71a557e2db9 66c3e9fa91746039
+/*
+fn main() {
+ let s = String::from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ let test = s.into_bytes();
+ let mut sh=HASH384::new();
+
+ for i in 0..test.len(){
+ sh.process(test[i]);
+ }
+
+ let digest=sh.hash();
+ for i in 0..48 {print!("{:02x}",digest[i])}
+} */
diff --git a/src/hash512.rs b/src/hash512.rs
new file mode 100644
index 0000000..4eb0689
--- /dev/null
+++ b/src/hash512.rs
@@ -0,0 +1,288 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+const HASH512_H0: u64 = 0x6a09e667f3bcc908;
+const HASH512_H1: u64 = 0xbb67ae8584caa73b;
+const HASH512_H2: u64 = 0x3c6ef372fe94f82b;
+const HASH512_H3: u64 = 0xa54ff53a5f1d36f1;
+const HASH512_H4: u64 = 0x510e527fade682d1;
+const HASH512_H5: u64 = 0x9b05688c2b3e6c1f;
+const HASH512_H6: u64 = 0x1f83d9abfb41bd6b;
+const HASH512_H7: u64 = 0x5be0cd19137e2179;
+
+const HASH512_K: [u64; 80] = [
+ 0x428a2f98d728ae22,
+ 0x7137449123ef65cd,
+ 0xb5c0fbcfec4d3b2f,
+ 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538,
+ 0x59f111f1b605d019,
+ 0x923f82a4af194f9b,
+ 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242,
+ 0x12835b0145706fbe,
+ 0x243185be4ee4b28c,
+ 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f,
+ 0x80deb1fe3b1696b1,
+ 0x9bdc06a725c71235,
+ 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2,
+ 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5,
+ 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275,
+ 0x4a7484aa6ea6e483,
+ 0x5cb0a9dcbd41fbd4,
+ 0x76f988da831153b5,
+ 0x983e5152ee66dfab,
+ 0xa831c66d2db43210,
+ 0xb00327c898fb213f,
+ 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2,
+ 0xd5a79147930aa725,
+ 0x06ca6351e003826f,
+ 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc,
+ 0x2e1b21385c26c926,
+ 0x4d2c6dfc5ac42aed,
+ 0x53380d139d95b3df,
+ 0x650a73548baf63de,
+ 0x766a0abb3c77b2a8,
+ 0x81c2c92e47edaee6,
+ 0x92722c851482353b,
+ 0xa2bfe8a14cf10364,
+ 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791,
+ 0xc76c51a30654be30,
+ 0xd192e819d6ef5218,
+ 0xd69906245565a910,
+ 0xf40e35855771202a,
+ 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8,
+ 0x1e376c085141ab53,
+ 0x2748774cdf8eeb99,
+ 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63,
+ 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373,
+ 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc,
+ 0x78a5636f43172f60,
+ 0x84c87814a1f0ab72,
+ 0x8cc702081a6439ec,
+ 0x90befffa23631e28,
+ 0xa4506cebde82bde9,
+ 0xbef9a3f7b2c67915,
+ 0xc67178f2e372532b,
+ 0xca273eceea26619c,
+ 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e,
+ 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba,
+ 0x0a637dc5a2c898a6,
+ 0x113f9804bef90dae,
+ 0x1b710b35131c471b,
+ 0x28db77f523047d84,
+ 0x32caab7b40c72493,
+ 0x3c9ebe0a15c9bebc,
+ 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6,
+ 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec,
+ 0x6c44198c4a475817,
+];
+
+pub struct HASH512 {
+ length: [u64; 2],
+ h: [u64; 8],
+ w: [u64; 80],
+}
+
+impl HASH512 {
+ fn s(n: u64, x: u64) -> u64 {
+ return ((x) >> n) | ((x) << (64 - n));
+ }
+ fn r(n: u64, x: u64) -> u64 {
+ return (x) >> n;
+ }
+
+ fn ch(x: u64, y: u64, z: u64) -> u64 {
+ return (x & y) ^ (!(x) & z);
+ }
+
+ fn maj(x: u64, y: u64, z: u64) -> u64 {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ fn sig0(x: u64) -> u64 {
+ return HASH512::s(28, x) ^ HASH512::s(34, x) ^ HASH512::s(39, x);
+ }
+
+ fn sig1(x: u64) -> u64 {
+ return HASH512::s(14, x) ^ HASH512::s(18, x) ^ HASH512::s(41, x);
+ }
+
+ fn theta0(x: u64) -> u64 {
+ return HASH512::s(1, x) ^ HASH512::s(8, x) ^ HASH512::r(7, x);
+ }
+
+ fn theta1(x: u64) -> u64 {
+ return HASH512::s(19, x) ^ HASH512::s(61, x) ^ HASH512::r(6, x);
+ }
+
+ fn transform(&mut self) {
+ /* basic transformation step */
+ for j in 16..80 {
+ self.w[j] = HASH512::theta1(self.w[j - 2])
+ .wrapping_add(self.w[j - 7])
+ .wrapping_add(HASH512::theta0(self.w[j - 15]))
+ .wrapping_add(self.w[j - 16]);
+ }
+ let mut a = self.h[0];
+ let mut b = self.h[1];
+ let mut c = self.h[2];
+ let mut d = self.h[3];
+ let mut e = self.h[4];
+ let mut f = self.h[5];
+ let mut g = self.h[6];
+ let mut hh = self.h[7];
+ for j in 0..80 {
+ /* 64 times - mush it up */
+ let t1 = hh
+ .wrapping_add(HASH512::sig1(e))
+ .wrapping_add(HASH512::ch(e, f, g))
+ .wrapping_add(HASH512_K[j])
+ .wrapping_add(self.w[j]);
+ let t2 = HASH512::sig0(a).wrapping_add(HASH512::maj(a, b, c));
+ hh = g;
+ g = f;
+ f = e;
+ e = d.wrapping_add(t1);
+ d = c;
+ c = b;
+ b = a;
+ a = t1.wrapping_add(t2);
+ }
+ self.h[0] = self.h[0].wrapping_add(a);
+ self.h[1] = self.h[1].wrapping_add(b);
+ self.h[2] = self.h[2].wrapping_add(c);
+ self.h[3] = self.h[3].wrapping_add(d);
+ self.h[4] = self.h[4].wrapping_add(e);
+ self.h[5] = self.h[5].wrapping_add(f);
+ self.h[6] = self.h[6].wrapping_add(g);
+ self.h[7] = self.h[7].wrapping_add(hh);
+ }
+
+ /* Initialise Hash function */
+ pub fn init(&mut self) {
+ /* initialise */
+ for i in 0..64 {
+ self.w[i] = 0
+ }
+ self.length[0] = 0;
+ self.length[1] = 0;
+ self.h[0] = HASH512_H0;
+ self.h[1] = HASH512_H1;
+ self.h[2] = HASH512_H2;
+ self.h[3] = HASH512_H3;
+ self.h[4] = HASH512_H4;
+ self.h[5] = HASH512_H5;
+ self.h[6] = HASH512_H6;
+ self.h[7] = HASH512_H7;
+ }
+
+ pub fn new() -> HASH512 {
+ let mut nh = HASH512 {
+ length: [0; 2],
+ h: [0; 8],
+ w: [0; 80],
+ };
+ nh.init();
+ return nh;
+ }
+
+ /* process a single byte */
+ pub fn process(&mut self, byt: u8) {
+ /* process the next message byte */
+ let cnt = ((self.length[0] / 64) % 16) as usize;
+ self.w[cnt] <<= 8;
+ self.w[cnt] |= (byt & 0xFF) as u64;
+ self.length[0] += 8;
+ if self.length[0] == 0 {
+ self.length[1] += 1;
+ self.length[0] = 0
+ }
+ if (self.length[0] % 1024) == 0 {
+ self.transform()
+ }
+ }
+
+ /* process an array of bytes */
+
+ pub fn process_array(&mut self, b: &[u8]) {
+ for i in 0..b.len() {
+ self.process(b[i])
+ }
+ }
+
+ /* process a 32-bit integer */
+ pub fn process_num(&mut self, n: i32) {
+ self.process(((n >> 24) & 0xff) as u8);
+ self.process(((n >> 16) & 0xff) as u8);
+ self.process(((n >> 8) & 0xff) as u8);
+ self.process((n & 0xff) as u8);
+ }
+
+ /* Generate 64-byte Hash */
+ pub fn hash(&mut self) -> [u8; 64] {
+ /* pad message and finish - supply digest */
+ let mut digest: [u8; 64] = [0; 64];
+ let len0 = self.length[0];
+ let len1 = self.length[1];
+ self.process(0x80);
+ while (self.length[0] % 1024) != 896 {
+ self.process(0)
+ }
+ self.w[14] = len1;
+ self.w[15] = len0;
+ self.transform();
+ for i in 0..64 {
+ /* convert to bytes */
+ digest[i] = ((self.h[i / 8] >> (8 * (7 - i % 8))) & 0xff) as u8;
+ }
+ self.init();
+ return digest;
+ }
+}
+
+//8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909
+/*
+fn main() {
+ let s = String::from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ let test = s.into_bytes();
+ let mut sh=HASH512::new();
+
+ for i in 0..test.len(){
+ sh.process(test[i]);
+ }
+
+ let digest=sh.hash();
+ for i in 0..64 {print!("{:02x}",digest[i])}
+} */
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..108057b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,561 @@
+pub mod aes;
+pub mod gcm;
+pub mod hash256;
+pub mod hash384;
+pub mod hash512;
+pub mod rand;
+pub mod sha3;
+pub mod nhs;
+pub mod types;
+#[cfg(target_pointer_width = "32")]
+#[path = "arch/arch32.rs"]
+pub mod arch;
+#[cfg(target_pointer_width = "64")]
+#[path = "arch/arch64.rs"]
+pub mod arch;
+
+#[cfg(feature = "bls48")]
+#[path = "./"]
+pub mod bls48 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bls48_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bls48_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecp8;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp8;
+ pub mod fp16;
+ pub mod fp48;
+ pub mod pair256;
+ pub mod mpin256;
+ pub mod bls256;
+}
+
+#[cfg(feature = "bls461")]
+#[path = "./"]
+pub mod bls461 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bls461_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bls461_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "bls383")]
+#[path = "./"]
+pub mod bls383 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bls383_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bls383_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "bls381")]
+#[path = "./"]
+pub mod bls381 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bls381_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bls381_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "fp512bn")]
+#[path = "./"]
+pub mod fp512bn {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_fp512bn_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_fp512bn_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "fp256bn")]
+#[path = "./"]
+pub mod fp256bn {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_fp256bn_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_fp256bn_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "bls24")]
+#[path = "./"]
+pub mod bls24 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bls24_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bls24_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp8;
+ pub mod fp24;
+ pub mod ecp;
+ pub mod ecp4;
+ pub mod pair192;
+ pub mod mpin192;
+ pub mod bls192;
+}
+
+#[cfg(feature = "anssi")]
+#[path = "./"]
+pub mod anssi {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_anssi_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_anssi_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "brainpool")]
+#[path = "./"]
+pub mod brainpool {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_brainpool_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_brainpool_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "goldilocks")]
+#[path = "./"]
+pub mod goldilocks {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_goldilocks_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_goldilocks_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "hifive")]
+#[path = "./"]
+pub mod hifive {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_hifive_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_hifive_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nist256")]
+#[path = "./"]
+pub mod nist256 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nist256_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nist256_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nist384")]
+#[path = "./"]
+pub mod nist384 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nist384_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nist384_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nist521")]
+#[path = "./"]
+pub mod nist521 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nist521_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nist521_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nums256e")]
+#[path = "./"]
+pub mod nums256e {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nums256e_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nums256e_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nums256w")]
+#[path = "./"]
+pub mod nums256w {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nums256w_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nums256w_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nums384e")]
+#[path = "./"]
+pub mod nums384e {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nums384e_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nums384e_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nums384w")]
+#[path = "./"]
+pub mod nums384w {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nums384w_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nums384w_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nums512w")]
+#[path = "./"]
+pub mod nums512w {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nums512w_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nums512w_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "nums512e")]
+#[path = "./"]
+pub mod nums512e {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_nums512e_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_nums512e_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "secp256k1")]
+#[path = "./"]
+pub mod secp256k1 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_secp256k1_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_secp256k1_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "c25519")]
+#[path = "./"]
+pub mod c25519 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_c25519_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_c25519_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "c41417")]
+#[path = "./"]
+pub mod c41417 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_c41417_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_c41417_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "ed25519")]
+#[path = "./"]
+pub mod ed25519 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_ed25519_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_ed25519_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+}
+
+#[cfg(feature = "bn254CX")]
+#[path = "./"]
+pub mod bn254CX {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bn254CX_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bn254CX_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "bn254")]
+#[path = "./"]
+pub mod bn254 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_bn254_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_bn254_64.rs"]
+ pub mod rom;
+
+ pub mod big;
+ pub mod dbig;
+ pub mod fp;
+ pub mod ecp;
+ pub mod ecdh;
+ pub mod ecp2;
+ pub mod fp2;
+ pub mod fp4;
+ pub mod fp12;
+ pub mod pair;
+ pub mod mpin;
+ pub mod bls;
+}
+
+#[cfg(feature = "rsa2048")]
+#[path = "./"]
+pub mod rsa2048 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_rsa2048_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_rsa2048_64.rs"]
+ pub mod rom;
+ pub mod big;
+ pub mod dbig;
+ pub mod ff;
+ pub mod rsa;
+}
+
+#[cfg(feature = "rsa3072")]
+#[path = "./"]
+pub mod rsa3072 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_rsa3072_32.rs"]
+ pub mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_rsa3072_64.rs"]
+ pub mod rom;
+ pub mod big;
+ pub mod dbig;
+ pub mod ff;
+ pub mod rsa;
+}
+
+#[cfg(feature = "rsa4096")]
+#[path = "./"]
+pub mod rsa4096 {
+ #[cfg(target_pointer_width = "32")]
+ #[path = "roms/rom_rsa4096_32.rs"]
+ mod rom;
+ #[cfg(target_pointer_width = "64")]
+ #[path = "roms/rom_rsa4096_64.rs"]
+ mod rom;
+ pub mod big;
+ pub mod dbig;
+ pub mod ff;
+ pub mod rsa;
+}
\ No newline at end of file
diff --git a/src/mpin.rs b/src/mpin.rs
new file mode 100644
index 0000000..6d7e9ca
--- /dev/null
+++ b/src/mpin.rs
@@ -0,0 +1,945 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use std::time::SystemTime;
+use std::time::UNIX_EPOCH;
+
+use super::ecp;
+use super::ecp::ECP;
+use super::ecp2::ECP2;
+use super::fp4::FP4;
+use super::fp12::FP12;
+use super::big::BIG;
+use super::pair;
+use super::big;
+use super::rom;
+
+use rand::RAND;
+use hash256::HASH256;
+use hash384::HASH384;
+use hash512::HASH512;
+
+
+/* MPIN API Functions */
+
+/* Configure mode of operation */
+
+pub const EFS: usize = big::MODBYTES as usize;
+pub const EGS: usize = big::MODBYTES as usize;
+pub const BAD_PARAMS: isize = -11;
+pub const INVALID_POINT: isize = -14;
+pub const WRONG_ORDER: isize = -18;
+pub const BAD_PIN: isize = -19;
+pub const SHA256: usize = 32;
+pub const SHA384: usize = 48;
+pub const SHA512: usize = 64;
+
+/* Configure your PIN here */
+
+pub const MAXPIN: i32 = 10000; /* PIN less than this */
+pub const PBLEN: i32 = 14; /* Number of bits in PIN */
+pub const TS: usize = 10; /* 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */
+pub const TRAP: usize = 200; /* 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) */
+
+#[allow(non_snake_case)]
+fn hash(sha: usize, c: &mut FP4, U: &mut ECP, r: &mut [u8]) -> bool {
+ let mut w: [u8; EFS] = [0; EFS];
+ let mut t: [u8; 6 * EFS] = [0; 6 * EFS];
+
+ c.geta().geta().tobytes(&mut w);
+ for i in 0..EFS {
+ t[i] = w[i]
+ }
+ c.geta().getb().tobytes(&mut w);
+ for i in EFS..2 * EFS {
+ t[i] = w[i - EFS]
+ }
+ c.getb().geta().tobytes(&mut w);
+ for i in 2 * EFS..3 * EFS {
+ t[i] = w[i - 2 * EFS]
+ }
+ c.getb().getb().tobytes(&mut w);
+ for i in 3 * EFS..4 * EFS {
+ t[i] = w[i - 3 * EFS]
+ }
+
+ U.getx().tobytes(&mut w);
+ for i in 4 * EFS..5 * EFS {
+ t[i] = w[i - 4 * EFS]
+ }
+ U.gety().tobytes(&mut w);
+ for i in 5 * EFS..6 * EFS {
+ t[i] = w[i - 5 * EFS]
+ }
+
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ return false;
+}
+
+/* Hash number (optional) and string to point on curve */
+
+fn hashit(sha: usize, n: usize, id: &[u8], w: &mut [u8]) -> bool {
+ let mut r: [u8; 64] = [0; 64];
+ let mut didit = false;
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if !didit {
+ return false;
+ }
+
+ let rm = big::MODBYTES as usize;
+
+ if sha > rm {
+ for i in 0..rm {
+ w[i] = r[i]
+ }
+ } else {
+ for i in 0..sha {
+ w[i + rm - sha] = r[i]
+ }
+ for i in 0..(rm - sha) {
+ w[i] = 0
+ }
+ }
+
+ return true;
+}
+
+/* return time in slots since epoch */
+pub fn today() -> usize {
+ return (SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs()
+ / (60 * 1440)) as usize;
+}
+
+/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */
+/* maps a random u to a point on the curve */
+#[allow(non_snake_case)]
+fn emap(u: &BIG, cb: isize) -> ECP {
+ let mut P: ECP;
+ let mut x = BIG::new_copy(u);
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ x.rmod(&mut p);
+ loop {
+ P = ECP::new_bigint(&x, cb);
+ if !P.is_infinity() {
+ break;
+ }
+ x.inc(1);
+ x.norm();
+ }
+ return P;
+}
+
+/* returns u derived from P. Random value in range 1 to return value should then be added to u */
+#[allow(non_snake_case)]
+fn unmap(u: &mut BIG, P: &mut ECP) -> isize {
+ let s = P.gets();
+ let mut R: ECP;
+ let mut r = 0;
+ let x = P.getx();
+ u.copy(&x);
+ loop {
+ u.dec(1);
+ u.norm();
+ r += 1;
+ R = ECP::new_bigint(u, s);
+ if !R.is_infinity() {
+ break;
+ }
+ }
+ return r as isize;
+}
+
+pub fn hash_id(sha: usize, id: &[u8], w: &mut [u8]) -> bool {
+ return hashit(sha, 0, id, w);
+}
+
+/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */
+/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */
+/* Note that u and v are indistinguisible from random strings */
+#[allow(non_snake_case)]
+pub fn encoding(rng: &mut RAND, e: &mut [u8]) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+
+ for i in 0..EFS {
+ t[i] = e[i + 1]
+ }
+ let mut u = BIG::frombytes(&t);
+ for i in 0..EFS {
+ t[i] = e[i + EFS + 1]
+ }
+ let mut v = BIG::frombytes(&t);
+
+ let mut P = ECP::new_bigs(&u, &v);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let p = BIG::new_ints(&rom::MODULUS);
+ u = BIG::randomnum(&p, rng);
+
+ let mut su = rng.getbyte() as isize;
+ su %= 2;
+
+ let mut W = emap(&mut u, su);
+ P.sub(&mut W);
+ let sv = P.gets();
+ let rn = unmap(&mut v, &mut P);
+ let mut m = rng.getbyte() as isize;
+ m %= rn;
+ v.inc(m + 1);
+ e[0] = (su + 2 * sv) as u8;
+ u.tobytes(&mut t);
+ for i in 0..EFS {
+ e[i + 1] = t[i]
+ }
+ v.tobytes(&mut t);
+ for i in 0..EFS {
+ e[i + EFS + 1] = t[i]
+ }
+
+ return 0;
+}
+
+#[allow(non_snake_case)]
+pub fn decoding(d: &mut [u8]) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+
+ if (d[0] & 0x04) != 0 {
+ return INVALID_POINT;
+ }
+
+ for i in 0..EFS {
+ t[i] = d[i + 1]
+ }
+ let mut u = BIG::frombytes(&t);
+ for i in 0..EFS {
+ t[i] = d[i + EFS + 1]
+ }
+ let mut v = BIG::frombytes(&t);
+
+ let su = (d[0] & 1) as isize;
+ let sv = ((d[0] >> 1) & 1) as isize;
+ let mut W = emap(&mut u, su);
+ let mut P = emap(&mut v, sv);
+ P.add(&mut W);
+ u = P.getx();
+ v = P.gety();
+ d[0] = 0x04;
+ u.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i + 1] = t[i]
+ }
+ v.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i + EFS + 1] = t[i]
+ }
+
+ return 0;
+}
+
+/* R=R1+R2 in group G1 */
+#[allow(non_snake_case)]
+pub fn recombine_g1(r1: &[u8], r2: &[u8], r: &mut [u8]) -> isize {
+ let mut P = ECP::frombytes(&r1);
+ let mut Q = ECP::frombytes(&r2);
+
+ if P.is_infinity() || Q.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P.add(&mut Q);
+
+ P.tobytes(r, false);
+ return 0;
+}
+
+/* W=W1+W2 in group G2 */
+#[allow(non_snake_case)]
+pub fn recombine_g2(w1: &[u8], w2: &[u8], w: &mut [u8]) -> isize {
+ let mut P = ECP2::frombytes(&w1);
+ let mut Q = ECP2::frombytes(&w2);
+
+ if P.is_infinity() || Q.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P.add(&mut Q);
+
+ P.tobytes(w);
+ return 0;
+}
+
+/* create random secret S */
+pub fn random_generate(rng: &mut RAND, s: &mut [u8]) -> isize {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut sc = BIG::randomnum(&r, rng);
+ sc.tobytes(s);
+ return 0;
+}
+
+/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */
+#[allow(non_snake_case)]
+pub fn get_server_secret(s: &[u8], sst: &mut [u8]) -> isize {
+ let mut Q = ECP2::generator();
+
+ let mut sc = BIG::frombytes(s);
+ Q = pair::g2mul(&mut Q, &mut sc);
+ Q.tobytes(sst);
+ return 0;
+}
+
+/*
+ W=x*H(G);
+ if RNG == NULL then X is passed in
+ if RNG != NULL the X is passed out
+ if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve
+*/
+#[allow(non_snake_case)]
+pub fn get_g1_multiple(
+ rng: Option<&mut RAND>,
+ typ: usize,
+ x: &mut [u8],
+ g: &[u8],
+ w: &mut [u8],
+) -> isize {
+ let mut sx: BIG;
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ if let Some(rd) = rng {
+ sx = BIG::randomnum(&r, rd);
+ sx.tobytes(x);
+ } else {
+ sx = BIG::frombytes(x);
+ }
+ let mut P: ECP;
+
+ if typ == 0 {
+ P = ECP::frombytes(g);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ } else {
+ P = ECP::mapit(g)
+ }
+
+ pair::g1mul(&mut P, &mut sx).tobytes(w, false);
+ return 0;
+}
+
+/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */
+/* CID is hashed externally */
+pub fn get_client_secret(s: &mut [u8], cid: &[u8], cst: &mut [u8]) -> isize {
+ return get_g1_multiple(None, 1, s, cid, cst);
+}
+
+/* Extract PIN from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_pin(sha: usize, cid: &[u8], pin: i32, token: &mut [u8]) -> isize {
+ return extract_factor(sha, cid, pin % MAXPIN, PBLEN, token);
+}
+
+/* Extract factor from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_factor(
+ sha: usize,
+ cid: &[u8],
+ factor: i32,
+ facbits: i32,
+ token: &mut [u8],
+) -> isize {
+ let mut P = ECP::frombytes(&token);
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ hashit(sha, 0, cid, &mut h);
+ let mut R = ECP::mapit(&h);
+
+ R = R.pinmul(factor, facbits);
+ P.sub(&mut R);
+
+ P.tobytes(token, false);
+
+ return 0;
+}
+
+/* Restore factor to TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn restore_factor(
+ sha: usize,
+ cid: &[u8],
+ factor: i32,
+ facbits: i32,
+ token: &mut [u8],
+) -> isize {
+ let mut P = ECP::frombytes(&token);
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ hashit(sha, 0, cid, &mut h);
+ let mut R = ECP::mapit(&h);
+
+ R = R.pinmul(factor, facbits);
+ P.add(&mut R);
+
+ P.tobytes(token, false);
+
+ return 0;
+}
+
+/* Functions to support M-Pin Full */
+#[allow(non_snake_case)]
+pub fn precompute(token: &[u8], cid: &[u8], g1: &mut [u8], g2: &mut [u8]) -> isize {
+ let T = ECP::frombytes(&token);
+ if T.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let P = ECP::mapit(&cid);
+
+ let Q = ECP2::generator();
+
+ let mut g = pair::ate(&Q, &T);
+ g = pair::fexp(&g);
+ g.tobytes(g1);
+
+ g = pair::ate(&Q, &P);
+ g = pair::fexp(&g);
+ g.tobytes(g2);
+
+ return 0;
+}
+
+/* Time Permit CTT=S*(date|H(CID)) where S is master secret */
+#[allow(non_snake_case)]
+pub fn get_client_permit(sha: usize, date: usize, s: &[u8], cid: &[u8], ctt: &mut [u8]) -> isize {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ hashit(sha, date, cid, &mut h);
+ let mut P = ECP::mapit(&h);
+
+ let mut sc = BIG::frombytes(s);
+ pair::g1mul(&mut P, &mut sc).tobytes(ctt, false);
+ return 0;
+}
+
+/* Implement step 1 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_1(
+ sha: usize,
+ date: usize,
+ client_id: &[u8],
+ rng: Option<&mut RAND>,
+ x: &mut [u8],
+ pin: usize,
+ token: &[u8],
+ sec: &mut [u8],
+ xid: Option<&mut [u8]>,
+ xcid: Option<&mut [u8]>,
+ permit: Option<&[u8]>,
+) -> isize {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ let mut sx: BIG;
+
+ if let Some(rd) = rng {
+ sx = BIG::randomnum(&r, rd);
+ sx.tobytes(x);
+ } else {
+ sx = BIG::frombytes(x);
+ }
+
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, 0, &client_id, &mut h);
+ let mut P = ECP::mapit(&h);
+
+ let mut T = ECP::frombytes(&token);
+ if T.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut W = P.pinmul((pin as i32) % MAXPIN, PBLEN);
+ T.add(&mut W);
+ if date != 0 {
+ if let Some(rpermit) = permit {
+ W = ECP::frombytes(&rpermit);
+ }
+ if W.is_infinity() {
+ return INVALID_POINT;
+ }
+ T.add(&mut W);
+ let mut h2: [u8; RM] = [0; RM];
+ hashit(sha, date, &h, &mut h2);
+ W = ECP::mapit(&h2);
+ if let Some(mut rxid) = xid {
+ P = pair::g1mul(&mut P, &mut sx);
+ P.tobytes(&mut rxid, false);
+ W = pair::g1mul(&mut W, &mut sx);
+ P.add(&mut W);
+ } else {
+ P.add(&mut W);
+ P = pair::g1mul(&mut P, &mut sx);
+ }
+ if let Some(mut rxcid) = xcid {
+ P.tobytes(&mut rxcid, false)
+ }
+ } else {
+ if let Some(mut rxid) = xid {
+ P = pair::g1mul(&mut P, &mut sx);
+ P.tobytes(&mut rxid, false);
+ }
+ }
+
+ T.tobytes(sec, false);
+ return 0;
+}
+
+/* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set HID=HTID */
+#[allow(non_snake_case)]
+pub fn server_1(sha: usize, date: usize, cid: &[u8], hid: &mut [u8], htid: Option<&mut [u8]>) {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, 0, cid, &mut h);
+
+ let mut P = ECP::mapit(&h);
+
+ P.tobytes(hid, false);
+ if date != 0 {
+ let mut h2: [u8; RM] = [0; RM];
+ hashit(sha, date, &h, &mut h2);
+ let mut R = ECP::mapit(&h2);
+ P.add(&mut R);
+ if let Some(rhtid) = htid {
+ P.tobytes(rhtid, false);
+ }
+ }
+}
+
+/* Implement step 2 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_2(x: &[u8], y: &[u8], sec: &mut [u8]) -> isize {
+ let mut r = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut P = ECP::frombytes(sec);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut px = BIG::frombytes(x);
+ let py = BIG::frombytes(y);
+ px.add(&py);
+ px.rmod(&mut r);
+
+ P = pair::g1mul(&mut P, &mut px);
+ P.neg();
+ P.tobytes(sec, false);
+
+ return 0;
+}
+
+/* return time since epoch */
+pub fn get_time() -> usize {
+ return (SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs()) as usize;
+}
+
+/* Generate Y = H(epoch, xCID/xID) */
+pub fn get_y(sha: usize, timevalue: usize, xcid: &[u8], y: &mut [u8]) {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, timevalue, xcid, &mut h);
+
+ let mut sy = BIG::frombytes(&h);
+ let mut q = BIG::new_ints(&rom::CURVE_ORDER);
+ sy.rmod(&mut q);
+ sy.tobytes(y);
+}
+
+/* Implement step 2 of MPin protocol on server side */
+#[allow(non_snake_case)]
+pub fn server_2(
+ date: usize,
+ hid: &[u8],
+ htid: Option<&[u8]>,
+ y: &[u8],
+ sst: &[u8],
+ xid: Option<&[u8]>,
+ xcid: Option<&[u8]>,
+ msec: &[u8],
+ e: Option<&mut [u8]>,
+ f: Option<&mut [u8]>,
+) -> isize {
+ let Q = ECP2::generator();
+
+ let sQ = ECP2::frombytes(&sst);
+ if sQ.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut R: ECP;
+ if date != 0 {
+ if let Some(rxcid) = xcid {
+ R = ECP::frombytes(&rxcid);
+ } else {
+ return BAD_PARAMS;
+ }
+ } else {
+ if let Some(rxid) = xid {
+ R = ECP::frombytes(&rxid)
+ } else {
+ return BAD_PARAMS;
+ }
+ }
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut sy = BIG::frombytes(&y);
+ let mut P: ECP;
+ if date != 0 {
+ if let Some(rhtid) = htid {
+ P = ECP::frombytes(&rhtid)
+ } else {
+ return BAD_PARAMS;
+ }
+ } else {
+ P = ECP::frombytes(&hid);
+ }
+
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P = pair::g1mul(&mut P, &mut sy);
+ P.add(&mut R);
+ R = ECP::frombytes(&msec);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut g: FP12;
+
+ g = pair::ate2(&Q, &R, &sQ, &P);
+ g = pair::fexp(&g);
+
+ if !g.isunity() {
+ if let Some(rxid) = xid {
+ if let Some(re) = e {
+ if let Some(rf) = f {
+ g.tobytes(re);
+ if date != 0 {
+ P = ECP::frombytes(&hid);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ R = ECP::frombytes(&rxid);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+ P = pair::g1mul(&mut P, &mut sy);
+ P.add(&mut R); //P.affine();
+ }
+ g = pair::ate(&Q, &P);
+ g = pair::fexp(&g);
+ g.tobytes(rf);
+ }
+ }
+ }
+
+ return BAD_PIN;
+ }
+
+ return 0;
+}
+
+/* Pollards kangaroos used to return PIN error */
+pub fn kangaroo(e: &[u8], f: &[u8]) -> isize {
+ let mut ge = FP12::frombytes(e);
+ let mut gf = FP12::frombytes(f);
+ let mut distance: [isize; TS] = [0; TS];
+ let mut t = FP12::new_copy(&gf);
+
+ let mut table: [FP12; TS] = [FP12::new(); TS];
+ let mut s: isize = 1;
+ for m in 0..TS {
+ distance[m] = s;
+ table[m] = FP12::new_copy(&t);
+ s *= 2;
+ t.usqr();
+ }
+ t.one();
+ let mut dn: isize = 0;
+ let mut i: usize;
+ for _ in 0..TRAP {
+ i = (t.geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
+ t.mul(&mut table[i]);
+ dn += distance[i];
+ }
+ gf.copy(&t);
+ gf.conj();
+ let mut steps: usize = 0;
+ let mut dm: isize = 0;
+ let mut res: isize = 0;
+ while dm - dn < MAXPIN as isize {
+ steps += 1;
+ if steps > 4 * TRAP {
+ break;
+ }
+ i = (ge.geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
+ ge.mul(&mut table[i]);
+ dm += distance[i];
+ if ge.equals(&mut t) {
+ res = dm - dn;
+ break;
+ }
+ if ge.equals(&mut gf) {
+ res = dn - dm;
+ break;
+ }
+ }
+ if steps > 4 * TRAP || dm - dn >= MAXPIN as isize {
+ res = 0
+ } // Trap Failed - probable invalid token
+ return res;
+}
+
+/* Hash the M-Pin transcript - new */
+
+pub fn hash_all(
+ sha: usize,
+ hid: &[u8],
+ xid: &[u8],
+ xcid: Option<&[u8]>,
+ sec: &[u8],
+ y: &[u8],
+ r: &[u8],
+ w: &[u8],
+ h: &mut [u8],
+) -> bool {
+ let mut tlen: usize = 0;
+ const RM: usize = big::MODBYTES as usize;
+ let mut t: [u8; 10 * RM + 4] = [0; 10 * RM + 4];
+
+ for i in 0..hid.len() {
+ t[i] = hid[i]
+ }
+ tlen += hid.len();
+
+ if let Some(rxcid) = xcid {
+ for i in 0..rxcid.len() {
+ t[i + tlen] = rxcid[i]
+ }
+ tlen += rxcid.len();
+ } else {
+ for i in 0..xid.len() {
+ t[i + tlen] = xid[i]
+ }
+ tlen += xid.len();
+ }
+
+ for i in 0..sec.len() {
+ t[i + tlen] = sec[i]
+ }
+ tlen += sec.len();
+ for i in 0..y.len() {
+ t[i + tlen] = y[i]
+ }
+ tlen += y.len();
+ for i in 0..r.len() {
+ t[i + tlen] = r[i]
+ }
+ tlen += r.len();
+ for i in 0..w.len() {
+ t[i + tlen] = w[i]
+ }
+ tlen += w.len();
+ if tlen != 10 * RM + 4 {
+ return false;
+ }
+
+ return hashit(sha, 0, &t, h);
+}
+
+/* calculate common key on client side */
+/* wCID = w.(A+AT) */
+#[allow(non_snake_case)]
+pub fn client_key(
+ sha: usize,
+ g1: &[u8],
+ g2: &[u8],
+ pin: usize,
+ r: &[u8],
+ x: &[u8],
+ h: &[u8],
+ wcid: &[u8],
+ ck: &mut [u8],
+) -> isize {
+ let mut g1 = FP12::frombytes(&g1);
+ let mut g2 = FP12::frombytes(&g2);
+ let mut z = BIG::frombytes(&r);
+ let mut x = BIG::frombytes(&x);
+ let h = BIG::frombytes(&h);
+
+ let mut W = ECP::frombytes(&wcid);
+ if W.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ W = pair::g1mul(&mut W, &mut x);
+
+ let mut r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ z.add(&h); //new
+ z.rmod(&mut r);
+
+ g2.pinpow(pin as i32, PBLEN);
+ g1.mul(&mut g2);
+
+ let mut c = g1.compow(&z, &mut r);
+
+ hash(sha, &mut c, &mut W, ck);
+
+ return 0;
+}
+
+/* calculate common key on server side */
+/* Z=r.A - no time permits involved */
+#[allow(non_snake_case)]
+pub fn server_key(
+ sha: usize,
+ z: &[u8],
+ sst: &[u8],
+ w: &[u8],
+ h: &[u8],
+ hid: &[u8],
+ xid: &[u8],
+ xcid: Option<&[u8]>,
+ sk: &mut [u8],
+) -> isize {
+ let sQ = ECP2::frombytes(&sst);
+ if sQ.is_infinity() {
+ return INVALID_POINT;
+ }
+ let mut R = ECP::frombytes(&z);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+ let mut A = ECP::frombytes(&hid);
+ if A.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut U = ECP::new();
+ if let Some(rxcid) = xcid {
+ U.copy(&ECP::frombytes(&rxcid));
+ } else {
+ U.copy(&ECP::frombytes(&xid));
+ }
+
+ if U.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut w = BIG::frombytes(&w);
+ let mut h = BIG::frombytes(&h);
+ A = pair::g1mul(&mut A, &mut h); // new
+ R.add(&mut A);
+
+ U = pair::g1mul(&mut U, &mut w);
+ let mut g = pair::ate(&sQ, &R);
+ g = pair::fexp(&g);
+
+ let mut c = g.trace();
+
+ hash(sha, &mut c, &mut U, sk);
+
+ return 0;
+}
diff --git a/src/mpin192.rs b/src/mpin192.rs
new file mode 100644
index 0000000..276a560
--- /dev/null
+++ b/src/mpin192.rs
@@ -0,0 +1,960 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use std::time::SystemTime;
+use std::time::UNIX_EPOCH;
+
+use super::ecp;
+use super::ecp::ECP;
+use super::ecp4::ECP4;
+use super::fp8::FP8;
+use super::fp24::FP24;
+use super::big::BIG;
+use super::pair192;
+use super::big;
+use super::rom;
+
+use rand::RAND;
+use hash256::HASH256;
+use hash384::HASH384;
+use hash512::HASH512;
+
+
+/* MPIN API Functions */
+
+/* Configure mode of operation */
+
+pub const EFS: usize = big::MODBYTES as usize;
+pub const EGS: usize = big::MODBYTES as usize;
+pub const BAD_PARAMS: isize = -11;
+pub const INVALID_POINT: isize = -14;
+pub const WRONG_ORDER: isize = -18;
+pub const BAD_PIN: isize = -19;
+pub const SHA256: usize = 32;
+pub const SHA384: usize = 48;
+pub const SHA512: usize = 64;
+
+/* Configure your PIN here */
+
+pub const MAXPIN: i32 = 10000; /* PIN less than this */
+pub const PBLEN: i32 = 14; /* Number of bits in PIN */
+pub const TS: usize = 10; /* 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */
+pub const TRAP: usize = 200; /* 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) */
+
+#[allow(non_snake_case)]
+fn hash(sha: usize, c: &mut FP8, U: &mut ECP, r: &mut [u8]) -> bool {
+ let mut w: [u8; EFS] = [0; EFS];
+ let mut t: [u8; 10 * EFS] = [0; 10 * EFS];
+
+ c.geta().geta().geta().tobytes(&mut w);
+ for i in 0..EFS {
+ t[i] = w[i]
+ }
+ c.geta().geta().getb().tobytes(&mut w);
+ for i in EFS..2 * EFS {
+ t[i] = w[i - EFS]
+ }
+ c.geta().getb().geta().tobytes(&mut w);
+ for i in 2 * EFS..3 * EFS {
+ t[i] = w[i - 2 * EFS]
+ }
+ c.geta().getb().getb().tobytes(&mut w);
+ for i in 3 * EFS..4 * EFS {
+ t[i] = w[i - 3 * EFS]
+ }
+ c.getb().geta().geta().tobytes(&mut w);
+ for i in 4 * EFS..5 * EFS {
+ t[i] = w[i - 4 * EFS]
+ }
+ c.getb().geta().getb().tobytes(&mut w);
+ for i in 5 * EFS..6 * EFS {
+ t[i] = w[i - 5 * EFS]
+ }
+ c.getb().getb().geta().tobytes(&mut w);
+ for i in 6 * EFS..7 * EFS {
+ t[i] = w[i - 6 * EFS]
+ }
+ c.getb().getb().getb().tobytes(&mut w);
+ for i in 7 * EFS..8 * EFS {
+ t[i] = w[i - 7 * EFS]
+ }
+
+ U.getx().tobytes(&mut w);
+ for i in 8 * EFS..9 * EFS {
+ t[i] = w[i - 8 * EFS]
+ }
+ U.gety().tobytes(&mut w);
+ for i in 9 * EFS..10 * EFS {
+ t[i] = w[i - 9 * EFS]
+ }
+
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ return false;
+}
+
+/* Hash number (optional) and string to point on curve */
+
+fn hashit(sha: usize, n: usize, id: &[u8], w: &mut [u8]) -> bool {
+ let mut r: [u8; 64] = [0; 64];
+ let mut didit = false;
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if !didit {
+ return false;
+ }
+
+ let rm = big::MODBYTES as usize;
+
+ if sha > rm {
+ for i in 0..rm {
+ w[i] = r[i]
+ }
+ } else {
+ for i in 0..sha {
+ w[i + rm - sha] = r[i]
+ }
+ for i in 0..(rm - sha) {
+ w[i] = 0
+ }
+ }
+
+ return true;
+}
+
+/* return time in slots since epoch */
+pub fn today() -> usize {
+ return (SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs()
+ / (60 * 1440)) as usize;
+}
+
+/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */
+/* maps a random u to a point on the curve */
+#[allow(non_snake_case)]
+fn emap(u: &BIG, cb: isize) -> ECP {
+ let mut P: ECP;
+ let mut x = BIG::new_copy(u);
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ x.rmod(&mut p);
+ loop {
+ P = ECP::new_bigint(&x, cb);
+ if !P.is_infinity() {
+ break;
+ }
+ x.inc(1);
+ x.norm();
+ }
+ return P;
+}
+
+/* returns u derived from P. Random value in range 1 to return value should then be added to u */
+#[allow(non_snake_case)]
+fn unmap(u: &mut BIG, P: &mut ECP) -> isize {
+ let s = P.gets();
+ let mut R: ECP;
+ let mut r = 0;
+ let x = P.getx();
+ u.copy(&x);
+ loop {
+ u.dec(1);
+ u.norm();
+ r += 1;
+ R = ECP::new_bigint(u, s);
+ if !R.is_infinity() {
+ break;
+ }
+ }
+ return r as isize;
+}
+
+pub fn hash_id(sha: usize, id: &[u8], w: &mut [u8]) -> bool {
+ return hashit(sha, 0, id, w);
+}
+
+/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */
+/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */
+/* Note that u and v are indistinguisible from random strings */
+#[allow(non_snake_case)]
+pub fn encoding(rng: &mut RAND, e: &mut [u8]) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+
+ for i in 0..EFS {
+ t[i] = e[i + 1]
+ }
+ let mut u = BIG::frombytes(&t);
+ for i in 0..EFS {
+ t[i] = e[i + EFS + 1]
+ }
+ let mut v = BIG::frombytes(&t);
+
+ let mut P = ECP::new_bigs(&u, &v);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let p = BIG::new_ints(&rom::MODULUS);
+ u = BIG::randomnum(&p, rng);
+
+ let mut su = rng.getbyte() as isize;
+ su %= 2;
+
+ let mut W = emap(&mut u, su);
+ P.sub(&mut W);
+ let sv = P.gets();
+ let rn = unmap(&mut v, &mut P);
+ let mut m = rng.getbyte() as isize;
+ m %= rn;
+ v.inc(m + 1);
+ e[0] = (su + 2 * sv) as u8;
+ u.tobytes(&mut t);
+ for i in 0..EFS {
+ e[i + 1] = t[i]
+ }
+ v.tobytes(&mut t);
+ for i in 0..EFS {
+ e[i + EFS + 1] = t[i]
+ }
+
+ return 0;
+}
+
+#[allow(non_snake_case)]
+pub fn decoding(d: &mut [u8]) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+
+ if (d[0] & 0x04) != 0 {
+ return INVALID_POINT;
+ }
+
+ for i in 0..EFS {
+ t[i] = d[i + 1]
+ }
+ let mut u = BIG::frombytes(&t);
+ for i in 0..EFS {
+ t[i] = d[i + EFS + 1]
+ }
+ let mut v = BIG::frombytes(&t);
+
+ let su = (d[0] & 1) as isize;
+ let sv = ((d[0] >> 1) & 1) as isize;
+ let mut W = emap(&mut u, su);
+ let mut P = emap(&mut v, sv);
+ P.add(&mut W);
+ u = P.getx();
+ v = P.gety();
+ d[0] = 0x04;
+ u.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i + 1] = t[i]
+ }
+ v.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i + EFS + 1] = t[i]
+ }
+
+ return 0;
+}
+
+/* R=R1+R2 in group G1 */
+#[allow(non_snake_case)]
+pub fn recombine_g1(r1: &[u8], r2: &[u8], r: &mut [u8]) -> isize {
+ let mut P = ECP::frombytes(&r1);
+ let mut Q = ECP::frombytes(&r2);
+
+ if P.is_infinity() || Q.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P.add(&mut Q);
+
+ P.tobytes(r, false);
+ return 0;
+}
+
+/* W=W1+W2 in group G2 */
+#[allow(non_snake_case)]
+pub fn recombine_g2(w1: &[u8], w2: &[u8], w: &mut [u8]) -> isize {
+ let mut P = ECP4::frombytes(&w1);
+ let mut Q = ECP4::frombytes(&w2);
+
+ if P.is_infinity() || Q.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P.add(&mut Q);
+
+ P.tobytes(w);
+ return 0;
+}
+
+/* create random secret S */
+pub fn random_generate(rng: &mut RAND, s: &mut [u8]) -> isize {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut sc = BIG::randomnum(&r, rng);
+ sc.tobytes(s);
+ return 0;
+}
+
+/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */
+#[allow(non_snake_case)]
+pub fn get_server_secret(s: &[u8], sst: &mut [u8]) -> isize {
+ let mut Q = ECP4::generator();
+ let mut sc = BIG::frombytes(s);
+ Q = pair192::g2mul(&mut Q, &mut sc);
+ Q.tobytes(sst);
+ return 0;
+}
+
+/*
+ W=x*H(G);
+ if RNG == NULL then X is passed in
+ if RNG != NULL the X is passed out
+ if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve
+*/
+#[allow(non_snake_case)]
+pub fn get_g1_multiple(
+ rng: Option<&mut RAND>,
+ typ: usize,
+ x: &mut [u8],
+ g: &[u8],
+ w: &mut [u8],
+) -> isize {
+ let mut sx: BIG;
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ if let Some(rd) = rng {
+ sx = BIG::randomnum(&r, rd);
+ sx.tobytes(x);
+ } else {
+ sx = BIG::frombytes(x);
+ }
+ let mut P: ECP;
+
+ if typ == 0 {
+ P = ECP::frombytes(g);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ } else {
+ P = ECP::mapit(g)
+ }
+
+ pair192::g1mul(&mut P, &mut sx).tobytes(w, false);
+ return 0;
+}
+
+/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */
+/* CID is hashed externally */
+pub fn get_client_secret(s: &mut [u8], cid: &[u8], cst: &mut [u8]) -> isize {
+ return get_g1_multiple(None, 1, s, cid, cst);
+}
+
+/* Extract PIN from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_pin(sha: usize, cid: &[u8], pin: i32, token: &mut [u8]) -> isize {
+ return extract_factor(sha, cid, pin % MAXPIN, PBLEN, token);
+}
+
+/* Extract factor from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_factor(
+ sha: usize,
+ cid: &[u8],
+ factor: i32,
+ facbits: i32,
+ token: &mut [u8],
+) -> isize {
+ let mut P = ECP::frombytes(&token);
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ hashit(sha, 0, cid, &mut h);
+ let mut R = ECP::mapit(&h);
+
+ R = R.pinmul(factor, facbits);
+ P.sub(&mut R);
+
+ P.tobytes(token, false);
+
+ return 0;
+}
+
+/* Restore factor to TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn restore_factor(
+ sha: usize,
+ cid: &[u8],
+ factor: i32,
+ facbits: i32,
+ token: &mut [u8],
+) -> isize {
+ let mut P = ECP::frombytes(&token);
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ hashit(sha, 0, cid, &mut h);
+ let mut R = ECP::mapit(&h);
+
+ R = R.pinmul(factor, facbits);
+ P.add(&mut R);
+
+ P.tobytes(token, false);
+
+ return 0;
+}
+
+/* Functions to support M-Pin Full */
+#[allow(non_snake_case)]
+pub fn precompute(token: &[u8], cid: &[u8], g1: &mut [u8], g2: &mut [u8]) -> isize {
+ let T = ECP::frombytes(&token);
+ if T.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let P = ECP::mapit(&cid);
+
+ let Q = ECP4::generator();
+
+ let mut g = pair192::ate(&Q, &T);
+ g = pair192::fexp(&g);
+ g.tobytes(g1);
+
+ g = pair192::ate(&Q, &P);
+ g = pair192::fexp(&g);
+ g.tobytes(g2);
+
+ return 0;
+}
+
+/* Time Permit CTT=S*(date|H(CID)) where S is master secret */
+#[allow(non_snake_case)]
+pub fn get_client_permit(sha: usize, date: usize, s: &[u8], cid: &[u8], ctt: &mut [u8]) -> isize {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ hashit(sha, date, cid, &mut h);
+ let mut P = ECP::mapit(&h);
+
+ let mut sc = BIG::frombytes(s);
+ pair192::g1mul(&mut P, &mut sc).tobytes(ctt, false);
+ return 0;
+}
+
+/* Implement step 1 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_1(
+ sha: usize,
+ date: usize,
+ client_id: &[u8],
+ rng: Option<&mut RAND>,
+ x: &mut [u8],
+ pin: usize,
+ token: &[u8],
+ sec: &mut [u8],
+ xid: Option<&mut [u8]>,
+ xcid: Option<&mut [u8]>,
+ permit: Option<&[u8]>,
+) -> isize {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ let mut sx: BIG;
+
+ if let Some(rd) = rng {
+ sx = BIG::randomnum(&r, rd);
+ sx.tobytes(x);
+ } else {
+ sx = BIG::frombytes(x);
+ }
+
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, 0, &client_id, &mut h);
+ let mut P = ECP::mapit(&h);
+
+ let mut T = ECP::frombytes(&token);
+ if T.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut W = P.pinmul((pin as i32) % MAXPIN, PBLEN);
+ T.add(&mut W);
+ if date != 0 {
+ if let Some(rpermit) = permit {
+ W = ECP::frombytes(&rpermit);
+ }
+ if W.is_infinity() {
+ return INVALID_POINT;
+ }
+ T.add(&mut W);
+ let mut h2: [u8; RM] = [0; RM];
+ hashit(sha, date, &h, &mut h2);
+ W = ECP::mapit(&h2);
+ if let Some(mut rxid) = xid {
+ P = pair192::g1mul(&mut P, &mut sx);
+ P.tobytes(&mut rxid, false);
+ W = pair192::g1mul(&mut W, &mut sx);
+ P.add(&mut W);
+ } else {
+ P.add(&mut W);
+ P = pair192::g1mul(&mut P, &mut sx);
+ }
+ if let Some(mut rxcid) = xcid {
+ P.tobytes(&mut rxcid, false)
+ }
+ } else {
+ if let Some(mut rxid) = xid {
+ P = pair192::g1mul(&mut P, &mut sx);
+ P.tobytes(&mut rxid, false);
+ }
+ }
+
+ T.tobytes(sec, false);
+ return 0;
+}
+
+/* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set HID=HTID */
+#[allow(non_snake_case)]
+pub fn server_1(sha: usize, date: usize, cid: &[u8], hid: &mut [u8], htid: Option<&mut [u8]>) {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, 0, cid, &mut h);
+
+ let mut P = ECP::mapit(&h);
+
+ P.tobytes(hid, false);
+ if date != 0 {
+ let mut h2: [u8; RM] = [0; RM];
+ hashit(sha, date, &h, &mut h2);
+ let mut R = ECP::mapit(&h2);
+ P.add(&mut R);
+ if let Some(rhtid) = htid {
+ P.tobytes(rhtid, false);
+ }
+ }
+}
+
+/* Implement step 2 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_2(x: &[u8], y: &[u8], sec: &mut [u8]) -> isize {
+ let mut r = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut P = ECP::frombytes(sec);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut px = BIG::frombytes(x);
+ let py = BIG::frombytes(y);
+ px.add(&py);
+ px.rmod(&mut r);
+
+ P = pair192::g1mul(&mut P, &mut px);
+ P.neg();
+ P.tobytes(sec, false);
+
+ return 0;
+}
+
+/* return time since epoch */
+pub fn get_time() -> usize {
+ return (SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs()) as usize;
+}
+
+/* Generate Y = H(epoch, xCID/xID) */
+pub fn get_y(sha: usize, timevalue: usize, xcid: &[u8], y: &mut [u8]) {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, timevalue, xcid, &mut h);
+
+ let mut sy = BIG::frombytes(&h);
+ let mut q = BIG::new_ints(&rom::CURVE_ORDER);
+ sy.rmod(&mut q);
+ sy.tobytes(y);
+}
+
+/* Implement step 2 of MPin protocol on server side */
+#[allow(non_snake_case)]
+pub fn server_2(
+ date: usize,
+ hid: &[u8],
+ htid: Option<&[u8]>,
+ y: &[u8],
+ sst: &[u8],
+ xid: Option<&[u8]>,
+ xcid: Option<&[u8]>,
+ msec: &[u8],
+ e: Option<&mut [u8]>,
+ f: Option<&mut [u8]>,
+) -> isize {
+ let Q = ECP4::generator();
+
+ let sQ = ECP4::frombytes(&sst);
+ if sQ.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut R: ECP;
+ if date != 0 {
+ if let Some(rxcid) = xcid {
+ R = ECP::frombytes(&rxcid);
+ } else {
+ return BAD_PARAMS;
+ }
+ } else {
+ if let Some(rxid) = xid {
+ R = ECP::frombytes(&rxid)
+ } else {
+ return BAD_PARAMS;
+ }
+ }
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut sy = BIG::frombytes(&y);
+ let mut P: ECP;
+ if date != 0 {
+ if let Some(rhtid) = htid {
+ P = ECP::frombytes(&rhtid)
+ } else {
+ return BAD_PARAMS;
+ }
+ } else {
+ P = ECP::frombytes(&hid);
+ }
+
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P = pair192::g1mul(&mut P, &mut sy);
+ P.add(&mut R);
+ R = ECP::frombytes(&msec);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut g: FP24;
+
+ g = pair192::ate2(&Q, &R, &sQ, &P);
+ g = pair192::fexp(&g);
+
+ if !g.isunity() {
+ if let Some(rxid) = xid {
+ if let Some(re) = e {
+ if let Some(rf) = f {
+ g.tobytes(re);
+ if date != 0 {
+ P = ECP::frombytes(&hid);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ R = ECP::frombytes(&rxid);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+ P = pair192::g1mul(&mut P, &mut sy);
+ P.add(&mut R); //P.affine();
+ }
+ g = pair192::ate(&Q, &P);
+ g = pair192::fexp(&g);
+ g.tobytes(rf);
+ }
+ }
+ }
+
+ return BAD_PIN;
+ }
+
+ return 0;
+}
+
+/* Pollards kangaroos used to return PIN error */
+pub fn kangaroo(e: &[u8], f: &[u8]) -> isize {
+ let mut ge = FP24::frombytes(e);
+ let mut gf = FP24::frombytes(f);
+ let mut distance: [isize; TS] = [0; TS];
+ let mut t = FP24::new_copy(&gf);
+
+ let mut table: [FP24; TS] = [FP24::new(); TS];
+ let mut s: isize = 1;
+ for m in 0..TS {
+ distance[m] = s;
+ table[m] = FP24::new_copy(&t);
+ s *= 2;
+ t.usqr();
+ }
+ t.one();
+ let mut dn: isize = 0;
+ let mut i: usize;
+ for _ in 0..TRAP {
+ i = (t.geta().geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
+ t.mul(&mut table[i]);
+ dn += distance[i];
+ }
+ gf.copy(&t);
+ gf.conj();
+ let mut steps: usize = 0;
+ let mut dm: isize = 0;
+ let mut res: isize = 0;
+ while dm - dn < MAXPIN as isize {
+ steps += 1;
+ if steps > 4 * TRAP {
+ break;
+ }
+ i = (ge.geta().geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
+ ge.mul(&mut table[i]);
+ dm += distance[i];
+ if ge.equals(&mut t) {
+ res = dm - dn;
+ break;
+ }
+ if ge.equals(&mut gf) {
+ res = dn - dm;
+ break;
+ }
+ }
+ if steps > 4 * TRAP || dm - dn >= MAXPIN as isize {
+ res = 0
+ } // Trap Failed - probable invalid token
+ return res;
+}
+
+/* Hash the M-Pin transcript - new */
+
+pub fn hash_all(
+ sha: usize,
+ hid: &[u8],
+ xid: &[u8],
+ xcid: Option<&[u8]>,
+ sec: &[u8],
+ y: &[u8],
+ r: &[u8],
+ w: &[u8],
+ h: &mut [u8],
+) -> bool {
+ let mut tlen: usize = 0;
+ const RM: usize = big::MODBYTES as usize;
+ let mut t: [u8; 10 * RM + 4] = [0; 10 * RM + 4];
+
+ for i in 0..hid.len() {
+ t[i] = hid[i]
+ }
+ tlen += hid.len();
+
+ if let Some(rxcid) = xcid {
+ for i in 0..rxcid.len() {
+ t[i + tlen] = rxcid[i]
+ }
+ tlen += rxcid.len();
+ } else {
+ for i in 0..xid.len() {
+ t[i + tlen] = xid[i]
+ }
+ tlen += xid.len();
+ }
+
+ for i in 0..sec.len() {
+ t[i + tlen] = sec[i]
+ }
+ tlen += sec.len();
+ for i in 0..y.len() {
+ t[i + tlen] = y[i]
+ }
+ tlen += y.len();
+ for i in 0..r.len() {
+ t[i + tlen] = r[i]
+ }
+ tlen += r.len();
+ for i in 0..w.len() {
+ t[i + tlen] = w[i]
+ }
+ tlen += w.len();
+ if tlen != 10 * RM + 4 {
+ return false;
+ }
+
+ return hashit(sha, 0, &t, h);
+}
+
+/* calculate common key on client side */
+/* wCID = w.(A+AT) */
+#[allow(non_snake_case)]
+pub fn client_key(
+ sha: usize,
+ g1: &[u8],
+ g2: &[u8],
+ pin: usize,
+ r: &[u8],
+ x: &[u8],
+ h: &[u8],
+ wcid: &[u8],
+ ck: &mut [u8],
+) -> isize {
+ let mut g1 = FP24::frombytes(&g1);
+ let mut g2 = FP24::frombytes(&g2);
+ let mut z = BIG::frombytes(&r);
+ let mut x = BIG::frombytes(&x);
+ let h = BIG::frombytes(&h);
+
+ let mut W = ECP::frombytes(&wcid);
+ if W.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ W = pair192::g1mul(&mut W, &mut x);
+
+ let mut r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ z.add(&h); //new
+ z.rmod(&mut r);
+
+ g2.pinpow(pin as i32, PBLEN);
+ g1.mul(&mut g2);
+
+ let mut c = g1.compow(&z, &mut r);
+
+ hash(sha, &mut c, &mut W, ck);
+
+ return 0;
+}
+
+/* calculate common key on server side */
+/* Z=r.A - no time permits involved */
+#[allow(non_snake_case)]
+pub fn server_key(
+ sha: usize,
+ z: &[u8],
+ sst: &[u8],
+ w: &[u8],
+ h: &[u8],
+ hid: &[u8],
+ xid: &[u8],
+ xcid: Option<&[u8]>,
+ sk: &mut [u8],
+) -> isize {
+ let sQ = ECP4::frombytes(&sst);
+ if sQ.is_infinity() {
+ return INVALID_POINT;
+ }
+ let mut R = ECP::frombytes(&z);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+ let mut A = ECP::frombytes(&hid);
+ if A.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut U = ECP::new();
+ if let Some(rxcid) = xcid {
+ U.copy(&ECP::frombytes(&rxcid));
+ } else {
+ U.copy(&ECP::frombytes(&xid));
+ }
+
+ if U.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut w = BIG::frombytes(&w);
+ let mut h = BIG::frombytes(&h);
+ A = pair192::g1mul(&mut A, &mut h); // new
+ R.add(&mut A);
+
+ U = pair192::g1mul(&mut U, &mut w);
+ let mut g = pair192::ate(&sQ, &R);
+ g = pair192::fexp(&g);
+
+ let mut c = g.trace();
+
+ hash(sha, &mut c, &mut U, sk);
+
+ return 0;
+}
diff --git a/src/mpin256.rs b/src/mpin256.rs
new file mode 100644
index 0000000..b4928e9
--- /dev/null
+++ b/src/mpin256.rs
@@ -0,0 +1,993 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use std::time::SystemTime;
+use std::time::UNIX_EPOCH;
+
+use super::ecp;
+use super::ecp::ECP;
+use super::ecp8::ECP8;
+use super::fp16::FP16;
+use super::fp48::FP48;
+use super::big::BIG;
+use super::pair256;
+use super::big;
+use super::rom;
+
+use rand::RAND;
+use hash256::HASH256;
+use hash384::HASH384;
+use hash512::HASH512;
+
+/* MPIN API Functions */
+
+/* Configure mode of operation */
+
+pub const EFS: usize = big::MODBYTES as usize;
+pub const EGS: usize = big::MODBYTES as usize;
+pub const BAD_PARAMS: isize = -11;
+pub const INVALID_POINT: isize = -14;
+pub const WRONG_ORDER: isize = -18;
+pub const BAD_PIN: isize = -19;
+pub const SHA256: usize = 32;
+pub const SHA384: usize = 48;
+pub const SHA512: usize = 64;
+
+/* Configure your PIN here */
+
+pub const MAXPIN: i32 = 10000; /* PIN less than this */
+pub const PBLEN: i32 = 14; /* Number of bits in PIN */
+pub const TS: usize = 10; /* 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */
+pub const TRAP: usize = 200; /* 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) */
+
+#[allow(non_snake_case)]
+fn hash(sha: usize, c: &mut FP16, U: &mut ECP, r: &mut [u8]) -> bool {
+ let mut w: [u8; EFS] = [0; EFS];
+ let mut t: [u8; 18 * EFS] = [0; 18 * EFS];
+
+ c.geta().geta().geta().geta().tobytes(&mut w);
+ for i in 0..EFS {
+ t[i] = w[i]
+ }
+ c.geta().geta().geta().getb().tobytes(&mut w);
+ for i in EFS..2 * EFS {
+ t[i] = w[i - EFS]
+ }
+ c.geta().geta().getb().geta().tobytes(&mut w);
+ for i in 2 * EFS..3 * EFS {
+ t[i] = w[i - 2 * EFS]
+ }
+ c.geta().geta().getb().getb().tobytes(&mut w);
+ for i in 3 * EFS..4 * EFS {
+ t[i] = w[i - 3 * EFS]
+ }
+ c.geta().getb().geta().geta().tobytes(&mut w);
+ for i in 4 * EFS..5 * EFS {
+ t[i] = w[i - 4 * EFS]
+ }
+ c.geta().getb().geta().getb().tobytes(&mut w);
+ for i in 5 * EFS..6 * EFS {
+ t[i] = w[i - 5 * EFS]
+ }
+ c.geta().getb().getb().geta().tobytes(&mut w);
+ for i in 6 * EFS..7 * EFS {
+ t[i] = w[i - 6 * EFS]
+ }
+ c.geta().getb().getb().getb().tobytes(&mut w);
+ for i in 7 * EFS..8 * EFS {
+ t[i] = w[i - 7 * EFS]
+ }
+
+ c.getb().geta().geta().geta().tobytes(&mut w);
+ for i in 8 * EFS..9 * EFS {
+ t[i] = w[i - 8 * EFS]
+ }
+ c.getb().geta().geta().getb().tobytes(&mut w);
+ for i in 9 * EFS..10 * EFS {
+ t[i] = w[i - 9 * EFS]
+ }
+ c.getb().geta().getb().geta().tobytes(&mut w);
+ for i in 10 * EFS..11 * EFS {
+ t[i] = w[i - 10 * EFS]
+ }
+ c.getb().geta().getb().getb().tobytes(&mut w);
+ for i in 11 * EFS..12 * EFS {
+ t[i] = w[i - 11 * EFS]
+ }
+ c.getb().getb().geta().geta().tobytes(&mut w);
+ for i in 12 * EFS..13 * EFS {
+ t[i] = w[i - 12 * EFS]
+ }
+ c.getb().getb().geta().getb().tobytes(&mut w);
+ for i in 13 * EFS..14 * EFS {
+ t[i] = w[i - 13 * EFS]
+ }
+ c.getb().getb().getb().geta().tobytes(&mut w);
+ for i in 14 * EFS..15 * EFS {
+ t[i] = w[i - 14 * EFS]
+ }
+ c.getb().getb().getb().getb().tobytes(&mut w);
+ for i in 15 * EFS..16 * EFS {
+ t[i] = w[i - 15 * EFS]
+ }
+
+ U.getx().tobytes(&mut w);
+ for i in 16 * EFS..17 * EFS {
+ t[i] = w[i - 16 * EFS]
+ }
+ U.gety().tobytes(&mut w);
+ for i in 17 * EFS..18 * EFS {
+ t[i] = w[i - 17 * EFS]
+ }
+
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ h.process_array(&t);
+ let sh = h.hash();
+ for i in 0..ecp::AESKEY {
+ r[i] = sh[i]
+ }
+ return true;
+ }
+ return false;
+}
+
+/* Hash number (optional) and string to point on curve */
+
+fn hashit(sha: usize, n: usize, id: &[u8], w: &mut [u8]) -> bool {
+ let mut r: [u8; 64] = [0; 64];
+ let mut didit = false;
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ if n > 0 {
+ h.process_num(n as i32)
+ }
+ h.process_array(id);
+ let hs = h.hash();
+ for i in 0..sha {
+ r[i] = hs[i];
+ }
+ didit = true;
+ }
+ if !didit {
+ return false;
+ }
+
+ let rm = big::MODBYTES as usize;
+
+ if sha > rm {
+ for i in 0..rm {
+ w[i] = r[i]
+ }
+ } else {
+ for i in 0..sha {
+ w[i + rm - sha] = r[i]
+ }
+ for i in 0..(rm - sha) {
+ w[i] = 0
+ }
+ }
+
+ return true;
+}
+
+/* return time in slots since epoch */
+pub fn today() -> usize {
+ return (SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs()
+ / (60 * 1440)) as usize;
+}
+
+/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */
+/* maps a random u to a point on the curve */
+#[allow(non_snake_case)]
+fn emap(u: &BIG, cb: isize) -> ECP {
+ let mut P: ECP;
+ let mut x = BIG::new_copy(u);
+ let mut p = BIG::new_ints(&rom::MODULUS);
+ x.rmod(&mut p);
+ loop {
+ P = ECP::new_bigint(&x, cb);
+ if !P.is_infinity() {
+ break;
+ }
+ x.inc(1);
+ x.norm();
+ }
+ return P;
+}
+
+/* returns u derived from P. Random value in range 1 to return value should then be added to u */
+#[allow(non_snake_case)]
+fn unmap(u: &mut BIG, P: &mut ECP) -> isize {
+ let s = P.gets();
+ let mut R: ECP;
+ let mut r = 0;
+ let x = P.getx();
+ u.copy(&x);
+ loop {
+ u.dec(1);
+ u.norm();
+ r += 1;
+ R = ECP::new_bigint(u, s);
+ if !R.is_infinity() {
+ break;
+ }
+ }
+ return r as isize;
+}
+
+pub fn hash_id(sha: usize, id: &[u8], w: &mut [u8]) -> bool {
+ return hashit(sha, 0, id, w);
+}
+
+/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */
+/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */
+/* Note that u and v are indistinguisible from random strings */
+#[allow(non_snake_case)]
+pub fn encoding(rng: &mut RAND, e: &mut [u8]) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+
+ for i in 0..EFS {
+ t[i] = e[i + 1]
+ }
+ let mut u = BIG::frombytes(&t);
+ for i in 0..EFS {
+ t[i] = e[i + EFS + 1]
+ }
+ let mut v = BIG::frombytes(&t);
+
+ let mut P = ECP::new_bigs(&u, &v);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let p = BIG::new_ints(&rom::MODULUS);
+ u = BIG::randomnum(&p, rng);
+
+ let mut su = rng.getbyte() as isize;
+ su %= 2;
+
+ let mut W = emap(&mut u, su);
+ P.sub(&mut W);
+ let sv = P.gets();
+ let rn = unmap(&mut v, &mut P);
+ let mut m = rng.getbyte() as isize;
+ m %= rn;
+ v.inc(m + 1);
+ e[0] = (su + 2 * sv) as u8;
+ u.tobytes(&mut t);
+ for i in 0..EFS {
+ e[i + 1] = t[i]
+ }
+ v.tobytes(&mut t);
+ for i in 0..EFS {
+ e[i + EFS + 1] = t[i]
+ }
+
+ return 0;
+}
+
+#[allow(non_snake_case)]
+pub fn decoding(d: &mut [u8]) -> isize {
+ let mut t: [u8; EFS] = [0; EFS];
+
+ if (d[0] & 0x04) != 0 {
+ return INVALID_POINT;
+ }
+
+ for i in 0..EFS {
+ t[i] = d[i + 1]
+ }
+ let mut u = BIG::frombytes(&t);
+ for i in 0..EFS {
+ t[i] = d[i + EFS + 1]
+ }
+ let mut v = BIG::frombytes(&t);
+
+ let su = (d[0] & 1) as isize;
+ let sv = ((d[0] >> 1) & 1) as isize;
+ let mut W = emap(&mut u, su);
+ let mut P = emap(&mut v, sv);
+ P.add(&mut W);
+ u = P.getx();
+ v = P.gety();
+ d[0] = 0x04;
+ u.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i + 1] = t[i]
+ }
+ v.tobytes(&mut t);
+ for i in 0..EFS {
+ d[i + EFS + 1] = t[i]
+ }
+
+ return 0;
+}
+
+/* R=R1+R2 in group G1 */
+#[allow(non_snake_case)]
+pub fn recombine_g1(r1: &[u8], r2: &[u8], r: &mut [u8]) -> isize {
+ let mut P = ECP::frombytes(&r1);
+ let mut Q = ECP::frombytes(&r2);
+
+ if P.is_infinity() || Q.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P.add(&mut Q);
+
+ P.tobytes(r, false);
+ return 0;
+}
+
+/* W=W1+W2 in group G2 */
+#[allow(non_snake_case)]
+pub fn recombine_g2(w1: &[u8], w2: &[u8], w: &mut [u8]) -> isize {
+ let mut P = ECP8::frombytes(&w1);
+ let mut Q = ECP8::frombytes(&w2);
+
+ if P.is_infinity() || Q.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P.add(&mut Q);
+
+ P.tobytes(w);
+ return 0;
+}
+
+/* create random secret S */
+pub fn random_generate(rng: &mut RAND, s: &mut [u8]) -> isize {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut sc = BIG::randomnum(&r, rng);
+ sc.tobytes(s);
+ return 0;
+}
+
+/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */
+#[allow(non_snake_case)]
+pub fn get_server_secret(s: &[u8], sst: &mut [u8]) -> isize {
+ let mut Q = ECP8::generator();
+
+ let mut sc = BIG::frombytes(s);
+ Q = pair256::g2mul(&mut Q, &mut sc);
+ Q.tobytes(sst);
+ return 0;
+}
+
+/*
+ W=x*H(G);
+ if RNG == NULL then X is passed in
+ if RNG != NULL the X is passed out
+ if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve
+*/
+#[allow(non_snake_case)]
+pub fn get_g1_multiple(
+ rng: Option<&mut RAND>,
+ typ: usize,
+ x: &mut [u8],
+ g: &[u8],
+ w: &mut [u8],
+) -> isize {
+ let mut sx: BIG;
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ if let Some(rd) = rng {
+ sx = BIG::randomnum(&r, rd);
+ sx.tobytes(x);
+ } else {
+ sx = BIG::frombytes(x);
+ }
+ let mut P: ECP;
+
+ if typ == 0 {
+ P = ECP::frombytes(g);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ } else {
+ P = ECP::mapit(g)
+ }
+
+ pair256::g1mul(&mut P, &mut sx).tobytes(w, false);
+ return 0;
+}
+
+/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */
+/* CID is hashed externally */
+pub fn get_client_secret(s: &mut [u8], cid: &[u8], cst: &mut [u8]) -> isize {
+ return get_g1_multiple(None, 1, s, cid, cst);
+}
+
+/* Extract PIN from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_pin(sha: usize, cid: &[u8], pin: i32, token: &mut [u8]) -> isize {
+ return extract_factor(sha, cid, pin % MAXPIN, PBLEN, token);
+}
+
+/* Extract factor from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_factor(
+ sha: usize,
+ cid: &[u8],
+ factor: i32,
+ facbits: i32,
+ token: &mut [u8],
+) -> isize {
+ let mut P = ECP::frombytes(&token);
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ hashit(sha, 0, cid, &mut h);
+ let mut R = ECP::mapit(&h);
+
+ R = R.pinmul(factor, facbits);
+ P.sub(&mut R);
+
+ P.tobytes(token, false);
+
+ return 0;
+}
+
+/* Restore factor to TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn restore_factor(
+ sha: usize,
+ cid: &[u8],
+ factor: i32,
+ facbits: i32,
+ token: &mut [u8],
+) -> isize {
+ let mut P = ECP::frombytes(&token);
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ hashit(sha, 0, cid, &mut h);
+ let mut R = ECP::mapit(&h);
+
+ R = R.pinmul(factor, facbits);
+ P.add(&mut R);
+
+ P.tobytes(token, false);
+
+ return 0;
+}
+
+/* Functions to support M-Pin Full */
+#[allow(non_snake_case)]
+pub fn precompute(token: &[u8], cid: &[u8], g1: &mut [u8], g2: &mut [u8]) -> isize {
+ let T = ECP::frombytes(&token);
+ if T.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let P = ECP::mapit(&cid);
+
+ let Q = ECP8::generator();
+
+ let mut g = pair256::ate(&Q, &T);
+ g = pair256::fexp(&g);
+ g.tobytes(g1);
+
+ g = pair256::ate(&Q, &P);
+ g = pair256::fexp(&g);
+ g.tobytes(g2);
+
+ return 0;
+}
+
+/* Time Permit CTT=S*(date|H(CID)) where S is master secret */
+#[allow(non_snake_case)]
+pub fn get_client_permit(sha: usize, date: usize, s: &[u8], cid: &[u8], ctt: &mut [u8]) -> isize {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+ hashit(sha, date, cid, &mut h);
+ let mut P = ECP::mapit(&h);
+
+ let mut sc = BIG::frombytes(s);
+ pair256::g1mul(&mut P, &mut sc).tobytes(ctt, false);
+ return 0;
+}
+
+/* Implement step 1 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_1(
+ sha: usize,
+ date: usize,
+ client_id: &[u8],
+ rng: Option<&mut RAND>,
+ x: &mut [u8],
+ pin: usize,
+ token: &[u8],
+ sec: &mut [u8],
+ xid: Option<&mut [u8]>,
+ xcid: Option<&mut [u8]>,
+ permit: Option<&[u8]>,
+) -> isize {
+ let r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ let mut sx: BIG;
+
+ if let Some(rd) = rng {
+ sx = BIG::randomnum(&r, rd);
+ sx.tobytes(x);
+ } else {
+ sx = BIG::frombytes(x);
+ }
+
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, 0, &client_id, &mut h);
+ let mut P = ECP::mapit(&h);
+
+ let mut T = ECP::frombytes(&token);
+ if T.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut W = P.pinmul((pin as i32) % MAXPIN, PBLEN);
+ T.add(&mut W);
+ if date != 0 {
+ if let Some(rpermit) = permit {
+ W = ECP::frombytes(&rpermit);
+ }
+ if W.is_infinity() {
+ return INVALID_POINT;
+ }
+ T.add(&mut W);
+ let mut h2: [u8; RM] = [0; RM];
+ hashit(sha, date, &h, &mut h2);
+ W = ECP::mapit(&h2);
+ if let Some(mut rxid) = xid {
+ P = pair256::g1mul(&mut P, &mut sx);
+ P.tobytes(&mut rxid, false);
+ W = pair256::g1mul(&mut W, &mut sx);
+ P.add(&mut W);
+ } else {
+ P.add(&mut W);
+ P = pair256::g1mul(&mut P, &mut sx);
+ }
+ if let Some(mut rxcid) = xcid {
+ P.tobytes(&mut rxcid, false)
+ }
+ } else {
+ if let Some(mut rxid) = xid {
+ P = pair256::g1mul(&mut P, &mut sx);
+ P.tobytes(&mut rxid, false);
+ }
+ }
+
+ T.tobytes(sec, false);
+ return 0;
+}
+
+/* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set HID=HTID */
+#[allow(non_snake_case)]
+pub fn server_1(sha: usize, date: usize, cid: &[u8], hid: &mut [u8], htid: Option<&mut [u8]>) {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, 0, cid, &mut h);
+
+ let mut P = ECP::mapit(&h);
+
+ P.tobytes(hid, false);
+ if date != 0 {
+ let mut h2: [u8; RM] = [0; RM];
+ hashit(sha, date, &h, &mut h2);
+ let mut R = ECP::mapit(&h2);
+ P.add(&mut R);
+ if let Some(rhtid) = htid {
+ P.tobytes(rhtid, false);
+ }
+ }
+}
+
+/* Implement step 2 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_2(x: &[u8], y: &[u8], sec: &mut [u8]) -> isize {
+ let mut r = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut P = ECP::frombytes(sec);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut px = BIG::frombytes(x);
+ let py = BIG::frombytes(y);
+ px.add(&py);
+ px.rmod(&mut r);
+
+ P = pair256::g1mul(&mut P, &mut px);
+ P.neg();
+ P.tobytes(sec, false);
+
+ return 0;
+}
+
+/* return time since epoch */
+pub fn get_time() -> usize {
+ return (SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs()) as usize;
+}
+
+/* Generate Y = H(epoch, xCID/xID) */
+pub fn get_y(sha: usize, timevalue: usize, xcid: &[u8], y: &mut [u8]) {
+ const RM: usize = big::MODBYTES as usize;
+ let mut h: [u8; RM] = [0; RM];
+
+ hashit(sha, timevalue, xcid, &mut h);
+
+ let mut sy = BIG::frombytes(&h);
+ let mut q = BIG::new_ints(&rom::CURVE_ORDER);
+ sy.rmod(&mut q);
+ sy.tobytes(y);
+}
+
+/* Implement step 2 of MPin protocol on server side */
+#[allow(non_snake_case)]
+pub fn server_2(
+ date: usize,
+ hid: &[u8],
+ htid: Option<&[u8]>,
+ y: &[u8],
+ sst: &[u8],
+ xid: Option<&[u8]>,
+ xcid: Option<&[u8]>,
+ msec: &[u8],
+ e: Option<&mut [u8]>,
+ f: Option<&mut [u8]>,
+) -> isize {
+ let Q = ECP8::generator();
+
+ let sQ = ECP8::frombytes(&sst);
+ if sQ.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut R: ECP;
+ if date != 0 {
+ if let Some(rxcid) = xcid {
+ R = ECP::frombytes(&rxcid);
+ } else {
+ return BAD_PARAMS;
+ }
+ } else {
+ if let Some(rxid) = xid {
+ R = ECP::frombytes(&rxid)
+ } else {
+ return BAD_PARAMS;
+ }
+ }
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut sy = BIG::frombytes(&y);
+ let mut P: ECP;
+ if date != 0 {
+ if let Some(rhtid) = htid {
+ P = ECP::frombytes(&rhtid)
+ } else {
+ return BAD_PARAMS;
+ }
+ } else {
+ P = ECP::frombytes(&hid);
+ }
+
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ P = pair256::g1mul(&mut P, &mut sy);
+ P.add(&mut R);
+ R = ECP::frombytes(&msec);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut g: FP48;
+
+ g = pair256::ate2(&Q, &R, &sQ, &P);
+ g = pair256::fexp(&g);
+
+ if !g.isunity() {
+ if let Some(rxid) = xid {
+ if let Some(re) = e {
+ if let Some(rf) = f {
+ g.tobytes(re);
+ if date != 0 {
+ P = ECP::frombytes(&hid);
+ if P.is_infinity() {
+ return INVALID_POINT;
+ }
+ R = ECP::frombytes(&rxid);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+ P = pair256::g1mul(&mut P, &mut sy);
+ P.add(&mut R); //P.affine();
+ }
+ g = pair256::ate(&Q, &P);
+ g = pair256::fexp(&g);
+ g.tobytes(rf);
+ }
+ }
+ }
+
+ return BAD_PIN;
+ }
+
+ return 0;
+}
+
+/* Pollards kangaroos used to return PIN error */
+pub fn kangaroo(e: &[u8], f: &[u8]) -> isize {
+ let mut ge = FP48::frombytes(e);
+ let mut gf = FP48::frombytes(f);
+ let mut distance: [isize; TS] = [0; TS];
+ let mut t = FP48::new_copy(&gf);
+
+ let mut table: [FP48; TS] = [FP48::new(); TS];
+ let mut s: isize = 1;
+ for m in 0..TS {
+ distance[m] = s;
+ table[m] = FP48::new_copy(&t);
+ s *= 2;
+ t.usqr();
+ }
+ t.one();
+ let mut dn: isize = 0;
+ let mut i: usize;
+ for _ in 0..TRAP {
+ i = (t.geta().geta().geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
+ t.mul(&mut table[i]);
+ dn += distance[i];
+ }
+ gf.copy(&t);
+ gf.conj();
+ let mut steps: usize = 0;
+ let mut dm: isize = 0;
+ let mut res: isize = 0;
+ while dm - dn < MAXPIN as isize {
+ steps += 1;
+ if steps > 4 * TRAP {
+ break;
+ }
+ i = (ge.geta().geta().geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
+ ge.mul(&mut table[i]);
+ dm += distance[i];
+ if ge.equals(&mut t) {
+ res = dm - dn;
+ break;
+ }
+ if ge.equals(&mut gf) {
+ res = dn - dm;
+ break;
+ }
+ }
+ if steps > 4 * TRAP || dm - dn >= MAXPIN as isize {
+ res = 0
+ } // Trap Failed - probable invalid token
+ return res;
+}
+
+/* Hash the M-Pin transcript - new */
+
+pub fn hash_all(
+ sha: usize,
+ hid: &[u8],
+ xid: &[u8],
+ xcid: Option<&[u8]>,
+ sec: &[u8],
+ y: &[u8],
+ r: &[u8],
+ w: &[u8],
+ h: &mut [u8],
+) -> bool {
+ let mut tlen: usize = 0;
+ const RM: usize = big::MODBYTES as usize;
+ let mut t: [u8; 10 * RM + 4] = [0; 10 * RM + 4];
+
+ for i in 0..hid.len() {
+ t[i] = hid[i]
+ }
+ tlen += hid.len();
+
+ if let Some(rxcid) = xcid {
+ for i in 0..rxcid.len() {
+ t[i + tlen] = rxcid[i]
+ }
+ tlen += rxcid.len();
+ } else {
+ for i in 0..xid.len() {
+ t[i + tlen] = xid[i]
+ }
+ tlen += xid.len();
+ }
+
+ for i in 0..sec.len() {
+ t[i + tlen] = sec[i]
+ }
+ tlen += sec.len();
+ for i in 0..y.len() {
+ t[i + tlen] = y[i]
+ }
+ tlen += y.len();
+ for i in 0..r.len() {
+ t[i + tlen] = r[i]
+ }
+ tlen += r.len();
+ for i in 0..w.len() {
+ t[i + tlen] = w[i]
+ }
+ tlen += w.len();
+ if tlen != 10 * RM + 4 {
+ return false;
+ }
+
+ return hashit(sha, 0, &t, h);
+}
+
+/* calculate common key on client side */
+/* wCID = w.(A+AT) */
+#[allow(non_snake_case)]
+pub fn client_key(
+ sha: usize,
+ g1: &[u8],
+ g2: &[u8],
+ pin: usize,
+ r: &[u8],
+ x: &[u8],
+ h: &[u8],
+ wcid: &[u8],
+ ck: &mut [u8],
+) -> isize {
+ let mut g1 = FP48::frombytes(&g1);
+ let mut g2 = FP48::frombytes(&g2);
+ let mut z = BIG::frombytes(&r);
+ let mut x = BIG::frombytes(&x);
+ let h = BIG::frombytes(&h);
+
+ let mut W = ECP::frombytes(&wcid);
+ if W.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ W = pair256::g1mul(&mut W, &mut x);
+
+ let mut r = BIG::new_ints(&rom::CURVE_ORDER);
+
+ z.add(&h); //new
+ z.rmod(&mut r);
+
+ g2.pinpow(pin as i32, PBLEN);
+ g1.mul(&mut g2);
+
+ let mut c = g1.compow(&z, &mut r);
+
+ hash(sha, &mut c, &mut W, ck);
+
+ return 0;
+}
+
+/* calculate common key on server side */
+/* Z=r.A - no time permits involved */
+#[allow(non_snake_case)]
+pub fn server_key(
+ sha: usize,
+ z: &[u8],
+ sst: &[u8],
+ w: &[u8],
+ h: &[u8],
+ hid: &[u8],
+ xid: &[u8],
+ xcid: Option<&[u8]>,
+ sk: &mut [u8],
+) -> isize {
+ let sQ = ECP8::frombytes(&sst);
+ if sQ.is_infinity() {
+ return INVALID_POINT;
+ }
+ let mut R = ECP::frombytes(&z);
+ if R.is_infinity() {
+ return INVALID_POINT;
+ }
+ let mut A = ECP::frombytes(&hid);
+ if A.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut U = ECP::new();
+ if let Some(rxcid) = xcid {
+ U.copy(&ECP::frombytes(&rxcid));
+ } else {
+ U.copy(&ECP::frombytes(&xid));
+ }
+
+ if U.is_infinity() {
+ return INVALID_POINT;
+ }
+
+ let mut w = BIG::frombytes(&w);
+ let mut h = BIG::frombytes(&h);
+ A = pair256::g1mul(&mut A, &mut h); // new
+ R.add(&mut A);
+
+ U = pair256::g1mul(&mut U, &mut w);
+ let mut g = pair256::ate(&sQ, &R);
+ g = pair256::fexp(&g);
+
+ let mut c = g.trace();
+
+ hash(sha, &mut c, &mut U, sk);
+
+ return 0;
+}
diff --git a/src/nhs.rs b/src/nhs.rs
new file mode 100644
index 0000000..7f2f605
--- /dev/null
+++ b/src/nhs.rs
@@ -0,0 +1,705 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* NewHope Simple API high-level functions */
+
+use crate::rand::RAND;
+use crate::sha3;
+use crate::sha3::SHA3;
+
+const PRIME: i32 = 0x3001; // q in Hex
+const LGN: usize = 10; // Degree n=2^LGN
+const ND: u32 = 0xF7002FFF; // 1/(R-q) mod R
+const ONE: i32 = 0x2AC8; // R mod q
+const R2MODP: u64 = 0x1620; // R^2 mod q
+
+const DEGREE: usize = (1 << LGN);
+const WL: usize = 32;
+
+const INV: i32 = 0xeab;
+const INVPR: i32 = 0x2c2a;
+
+const ROOTS: [i32; 1024] = [
+ 0x2ac8, 0x2baf, 0x299b, 0x685, 0x2f04, 0x158d, 0x2d49, 0x24b5, 0x1edc, 0xab3, 0x2a95, 0x24d,
+ 0x3cb, 0x6a8, 0x12f9, 0x15ba, 0x1861, 0x2a89, 0x1c5c, 0xbe6, 0xc1e, 0x2024, 0x207, 0x19ce,
+ 0x2710, 0x1744, 0x18bc, 0x2cd7, 0x396, 0x18d5, 0x1c45, 0xc4, 0x21a6, 0xe03, 0x2b3c, 0x2d91,
+ 0xc5d, 0x432, 0x1fbc, 0xcae, 0x2512, 0x2979, 0x3b2, 0x714, 0xb2e, 0x1a97, 0x1a03, 0x1bcd,
+ 0x2216, 0x2701, 0xa, 0x263c, 0x1179, 0x200c, 0x2d08, 0x1c34, 0x291, 0x2c99, 0x2a5a, 0x723,
+ 0xb1d, 0x1ccc, 0x1fb6, 0x2f58, 0x2bfe, 0x1cda, 0x2a0, 0x5f1, 0x2de, 0x1fc7, 0x1ea8, 0x1719,
+ 0x2fa7, 0x27ec, 0x20ff, 0x12c0, 0x1ac1, 0x2232, 0x2f9b, 0xd3e, 0x2aed, 0x15f0, 0x11e8, 0xed0,
+ 0x26a, 0x1de5, 0xa3f, 0xf43, 0xebf, 0x204e, 0xac7, 0x2d9c, 0x5ea, 0x25d1, 0xb6, 0x49c, 0x995,
+ 0x2555, 0x26e2, 0x100, 0x1878, 0x5aa, 0x2e10, 0x271c, 0xcb, 0x1b4c, 0x2fb8, 0x25b7, 0x1543,
+ 0x2c7b, 0x241a, 0x2223, 0x20ca, 0x24ed, 0x137, 0x1b65, 0x1dc2, 0x7c7, 0x2ec3, 0xd0c, 0x1169,
+ 0x1c7a, 0x1ea1, 0xf89, 0x2199, 0x291d, 0x1088, 0x2046, 0x256d, 0x2bc7, 0x2e9b, 0x41f, 0x1b55,
+ 0x2b38, 0xd0, 0x2e6a, 0x1755, 0x6bc, 0x2724, 0x3ba, 0x222e, 0x2c5c, 0x2da5, 0x213c, 0x10fe,
+ 0x169a, 0x1552, 0x5d3, 0x300, 0x1b5d, 0x1342, 0x2004, 0x256f, 0x2039, 0x667, 0x23b5, 0x1123,
+ 0xdb, 0x2da0, 0xe1e, 0x2f54, 0x2767, 0x154a, 0x40a, 0x11d3, 0x2821, 0xc09, 0x974, 0x694, 0xfbf,
+ 0x27ba, 0x132, 0x83f, 0x2d06, 0x10e, 0x183f, 0x29ae, 0x28c3, 0x2dc9, 0x1144, 0x2c70, 0x2a4a,
+ 0xf3c, 0x1e32, 0x1171, 0x1e43, 0xdd4, 0x2ddf, 0x28d2, 0xfac, 0x3c4, 0x2f19, 0x10a6, 0x2f7,
+ 0xe1d, 0x828, 0x138f, 0x1332, 0xfab, 0xcf6, 0x13f8, 0x24a0, 0x112d, 0x2717, 0x6e7, 0x1044,
+ 0x36e, 0xfe8, 0x6a, 0xba7, 0x1d69, 0x29ec, 0x23b2, 0xaee, 0x16df, 0x1068, 0x1a7e, 0x253f,
+ 0x24c, 0xb33, 0x2683, 0x15ce, 0x1ad3, 0x1a36, 0xc96, 0xaea, 0x260a, 0xce, 0x28b1, 0xe4f,
+ 0x2b11, 0x5f8, 0x1fc4, 0xe77, 0x2366, 0x11f9, 0x153c, 0x24eb, 0x20cd, 0x1398, 0x22, 0x2b97,
+ 0x249b, 0x8eb, 0x12b2, 0x2fe3, 0x29c1, 0x1b00, 0x2663, 0xeaa, 0x2e06, 0xe0, 0x1569, 0x10f5,
+ 0x284e, 0xa38, 0x201d, 0x1c53, 0x1681, 0x1f6f, 0x2f95, 0x2fe8, 0xacb, 0x1680, 0x17fd, 0x2c39,
+ 0x165a, 0x10bb, 0x29d8, 0x2622, 0x1196, 0x884, 0x2a79, 0x140e, 0x2d80, 0x6fa, 0x11b2, 0x26c4,
+ 0x355, 0x1054, 0x29e9, 0x23ed, 0xbe3, 0x24fa, 0x1fb3, 0x10ac, 0x2919, 0x2584, 0x10a4, 0xe85,
+ 0x650, 0x1893, 0x1dc1, 0xd8e, 0x12dc, 0x2d42, 0x284d, 0xfff, 0x250f, 0xacd, 0x13c3, 0x6cc,
+ 0x1a79, 0x1221, 0x2614, 0x270a, 0x1ea, 0x155, 0x2818, 0x222c, 0x2e5b, 0x25d8, 0x1dbf, 0x191c,
+ 0xb0f, 0xdac, 0x1082, 0x12ef, 0x11b6, 0xfa8, 0x2b72, 0x159d, 0x209e, 0x31b, 0x2c7c, 0x14f7,
+ 0xe09, 0x1bb2, 0x1ec7, 0x2404, 0x20ae, 0x6ad, 0xed6, 0x2b70, 0x1c7b, 0x18d1, 0x2732, 0x12da,
+ 0xd56, 0x5c1, 0x1648, 0x18b7, 0x1605, 0x1bc4, 0x280, 0x2ece, 0xc, 0x1aae, 0x1c4, 0x1cdb,
+ 0x22d6, 0x21d8, 0x257c, 0x51f, 0x211b, 0xff, 0x2ee0, 0x2585, 0xe1, 0x2c35, 0x26db, 0x2971,
+ 0x2208, 0x17e1, 0x21be, 0x135e, 0x28d6, 0x2891, 0x1689, 0x2138, 0xb86, 0x2e3a, 0x1204, 0x2d10,
+ 0x2324, 0xf3f, 0x2508, 0x33d, 0xcb2, 0x292a, 0xe27, 0x2e64, 0x29f8, 0x2d46, 0x9b7, 0x20eb,
+ 0x1b7c, 0x9eb, 0x2b2a, 0x58c, 0x27d0, 0x121b, 0x272e, 0x29f6, 0x2dbd, 0x2697, 0x2aac, 0xd6f,
+ 0x1c67, 0x2c5b, 0x108d, 0x363, 0x249d, 0x2d5e, 0x2fd, 0x2cb2, 0x1f8f, 0x20a4, 0xa19, 0x2ac9,
+ 0x19b1, 0x1581, 0x17a2, 0x29eb, 0x1b72, 0x13b0, 0xee4, 0xa8f, 0x2315, 0x5e6, 0x951, 0x2e29,
+ 0xdad, 0x1f2b, 0x224e, 0x37f, 0x1a72, 0xa91, 0x1407, 0x2df9, 0x3ad, 0x23f7, 0x1a24, 0x1d2a,
+ 0x234b, 0x1df3, 0x1143, 0x7ff, 0x1a6d, 0x2774, 0x2690, 0x2ab5, 0x586, 0x2781, 0x2009, 0x2fdd,
+ 0x2881, 0x399, 0x2fb6, 0x144, 0x137f, 0xfa0, 0x2e4c, 0x1c7f, 0x2fac, 0xb09, 0x1264, 0x127b,
+ 0x198c, 0x2b40, 0x230, 0x1cf4, 0x180b, 0xb58, 0x144a, 0x2aec, 0xfb, 0x2602, 0x14ee, 0x783,
+ 0x1098, 0x23d8, 0x203, 0xe9, 0x108a, 0x14b8, 0xeec, 0xc58, 0x1248, 0x243c, 0x28aa, 0x6bf,
+ 0x27c4, 0x276e, 0x19b8, 0x1d11, 0x2e16, 0x472, 0x1464, 0x24b9, 0x662, 0x1097, 0x2067, 0x20d6,
+ 0x171c, 0x4, 0x682, 0x17bb, 0x1186, 0x4f2, 0x3ff, 0x2a43, 0x1dc7, 0x1ae5, 0x8cc, 0x2e7c,
+ 0x2ef8, 0x2ae0, 0x2904, 0xed4, 0x6c5, 0x14ae, 0xb72, 0x11c3, 0x337, 0x2da3, 0x2916, 0x6d8,
+ 0x1cf9, 0x10ee, 0x1800, 0x1ae4, 0xa0d, 0x101b, 0x1a8d, 0x2e98, 0x24cd, 0x813, 0x1aa4, 0x9b9,
+ 0x680, 0x2349, 0x24d1, 0x20f8, 0xe31, 0x249f, 0x216b, 0x12d9, 0x1d21, 0x19db, 0x191a, 0x1dd0,
+ 0x5df, 0x55c, 0x2b86, 0x213, 0xe9e, 0x1ef1, 0x268a, 0x1d5e, 0x1e20, 0x28c1, 0x1379, 0x249,
+ 0x19de, 0x18b, 0x1e41, 0x2a1e, 0x2612, 0x297, 0x2e96, 0x2102, 0x46, 0x1b9f, 0x1a4d, 0x2050,
+ 0x1b32, 0x568, 0x11f7, 0x1829, 0x870, 0x1f4, 0x1dca, 0x990, 0x1df6, 0x2b62, 0x13ec, 0x9f2,
+ 0x1260, 0x2997, 0x1412, 0x1e6d, 0x1694, 0x11ac, 0x2d8b, 0x276f, 0x26f5, 0x233e, 0x2b44, 0x2f5a,
+ 0x2d37, 0x2cb1, 0xc75, 0x98d, 0x1d56, 0x7ae, 0x10e6, 0x113f, 0x17b8, 0xad3, 0x737, 0x221e,
+ 0x1b70, 0x1f3e, 0x2966, 0x18b2, 0x4fa, 0x2044, 0x1312, 0x154e, 0x2029, 0x700, 0x1b45, 0x27a6,
+ 0x226a, 0x21bf, 0x58d, 0x2f11, 0x2e02, 0x17fc, 0x4d2, 0x1757, 0xcb1, 0x2ef1, 0x2582, 0x1276,
+ 0x881, 0x2fc0, 0x104a, 0x670, 0x274f, 0x2b53, 0x19dd, 0x752, 0x1663, 0xcbd, 0x2b2b, 0x2fc6,
+ 0x13b6, 0x21e6, 0x15f6, 0x126b, 0x2637, 0x1cd9, 0x2f50, 0xe82, 0x5b0, 0x24e0, 0x1350, 0x2f24,
+ 0x21f7, 0x1a16, 0x2f3e, 0x167e, 0x1f7d, 0x28a0, 0x16f0, 0xe33, 0x53b, 0x28c5, 0x1500, 0x2f88,
+ 0x26cc, 0x2018, 0x1604, 0x218b, 0x2cd1, 0x9ee, 0x17f3, 0x5fd, 0x1f5a, 0x2d0, 0x2b46, 0x23cc,
+ 0x503, 0x1c46, 0x1cc3, 0x28e2, 0x243e, 0x122b, 0x2e0c, 0xe37, 0x2611, 0x85e, 0x9b8, 0x1b24,
+ 0x762, 0x19b6, 0x3bc, 0x2d50, 0x2079, 0x18da, 0x170a, 0x800, 0xaa2, 0x135a, 0x1a15, 0x13d1,
+ 0xca, 0x2113, 0x2db9, 0xdb2, 0x1a5c, 0x29a9, 0x1488, 0x14c1, 0x2c9, 0x917, 0x28e7, 0x265c,
+ 0xdab, 0x2ab9, 0x2bc6, 0x105b, 0x1839, 0x219c, 0x50, 0x11da, 0x1802, 0xf56, 0x2e6, 0x2190,
+ 0xddb, 0x56e, 0x9d9, 0x1c81, 0x1016, 0x12d6, 0x296f, 0x14b4, 0x1014, 0x1e64, 0x1d90, 0x89f,
+ 0x2bc2, 0x2777, 0x2819, 0x1c65, 0x1a41, 0x5a2, 0x2cd2, 0x427, 0xd71, 0x29c8, 0x1e58, 0x53f,
+ 0x7c5, 0x1dcd, 0x4a1, 0x1268, 0x2597, 0x2926, 0xee, 0x111b, 0x1038, 0xe6c, 0x22dc, 0x2f2f,
+ 0x441, 0x2cfd, 0x1cb0, 0x6a4, 0x2224, 0x620, 0x5dc, 0x16b1, 0x2a1d, 0x1787, 0x20c7, 0x641,
+ 0xd84, 0x1c05, 0x2d0d, 0x2f52, 0x1b8c, 0xd7d, 0x17e8, 0x1589, 0xc73, 0x151b, 0x4e2, 0x1ae9,
+ 0x1b18, 0xb9b, 0x949, 0x2c60, 0x1e7a, 0xd5, 0x1bdc, 0x1f57, 0x1753, 0x124a, 0x559, 0xb76,
+ 0x2334, 0x12d1, 0x1de1, 0x14b2, 0x2faa, 0x1697, 0x147a, 0x5a1, 0x2c30, 0x1c02, 0x1043, 0x2ee1,
+ 0x2402, 0x1cc8, 0x2a16, 0xff7, 0x1364, 0x1b9a, 0x2a53, 0x2f94, 0x294c, 0x1ee5, 0x1a87, 0x2141,
+ 0xd66, 0x953, 0x28a3, 0x2f30, 0x2477, 0x18e3, 0x1035, 0x1fc1, 0x1d68, 0x2fb3, 0x138c, 0x2487,
+ 0x1bf8, 0xd96, 0x1018, 0x748, 0x244e, 0x15bd, 0x175e, 0x2be, 0x23d, 0x1da, 0x176d, 0xc17,
+ 0x24be, 0x2ebb, 0x7d8, 0x100a, 0x759, 0x1db4, 0x2259, 0x23f4, 0x2d59, 0x2847, 0xbf5, 0x1cfe,
+ 0xa20, 0x258, 0x1180, 0x279c, 0x54, 0x2abf, 0xc5c, 0x9f9, 0x3d5, 0x2ce4, 0x165f, 0x23d9,
+ 0x27b9, 0x6f9, 0x281a, 0x169e, 0x627, 0x156d, 0x1ff8, 0x211, 0x2e34, 0x1724, 0x2c2e, 0x2790,
+ 0x2dd5, 0x2bf2, 0xdbc, 0x2884, 0x20a9, 0x2390, 0x1e1a, 0x1b6a, 0x5f7, 0xab7, 0x1333, 0x16ab,
+ 0x28dd, 0x20, 0x30f, 0x24b6, 0x5c2, 0x1ce4, 0x1400, 0x2669, 0x60, 0x156c, 0xe20, 0x26d4,
+ 0x26ab, 0x1ebb, 0x223d, 0x5b4, 0x2025, 0x1e1c, 0xaae, 0x2e08, 0x6cd, 0x1677, 0x13d9, 0x17b5,
+ 0x1046, 0x1d8c, 0x14eb, 0x18d8, 0x1ce5, 0x2478, 0x16ae, 0xb79, 0x23d4, 0x684, 0x156b, 0x567,
+ 0x1a, 0x29ce, 0x83a, 0x19e8, 0x58e, 0x294a, 0x1136, 0x2319, 0x2fba, 0x1a29, 0x1d, 0x1879,
+ 0x291b, 0x19f6, 0x2c2f, 0x21c9, 0x19bb, 0xbbc, 0x26f9, 0xc22, 0x708, 0x11a1, 0x18d3, 0x7f8,
+ 0x28f8, 0x2427, 0x1deb, 0xaed, 0x26aa, 0x2482, 0x203b, 0x2f05, 0x2b82, 0x192f, 0x2df4, 0x8dc,
+ 0x2877, 0xd5e, 0x240e, 0x775, 0x2dae, 0x1d3e, 0x20ba, 0x215b, 0x22d1, 0xeba, 0xf50, 0xaa8,
+ 0x184a, 0x1f67, 0x2e04, 0xc6e, 0x6dd, 0x1a09, 0x27f, 0x494, 0x1426, 0xae3, 0xe15, 0x65f,
+ 0x13c4, 0x105, 0x872, 0x2667, 0x1ff6, 0xd9f, 0x2ca1, 0x2f39, 0x2657, 0x23fd, 0x2405, 0xb73,
+ 0x2294, 0x1f1e, 0x2eba, 0x110a, 0x2cae, 0x141f, 0x22cd, 0x25d6, 0x11c1, 0x1c, 0x2d8e, 0x161a,
+ 0x1aa8, 0x229e, 0x1bf9, 0x7cf, 0x106d, 0x2c40, 0xd93, 0x255e, 0x28c2, 0xc1a, 0x2f17, 0x7ca,
+ 0x2f63, 0xbf,
+];
+const IROOTS: [i32; 1024] = [
+ 0x2ac8, 0x452, 0x297c, 0x666, 0xb4c, 0x2b8, 0x1a74, 0xfd, 0x1a47, 0x1d08, 0x2959, 0x2c36,
+ 0x2db4, 0x56c, 0x254e, 0x1125, 0x2f3d, 0x13bc, 0x172c, 0x2c6b, 0x32a, 0x1745, 0x18bd, 0x8f1,
+ 0x1633, 0x2dfa, 0xfdd, 0x23e3, 0x241b, 0x13a5, 0x578, 0x17a0, 0xa9, 0x104b, 0x1335, 0x24e4,
+ 0x28de, 0x5a7, 0x368, 0x2d70, 0x13cd, 0x2f9, 0xff5, 0x1e88, 0x9c5, 0x2ff7, 0x900, 0xdeb,
+ 0x1434, 0x15fe, 0x156a, 0x24d3, 0x28ed, 0x2c4f, 0x688, 0xaef, 0x2353, 0x1045, 0x2bcf, 0x23a4,
+ 0x270, 0x4c5, 0x21fe, 0xe5b, 0xfbb, 0x1f79, 0x6e4, 0xe68, 0x2078, 0x1160, 0x1387, 0x1e98,
+ 0x22f5, 0x13e, 0x283a, 0x123f, 0x149c, 0x2eca, 0xb14, 0xf37, 0xdde, 0xbe7, 0x386, 0x1abe,
+ 0xa4a, 0x49, 0x14b5, 0x2f36, 0x8e5, 0x1f1, 0x2a57, 0x1789, 0x2f01, 0x91f, 0xaac, 0x266c,
+ 0x2b65, 0x2f4b, 0xa30, 0x2a17, 0x265, 0x253a, 0xfb3, 0x2142, 0x20be, 0x25c2, 0x121c, 0x2d97,
+ 0x2131, 0x1e19, 0x1a11, 0x514, 0x22c3, 0x66, 0xdcf, 0x1540, 0x1d41, 0xf02, 0x815, 0x5a, 0x18e8,
+ 0x1159, 0x103a, 0x2d23, 0x2a10, 0x2d61, 0x1327, 0x403, 0x25c9, 0x7b3, 0x1f0c, 0x1a98, 0x2f21,
+ 0x1fb, 0x2157, 0x99e, 0x1501, 0x640, 0x1e, 0x1d4f, 0x2716, 0xb66, 0x46a, 0x2fdf, 0x1c69, 0xf34,
+ 0xb16, 0x1ac5, 0x1e08, 0xc9b, 0x218a, 0x103d, 0x2a09, 0x4f0, 0x21b2, 0x750, 0x2f33, 0x9f7,
+ 0x2517, 0x236b, 0x15cb, 0x152e, 0x1a33, 0x97e, 0x24ce, 0x2db5, 0xac2, 0x1583, 0x1f99, 0x1922,
+ 0x2513, 0xc4f, 0x615, 0x1298, 0x245a, 0x2f97, 0x2019, 0x2c93, 0x1fbd, 0x291a, 0x8ea, 0x1ed4,
+ 0xb61, 0x1c09, 0x230b, 0x2056, 0x1ccf, 0x1c72, 0x27d9, 0x21e4, 0x2d0a, 0x1f5b, 0xe8, 0x2c3d,
+ 0x2055, 0x72f, 0x222, 0x222d, 0x11be, 0x1e90, 0x11cf, 0x20c5, 0x5b7, 0x391, 0x1ebd, 0x238,
+ 0x73e, 0x653, 0x17c2, 0x2ef3, 0x2fb, 0x27c2, 0x2ecf, 0x847, 0x2042, 0x296d, 0x268d, 0x23f8,
+ 0x7e0, 0x1e2e, 0x2bf7, 0x1ab7, 0x89a, 0xad, 0x21e3, 0x261, 0x2f26, 0x1ede, 0xc4c, 0x299a,
+ 0xfc8, 0xa92, 0xffd, 0x1cbf, 0x14a4, 0x2d01, 0x2a2e, 0x1aaf, 0x1967, 0x1f03, 0xec5, 0x25c,
+ 0x3a5, 0xdd3, 0x2c47, 0x8dd, 0x2945, 0x18ac, 0x197, 0x2f31, 0x4c9, 0x14ac, 0x2be2, 0x166,
+ 0x43a, 0xa94, 0x1b53, 0x293c, 0x212d, 0x6fd, 0x521, 0x109, 0x185, 0x2735, 0x151c, 0x123a,
+ 0x5be, 0x2c02, 0x2b0f, 0x1e7b, 0x1846, 0x297f, 0x2ffd, 0x18e5, 0xf2b, 0xf9a, 0x1f6a, 0x299f,
+ 0xb48, 0x1b9d, 0x2b8f, 0x1eb, 0x12f0, 0x1649, 0x893, 0x83d, 0x2942, 0x757, 0xbc5, 0x1db9,
+ 0x23a9, 0x2115, 0x1b49, 0x1f77, 0x2f18, 0x2dfe, 0xc29, 0x1f69, 0x287e, 0x1b13, 0x9ff, 0x2f06,
+ 0x515, 0x1bb7, 0x24a9, 0x17f6, 0x130d, 0x2dd1, 0x4c1, 0x1675, 0x1d86, 0x1d9d, 0x24f8, 0x55,
+ 0x1382, 0x1b5, 0x2061, 0x1c82, 0x2ebd, 0x4b, 0x2c68, 0x780, 0x24, 0xff8, 0x880, 0x2a7b, 0x54c,
+ 0x971, 0x88d, 0x1594, 0x2802, 0x1ebe, 0x120e, 0xcb6, 0x12d7, 0x15dd, 0xc0a, 0x2c54, 0x208,
+ 0x1bfa, 0x2570, 0x158f, 0x2c82, 0xdb3, 0x10d6, 0x2254, 0x1d8, 0x26b0, 0x2a1b, 0xcec, 0x2572,
+ 0x211d, 0x1c51, 0x148f, 0x616, 0x185f, 0x1a80, 0x1650, 0x538, 0x25e8, 0xf5d, 0x1072, 0x34f,
+ 0x2d04, 0x2a3, 0xb64, 0x2c9e, 0x1f74, 0x3a6, 0x139a, 0x2292, 0x555, 0x96a, 0x244, 0x60b, 0x8d3,
+ 0x1de6, 0x831, 0x2a75, 0x4d7, 0x2616, 0x1485, 0xf16, 0x264a, 0x2bb, 0x609, 0x19d, 0x21da,
+ 0x6d7, 0x234f, 0x2cc4, 0xaf9, 0x20c2, 0xcdd, 0x2f1, 0x1dfd, 0x1c7, 0x247b, 0xec9, 0x1978,
+ 0x770, 0x72b, 0x1ca3, 0xe43, 0x1820, 0xdf9, 0x690, 0x926, 0x3cc, 0x2f20, 0xa7c, 0x121, 0x2f02,
+ 0xee6, 0x2ae2, 0xa85, 0xe29, 0xd2b, 0x1326, 0x2e3d, 0x1553, 0x2ff5, 0x133, 0x2d81, 0x143d,
+ 0x19fc, 0x174a, 0x19b9, 0x2a40, 0x22ab, 0x1d27, 0x8cf, 0x1730, 0x1386, 0x491, 0x212b, 0x2954,
+ 0xf53, 0xbfd, 0x113a, 0x144f, 0x21f8, 0x1b0a, 0x385, 0x2ce6, 0xf63, 0x1a64, 0x48f, 0x2059,
+ 0x1e4b, 0x1d12, 0x1f7f, 0x2255, 0x24f2, 0x16e5, 0x1242, 0xa29, 0x1a6, 0xdd5, 0x7e9, 0x2eac,
+ 0x2e17, 0x8f7, 0x9ed, 0x1de0, 0x1588, 0x2935, 0x1c3e, 0x2534, 0xaf2, 0x2002, 0x7b4, 0x2bf,
+ 0x1d25, 0x2273, 0x1240, 0x176e, 0x29b1, 0x217c, 0x1f5d, 0xa7d, 0x6e8, 0x1f55, 0x104e, 0xb07,
+ 0x241e, 0xc14, 0x618, 0x1fad, 0x2cac, 0x93d, 0x1e4f, 0x2907, 0x281, 0x1bf3, 0x588, 0x277d,
+ 0x1e6b, 0x9df, 0x629, 0x1f46, 0x19a7, 0x3c8, 0x1804, 0x1981, 0x2536, 0x19, 0x6c, 0x1092,
+ 0x1980, 0x13ae, 0xfe4, 0x2f42, 0x9e, 0x2837, 0xea, 0x23e7, 0x73f, 0xaa3, 0x226e, 0x3c1, 0x1f94,
+ 0x2832, 0x1408, 0xd63, 0x1559, 0x19e7, 0x273, 0x2fe5, 0x1e40, 0xa2b, 0xd34, 0x1be2, 0x353,
+ 0x1ef7, 0x147, 0x10e3, 0xd6d, 0x248e, 0xbfc, 0xc04, 0x9aa, 0xc8, 0x360, 0x2262, 0x100b, 0x99a,
+ 0x278f, 0x2efc, 0x1c3d, 0x29a2, 0x21ec, 0x251e, 0x1bdb, 0x2b6d, 0x2d82, 0x15f8, 0x2924, 0x2393,
+ 0x1fd, 0x109a, 0x17b7, 0x2559, 0x20b1, 0x2147, 0xd30, 0xea6, 0xf47, 0x12c3, 0x253, 0x288c,
+ 0xbf3, 0x22a3, 0x78a, 0x2725, 0x20d, 0x16d2, 0x47f, 0xfc, 0xfc6, 0xb7f, 0x957, 0x2514, 0x1216,
+ 0xbda, 0x709, 0x2809, 0x172e, 0x1e60, 0x28f9, 0x23df, 0x908, 0x2445, 0x1646, 0xe38, 0x3d2,
+ 0x160b, 0x6e6, 0x1788, 0x2fe4, 0x15d8, 0x47, 0xce8, 0x1ecb, 0x6b7, 0x2a73, 0x1619, 0x27c7,
+ 0x633, 0x2fe7, 0x2a9a, 0x1a96, 0x297d, 0xc2d, 0x2488, 0x1953, 0xb89, 0x131c, 0x1729, 0x1b16,
+ 0x1275, 0x1fbb, 0x184c, 0x1c28, 0x198a, 0x2934, 0x1f9, 0x2553, 0x11e5, 0xfdc, 0x2a4d, 0xdc4,
+ 0x1146, 0x956, 0x92d, 0x21e1, 0x1a95, 0x2fa1, 0x998, 0x1c01, 0x131d, 0x2a3f, 0xb4b, 0x2cf2,
+ 0x2fe1, 0x724, 0x1956, 0x1cce, 0x254a, 0x2a0a, 0x1497, 0x11e7, 0xc71, 0xf58, 0x77d, 0x2245,
+ 0x40f, 0x22c, 0x871, 0x3d3, 0x18dd, 0x1cd, 0x2df0, 0x1009, 0x1a94, 0x29da, 0x1963, 0x7e7,
+ 0x2908, 0x848, 0xc28, 0x19a2, 0x31d, 0x2c2c, 0x2608, 0x23a5, 0x542, 0x2fad, 0x865, 0x1e81,
+ 0x2da9, 0x25e1, 0x1303, 0x240c, 0x7ba, 0x2a8, 0xc0d, 0xda8, 0x124d, 0x28a8, 0x1ff7, 0x2829,
+ 0x146, 0xb43, 0x23ea, 0x1894, 0x2e27, 0x2dc4, 0x2d43, 0x18a3, 0x1a44, 0xbb3, 0x28b9, 0x1fe9,
+ 0x226b, 0x1409, 0xb7a, 0x1c75, 0x4e, 0x1299, 0x1040, 0x1fcc, 0x171e, 0xb8a, 0xd1, 0x75e,
+ 0x26ae, 0x229b, 0xec0, 0x157a, 0x111c, 0x6b5, 0x6d, 0x5ae, 0x1467, 0x1c9d, 0x200a, 0x5eb,
+ 0x1339, 0xbff, 0x120, 0x1fbe, 0x13ff, 0x3d1, 0x2a60, 0x1b87, 0x196a, 0x57, 0x1b4f, 0x1220,
+ 0x1d30, 0xccd, 0x248b, 0x2aa8, 0x1db7, 0x18ae, 0x10aa, 0x1425, 0x2f2c, 0x1187, 0x3a1, 0x26b8,
+ 0x2466, 0x14e9, 0x1518, 0x2b1f, 0x1ae6, 0x238e, 0x1a78, 0x1819, 0x2284, 0x1475, 0xaf, 0x2f4,
+ 0x13fc, 0x227d, 0x29c0, 0xf3a, 0x187a, 0x5e4, 0x1950, 0x2a25, 0x29e1, 0xddd, 0x295d, 0x1351,
+ 0x304, 0x2bc0, 0xd2, 0xd25, 0x2195, 0x1fc9, 0x1ee6, 0x2f13, 0x6db, 0xa6a, 0x1d99, 0x2b60,
+ 0x1234, 0x283c, 0x2ac2, 0x11a9, 0x639, 0x2290, 0x2bda, 0x32f, 0x2a5f, 0x15c0, 0x139c, 0x7e8,
+ 0x88a, 0x43f, 0x2762, 0x1271, 0x119d, 0x1fed, 0x1b4d, 0x692, 0x1d2b, 0x1feb, 0x1380, 0x2628,
+ 0x2a93, 0x2226, 0xe71, 0x2d1b, 0x20ab, 0x17ff, 0x1e27, 0x2fb1, 0xe65, 0x17c8, 0x1fa6, 0x43b,
+ 0x548, 0x2256, 0x9a5, 0x71a, 0x26ea, 0x2d38, 0x1b40, 0x1b79, 0x658, 0x15a5, 0x224f, 0x248,
+ 0xeee, 0x2f37, 0x1c30, 0x15ec, 0x1ca7, 0x255f, 0x2801, 0x18f7, 0x1727, 0xf88, 0x2b1, 0x2c45,
+ 0x164b, 0x289f, 0x14dd, 0x2649, 0x27a3, 0x9f0, 0x21ca, 0x1f5, 0x1dd6, 0xbc3, 0x71f, 0x133e,
+ 0x13bb, 0x2afe, 0xc35, 0x4bb, 0x2d31, 0x10a7, 0x2a04, 0x180e, 0x2613, 0x330, 0xe76, 0x19fd,
+ 0xfe9, 0x935, 0x79, 0x1b01, 0x73c, 0x2ac6, 0x21ce, 0x1911, 0x761, 0x1084, 0x1983, 0xc3, 0x15eb,
+ 0xe0a, 0xdd, 0x1cb1, 0xb21, 0x2a51, 0x217f, 0xb1, 0x1328, 0x9ca, 0x1d96, 0x1a0b, 0xe1b, 0x1c4b,
+ 0x3b, 0x4d6, 0x2344, 0x199e, 0x28af, 0x1624, 0x4ae, 0x8b2, 0x2991, 0x1fb7, 0x41, 0x2780,
+ 0x1d8b, 0xa7f, 0x110, 0x2350, 0x18aa, 0x2b2f, 0x1805, 0x1ff, 0xf0, 0x2a74, 0xe42, 0xd97, 0x85b,
+ 0x14bc, 0x2901, 0xfd8, 0x1ab3, 0x1cef, 0xfbd, 0x2b07, 0x174f, 0x69b, 0x10c3, 0x1491, 0xde3,
+ 0x28ca, 0x252e, 0x1849, 0x1ec2, 0x1f1b, 0x2853, 0x12ab, 0x2674, 0x238c, 0x350, 0x2ca, 0xa7,
+ 0x4bd, 0xcc3, 0x90c, 0x892, 0x276, 0x1e55, 0x196d, 0x1194, 0x1bef, 0x66a, 0x1da1, 0x260f,
+ 0x1c15, 0x49f, 0x120b, 0x2671, 0x1237, 0x2e0d, 0x2791, 0x17d8, 0x1e0a, 0x2a99, 0x14cf, 0xfb1,
+ 0x15b4, 0x1462, 0x2fbb, 0xeff, 0x16b, 0x2d6a, 0x9ef, 0x5e3, 0x11c0, 0x2e76, 0x1623, 0x2db8,
+ 0x1c88, 0x740, 0x11e1, 0x12a3, 0x977, 0x1110, 0x2163, 0x2dee, 0x47b, 0x2aa5, 0x2a22, 0x1231,
+ 0x16e7, 0x1626, 0x12e0, 0x1d28, 0xe96, 0xb62, 0x21d0, 0xf09, 0xb30, 0xcb8, 0x2981, 0x2648,
+ 0x155d, 0x27ee, 0xb34, 0x169, 0x1574, 0x1fe6, 0x25f4, 0x151d, 0x1801, 0x1f13, 0x1308, 0x2929,
+ 0x6eb, 0x25e, 0x2cca, 0x1e3e, 0x248f,
+];
+
+fn round(a: i32, b: i32) -> i32 {
+ return (a + b / 2) / b;
+}
+
+/* Constant time absolute value */
+fn nabs(x: i32) -> i32 {
+ let mask = x >> 31;
+ return (x + mask) ^ mask;
+}
+
+/* Montgomery stuff */
+
+fn redc(t: u64) -> i32 {
+ let m = (t as u32).wrapping_mul(ND);
+ return (((m as u64) * (PRIME as u64) + t) >> WL) as i32;
+}
+
+fn nres(x: i32) -> i32 {
+ return redc((x as u64) * R2MODP);
+}
+
+fn modmul(a: i32, b: i32) -> i32 {
+ return redc((a as u64) * (b as u64));
+}
+
+/* Cooley-Tukey NTT */
+fn ntt(x: &mut [i32]) {
+ let mut t = DEGREE / 2;
+ let q = PRIME;
+
+ /* Convert to Montgomery form */
+ for j in 0..DEGREE {
+ x[j] = nres(x[j])
+ }
+ let mut m = 1;
+ while m < DEGREE {
+ let mut k = 0;
+ for i in 0..m {
+ let s = ROOTS[m + i];
+ for j in k..k + t {
+ let u = x[j];
+ let v = modmul(x[j + t], s);
+ x[j] = u + v;
+ x[j + t] = u + 2 * q - v;
+ }
+ k += 2 * t;
+ }
+ t /= 2;
+ m *= 2;
+ }
+}
+
+/* Gentleman-Sande INTT */
+
+fn intt(x: &mut [i32]) {
+ let mut t = 1;
+ let q = PRIME;
+ let mut m = DEGREE / 2;
+ while m > 1 {
+ let mut k = 0;
+ for i in 0..m {
+ let s = IROOTS[m + i];
+ for j in k..k + t {
+ let u = x[j];
+ let v = x[j + t];
+ x[j] = u + v;
+ let w = u + (DEGREE as i32) * q - v;
+ x[j + t] = modmul(w, s);
+ }
+ k += 2 * t;
+ }
+ t *= 2;
+ m /= 2;
+ }
+
+ /* Last iteration merged with n^-1 */
+ t = DEGREE / 2;
+ for j in 0..t {
+ let u = x[j];
+ let v = x[j + t];
+ let w = u + (DEGREE as i32) * q - v;
+ x[j + t] = modmul(w, INVPR);
+ x[j] = modmul(u + v, INV);
+ }
+ /* convert back from Montgomery to "normal" form */
+ for j in 0..DEGREE {
+ x[j] = redc(x[j] as u64);
+ x[j] -= q;
+ x[j] += (x[j] >> (WL - 1)) & q;
+ }
+}
+
+/* See https://eprint.iacr.org/2016/1157.pdf */
+
+fn encode(key: &[u8], poly: &mut [i32]) {
+ let q2 = PRIME / 2;
+ let mut j = 0;
+ let mut i = 0;
+ while i < 256 {
+ let mut kj = key[j];
+ j += 1;
+ for _ in 0..8 {
+ let b = (kj & 1) as i32;
+ poly[i] = b * q2;
+ poly[i + 256] = b * q2;
+ poly[i + 512] = b * q2;
+ poly[i + 768] = b * q2;
+ kj >>= 1;
+ i += 1;
+ }
+ }
+}
+
+fn decode(poly: &[i32], key: &mut [u8]) {
+ let q2 = PRIME / 2;
+ for i in 0..32 {
+ key[i] = 0;
+ }
+
+ let mut i = 0;
+ let mut j = 0;
+ while i < 256 {
+ for _ in 0..8 {
+ let t = nabs(poly[i] - q2)
+ + nabs(poly[i + 256] - q2)
+ + nabs(poly[i + 512] - q2)
+ + nabs(poly[i + 768] - q2);
+ let mut b = t - PRIME;
+ b = (b >> 31) & 1;
+ key[j] = (key[j] >> 1) + ((b << 7) as u8);
+ i += 1;
+ }
+ j += 1;
+ }
+}
+
+/* convert 32-byte seed to random polynomial */
+
+fn parse(seed: &[u8], poly: &mut [i32]) {
+ let mut hash: [u8; 4 * DEGREE] = [0; 4 * DEGREE];
+ let mut sh = SHA3::new(sha3::SHAKE128);
+ for i in 0..32 {
+ sh.process(seed[i])
+ }
+ sh.shake(&mut hash, 4 * DEGREE);
+
+ let mut j = 0;
+ for i in 0..DEGREE {
+ let mut n = (hash[j] & 0x7f) as i32;
+ n <<= 8;
+ n += (hash[j + 1]) as i32;
+ n <<= 8;
+ n += (hash[j + 2]) as i32;
+ n <<= 8;
+ n += (hash[j + 3]) as i32;
+ j += 4;
+ poly[i] = nres(n);
+ //poly[i]=modmul(n,ONE); // reduce 31-bit random number mod q
+ }
+}
+
+/* Compress 14 bits polynomial coefficients into byte array */
+/* 7 bytes is 3x14 */
+
+fn nhs_pack(poly: &[i32], array: &mut [u8]) {
+ let mut j = 0;
+ let mut i = 0;
+ while i < DEGREE {
+ let a = poly[i];
+ let b = poly[i + 1];
+ let c = poly[i + 2];
+ let d = poly[i + 3];
+ i += 4;
+ array[j] = (a & 0xff) as u8;
+ array[j + 1] = (((a >> 8) | (b << 6)) & 0xff) as u8;
+ array[j + 2] = ((b >> 2) & 0xff) as u8;
+ array[j + 3] = (((b >> 10) | (c << 4)) & 0xff) as u8;
+ array[j + 4] = ((c >> 4) & 0xff) as u8;
+ array[j + 5] = (((c >> 12) | (d << 2)) & 0xff) as u8;
+ array[j + 6] = (d >> 6) as u8;
+ j += 7;
+ }
+}
+
+fn nhs_unpack(array: &[u8], poly: &mut [i32]) {
+ let mut j = 0;
+ let mut i = 0;
+ while i < DEGREE {
+ let a = ((array[j]) & 0xff) as i32;
+ let b = ((array[j + 1]) & 0xff) as i32;
+ let c = ((array[j + 2]) & 0xff) as i32;
+ let d = ((array[j + 3]) & 0xff) as i32;
+ let e = ((array[j + 4]) & 0xff) as i32;
+ let f = ((array[j + 5]) & 0xff) as i32;
+ let g = ((array[j + 6]) & 0xff) as i32;
+ j += 7;
+ poly[i] = a | ((b & 0x3f) << 8);
+ poly[i + 1] = (b >> 6) | (c << 2) | ((d & 0xf) << 10);
+ poly[i + 2] = (d >> 4) | (e << 4) | ((f & 3) << 12);
+ poly[i + 3] = (f >> 2) | (g << 6);
+ i += 4;
+ }
+}
+
+/* See https://eprint.iacr.org/2016/1157.pdf */
+
+fn compress(poly: &[i32], array: &mut [u8]) {
+ let mut col = 0 as i32;
+ let mut j = 0;
+ let mut i = 0;
+ while i < DEGREE {
+ for _ in 0..8 {
+ let b = round(poly[i] * 8, PRIME) & 7;
+ col = (col << 3) + b;
+ i += 1;
+ }
+ array[j] = (col & 0xff) as u8;
+ array[j + 1] = ((col >> 8) & 0xff) as u8;
+ array[j + 2] = ((col >> 16) & 0xff) as u8;
+ j += 3;
+ col = 0;
+ }
+}
+
+fn decompress(array: &[u8], poly: &mut [i32]) {
+ let mut j = 0;
+ let mut i = 0;
+ while i < DEGREE {
+ let mut col = (array[j + 2] as i32) & 0xff;
+ col = (col << 8) + ((array[j + 1] as i32) & 0xff);
+ col = (col << 8) + ((array[j] as i32) & 0xff);
+ j += 3;
+ for _ in 0..8 {
+ let b = (col & 0xe00000) >> 21;
+ col <<= 3;
+ poly[i] = round(b * PRIME, 8);
+ i += 1;
+ }
+ }
+}
+
+/* generate centered binomial distribution */
+
+fn error(rng: &mut RAND, poly: &mut [i32]) {
+ for i in 0..DEGREE {
+ let mut n1 = ((rng.getbyte() as i32) & 0xff) + (((rng.getbyte() as i32) & 0xff) << 8);
+ let mut n2 = ((rng.getbyte() as i32) & 0xff) + (((rng.getbyte() as i32) & 0xff) << 8);
+ let mut r = 0 as i32;
+ for _ in 0..16 {
+ r += (n1 & 1) - (n2 & 1);
+ n1 >>= 1;
+ n2 >>= 1;
+ }
+ poly[i] = r + PRIME;
+ }
+}
+
+fn redc_it(p: &mut [i32]) {
+ for i in 0..DEGREE {
+ p[i] = redc(p[i] as u64);
+ }
+}
+
+fn nres_it(p: &mut [i32]) {
+ for i in 0..DEGREE {
+ p[i] = nres(p[i]);
+ }
+}
+
+fn poly_mul(p1: &mut [i32], p3: &[i32]) {
+ for i in 0..DEGREE {
+ p1[i] = modmul(p1[i], p3[i]);
+ }
+}
+
+fn poly_add(p1: &mut [i32], p3: &[i32]) {
+ for i in 0..DEGREE {
+ p1[i] = p1[i] + p3[i];
+ }
+}
+
+fn poly_rsub(p1: &mut [i32], p2: &[i32]) {
+ for i in 0..DEGREE {
+ p1[i] = p2[i] + PRIME - p1[i];
+ }
+}
+
+/* reduces inputs < 2q */
+fn poly_soft_reduce(poly: &mut [i32]) {
+ for i in 0..DEGREE {
+ let e = poly[i] - PRIME;
+ poly[i] = e + ((e >> (WL - 1)) & PRIME);
+ }
+}
+
+/* fully reduces modulo q */
+fn poly_hard_reduce(poly: &mut [i32]) {
+ for i in 0..DEGREE {
+ let mut e = modmul(poly[i], ONE);
+ e = e - PRIME;
+ poly[i] = e + ((e >> (WL - 1)) & PRIME);
+ }
+}
+
+/* API files */
+
+pub fn server_1(mut rng: &mut RAND, sb: &mut [u8], ss: &mut [u8]) {
+ let mut seed: [u8; 32] = [0; 32];
+ let mut array: [u8; 1792] = [0; 1792];
+ let mut s: [i32; DEGREE] = [0; DEGREE];
+ let mut e: [i32; DEGREE] = [0; DEGREE];
+ let mut b: [i32; DEGREE] = [0; DEGREE];
+
+ for i in 0..32 {
+ seed[i] = rng.getbyte();
+ }
+
+ parse(&seed, &mut b);
+
+ error(&mut rng, &mut e);
+ error(&mut rng, &mut s);
+
+ ntt(&mut s);
+ ntt(&mut e);
+ poly_mul(&mut b, &s);
+ poly_add(&mut b, &e);
+ poly_hard_reduce(&mut b);
+
+ redc_it(&mut b);
+ nhs_pack(&b, &mut array);
+
+ for i in 0..32 {
+ sb[i] = seed[i];
+ }
+
+ for i in 0..1792 {
+ sb[i + 32] = array[i];
+ }
+
+ poly_hard_reduce(&mut s);
+ nhs_pack(&s, &mut array);
+
+ for i in 0..1792 {
+ ss[i] = array[i];
+ }
+}
+
+pub fn client(mut rng: &mut RAND, sb: &[u8], uc: &mut [u8], okey: &mut [u8]) {
+ let mut sh = SHA3::new(sha3::HASH256);
+
+ let mut seed: [u8; 32] = [0; 32];
+ let mut array: [u8; 1792] = [0; 1792];
+ let mut key: [u8; 32] = [0; 32];
+ let mut cc: [u8; 384] = [0; 384];
+
+ let mut sd: [i32; DEGREE] = [0; DEGREE];
+ let mut ed: [i32; DEGREE] = [0; DEGREE];
+ let mut u: [i32; DEGREE] = [0; DEGREE];
+ let mut k: [i32; DEGREE] = [0; DEGREE];
+ let mut c: [i32; DEGREE] = [0; DEGREE];
+
+ error(&mut rng, &mut sd);
+ error(&mut rng, &mut ed);
+
+ ntt(&mut sd);
+ ntt(&mut ed);
+
+ for i in 0..32 {
+ seed[i] = sb[i];
+ }
+
+ for i in 0..1792 {
+ array[i] = sb[i + 32];
+ }
+
+ parse(&seed, &mut u);
+
+ poly_mul(&mut u, &sd);
+ poly_add(&mut u, &ed);
+ poly_hard_reduce(&mut u);
+
+ for i in 0..32 {
+ key[i] = rng.getbyte();
+ }
+
+ for i in 0..32 {
+ sh.process(key[i]);
+ }
+ sh.hash(&mut key);
+
+ encode(&key, &mut k);
+
+ nhs_unpack(&array, &mut c);
+ nres_it(&mut c);
+
+ poly_mul(&mut c, &sd);
+ intt(&mut c);
+ error(&mut rng, &mut ed);
+ poly_add(&mut c, &ed);
+ poly_add(&mut c, &k);
+
+ compress(&c, &mut cc);
+
+ sh = SHA3::new(sha3::HASH256);
+ for i in 0..32 {
+ sh.process(key[i]);
+ }
+ sh.hash(&mut key);
+
+ for i in 0..32 {
+ okey[i] = key[i];
+ }
+
+ redc_it(&mut u);
+ nhs_pack(&u, &mut array);
+
+ for i in 0..1792 {
+ uc[i] = array[i];
+ }
+
+ for i in 0..384 {
+ uc[i + 1792] = cc[i];
+ }
+}
+
+pub fn server_2(ss: &[u8], uc: &[u8], okey: &mut [u8]) {
+ let mut sh = SHA3::new(sha3::HASH256);
+
+ let mut s: [i32; DEGREE] = [0; DEGREE];
+ let mut k: [i32; DEGREE] = [0; DEGREE];
+ let mut c: [i32; DEGREE] = [0; DEGREE];
+
+ let mut array: [u8; 1792] = [0; 1792];
+ let mut key: [u8; 32] = [0; 32];
+ let mut cc: [u8; 384] = [0; 384];
+
+ for i in 0..1792 {
+ array[i] = uc[i];
+ }
+
+ nhs_unpack(&array, &mut k);
+ nres_it(&mut k);
+
+ for i in 0..384 {
+ cc[i] = uc[i + 1792];
+ }
+
+ decompress(&cc, &mut c);
+
+ for i in 0..1792 {
+ array[i] = ss[i];
+ }
+
+ nhs_unpack(&array, &mut s);
+
+ poly_mul(&mut k, &s);
+ intt(&mut k);
+ poly_rsub(&mut k, &c);
+ poly_soft_reduce(&mut k);
+
+ decode(&k, &mut key);
+
+ for i in 0..32 {
+ sh.process(key[i]);
+ }
+ sh.hash(&mut key);
+
+ for i in 0..32 {
+ okey[i] = key[i];
+ }
+}
+
+/*
+fn main() {
+ let x=3;
+ let y=redc(x as u64);
+ let z=redc((y as u64)*(R2MODP));
+ println!("{:02x}",z);
+
+ let mut a:[i32;1024]=[0;1024];
+ for i in 0..1024 {a[i]=i as i32}
+
+ ntt(&mut a);
+
+ for i in 0..1024 {a[i]=modmul(a[i],ONE)}
+
+ intt(&mut a);
+
+ println!("{:02x}",a[7]);
+
+}
+*/
diff --git a/src/pair.rs b/src/pair.rs
new file mode 100644
index 0000000..2050296
--- /dev/null
+++ b/src/pair.rs
@@ -0,0 +1,755 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+
+use super::fp::FP;
+use super::ecp::ECP;
+use super::fp2::FP2;
+use super::ecp2::ECP2;
+use super::fp4::FP4;
+use super::fp12;
+use super::fp12::FP12;
+use super::big::BIG;
+use super::dbig::DBIG;
+use super::ecp;
+use super::rom;
+use types::{SexticTwist, CurvePairingType, SignOfX};
+
+#[allow(non_snake_case)]
+fn linedbl(A: &mut ECP2, qx: &FP, qy: &FP) -> FP12 {
+ let mut a = FP4::new();
+ let mut b = FP4::new();
+ let mut c = FP4::new();
+
+ let mut xx = FP2::new_copy(&A.getpx()); //X
+ let mut yy = FP2::new_copy(&A.getpy()); //Y
+ let mut zz = FP2::new_copy(&A.getpz()); //Z
+ let mut yz = FP2::new_copy(&yy); //Y
+ yz.mul(&zz); //YZ
+ xx.sqr(); //X^2
+ yy.sqr(); //Y^2
+ zz.sqr(); //Z^2
+
+ yz.imul(4);
+ yz.neg();
+ yz.norm(); //-2YZ
+ yz.pmul(qy); //-2YZ.Ys
+
+ xx.imul(6); //3X^2
+ xx.pmul(qx); //3X^2.Xs
+
+ let sb = 3 * rom::CURVE_B_I;
+ zz.imul(sb);
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ zz.div_ip2();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ zz.mul_ip();
+ zz.dbl();
+ yz.mul_ip();
+ yz.norm();
+ }
+
+ zz.norm(); // 3b.Z^2
+
+ yy.dbl();
+ zz.sub(&yy);
+ zz.norm(); // 3b.Z^2-Y^2
+
+ a.copy(&FP4::new_fp2s(&yz, &zz)); // -2YZ.Ys | 3b.Z^2-Y^2 | 3X^2.Xs
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.copy(&FP4::new_fp2(&xx)); // L(0,1) | L(0,0) | L(1,0)
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ c.copy(&FP4::new_fp2(&xx));
+ c.times_i();
+ }
+ A.dbl();
+ let mut res= FP12::new_fp4s(&a, &b, &c);
+ res.settype(fp12::SPARSER);
+ return res;
+}
+
+#[allow(non_snake_case)]
+fn lineadd(A: &mut ECP2, B: &ECP2, qx: &FP, qy: &FP) -> FP12 {
+ let mut a = FP4::new();
+ let mut b = FP4::new();
+ let mut c = FP4::new();
+
+ let mut x1 = FP2::new_copy(&A.getpx()); // X1
+ let mut y1 = FP2::new_copy(&A.getpy()); // Y1
+ let mut t1 = FP2::new_copy(&A.getpz()); // Z1
+ let mut t2 = FP2::new_copy(&A.getpz()); // Z1
+
+ t1.mul(&B.getpy()); // T1=Z1.Y2
+ t2.mul(&B.getpx()); // T2=Z1.X2
+
+ x1.sub(&t2);
+ x1.norm(); // X1=X1-Z1.X2
+ y1.sub(&t1);
+ y1.norm(); // Y1=Y1-Z1.Y2
+
+ t1.copy(&x1); // T1=X1-Z1.X2
+ x1.pmul(qy); // X1=(X1-Z1.X2).Ys
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ x1.mul_ip();
+ x1.norm();
+ }
+
+ t1.mul(&B.getpy()); // T1=(X1-Z1.X2).Y2
+
+ t2.copy(&y1); // T2=Y1-Z1.Y2
+ t2.mul(&B.getpx()); // T2=(Y1-Z1.Y2).X2
+ t2.sub(&t1);
+ t2.norm(); // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2
+ y1.pmul(qx);
+ y1.neg();
+ y1.norm(); // Y1=-(Y1-Z1.Y2).Xs
+
+ a.copy(&FP4::new_fp2s(&x1, &t2)); // (X1-Z1.X2).Ys | (Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 | - (Y1-Z1.Y2).Xs
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.copy(&FP4::new_fp2(&y1));
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ c.copy(&FP4::new_fp2(&y1));
+ c.times_i();
+ }
+
+ A.add(B);
+ let mut res= FP12::new_fp4s(&a, &b, &c);
+ res.settype(fp12::SPARSER);
+ return res;
+}
+
+/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
+#[allow(non_snake_case)]
+fn lbits(n3: &mut BIG,n: &mut BIG) -> usize {
+ n.copy(&BIG::new_ints(&rom::CURVE_BNX));
+ if ecp::CURVE_PAIRING_TYPE==CurvePairingType::BN {
+ n.pmul(6);
+ if ecp::SIGN_OF_X==SignOfX::POSITIVEX {
+ n.inc(2);
+ } else {
+ n.dec(2);
+ }
+ }
+ n.norm();
+ n3.copy(&n);
+ n3.pmul(3);
+ n3.norm();
+ return n3.nbits();
+}
+
+/* prepare for multi-pairing */
+pub fn initmp() -> [FP12; rom::ATE_BITS] {
+ let r: [FP12; rom::ATE_BITS] = [FP12::new_int(1); rom::ATE_BITS];
+ return r
+}
+
+/* basic Miller loop */
+pub fn miller(r:&[FP12]) -> FP12 {
+ let mut res=FP12::new_int(1);
+ for i in (1..rom::ATE_BITS).rev() {
+ res.sqr();
+ res.ssmul(&r[i]);
+ }
+
+ if ecp::SIGN_OF_X==SignOfX::NEGATIVEX {
+ res.conj();
+ }
+ res.ssmul(&r[0]);
+ return res;
+}
+
+/* Accumulate another set of line functions for n-pairing */
+#[allow(non_snake_case)]
+pub fn another(r:&mut [FP12],P1: &ECP2,Q1: &ECP) {
+ let mut f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+ let mut K = ECP2::new();
+
+
+// P is needed in affine form for line function, Q for (Qx,Qy) extraction
+ let mut P = ECP2::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+
+ if ecp::CURVE_PAIRING_TYPE==CurvePairingType::BN {
+ if ecp::SEXTIC_TWIST==SexticTwist::M_TYPE {
+ f.inverse();
+ f.norm();
+ }
+ }
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+ let mut A = ECP2::new();
+
+ A.copy(&P);
+ let mut NP = ECP2::new();
+ NP.copy(&P);
+ NP.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb-1).rev() {
+ let mut lv=linedbl(&mut A,&qx,&qy);
+
+ let bt=n3.bit(i)-n.bit(i);
+ if bt==1 {
+ let lv2=lineadd(&mut A,&P,&qx,&qy);
+ lv.smul(&lv2);
+ }
+ if bt==-1 {
+ let lv2=lineadd(&mut A,&NP,&qx,&qy);
+ lv.smul(&lv2);
+ }
+ r[i].ssmul(&lv);
+ }
+
+/* R-ate fixup required for BN curves */
+ if ecp::CURVE_PAIRING_TYPE==CurvePairingType::BN {
+ if ecp::SIGN_OF_X==SignOfX::NEGATIVEX {
+ A.neg();
+ }
+ K.copy(&P);
+ K.frob(&f);
+ let mut lv=lineadd(&mut A,&K,&qx,&qy);
+ K.frob(&f);
+ K.neg();
+ let lv2=lineadd(&mut A,&K,&qx,&qy);
+ lv.smul(&lv2);
+ r[0].ssmul(&lv);
+ }
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate pairing */
+pub fn ate(P1: &ECP2, Q1: &ECP) -> FP12 {
+ let mut f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+ let mut K = ECP2::new();
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ f.inverse();
+ f.norm();
+ }
+ }
+ let mut P = ECP2::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+
+ let mut A = ECP2::new();
+ let mut r = FP12::new_int(1);
+
+ A.copy(&P);
+ let mut NP = ECP2::new();
+ NP.copy(&P);
+ NP.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb - 1).rev() {
+ r.sqr();
+ let mut lv = linedbl(&mut A, &qx, &qy);
+ let bt = n3.bit(i) - n.bit(i);
+ if bt == 1 {
+ let lv2 = lineadd(&mut A, &P, &qx, &qy);
+ lv.smul(&lv2);
+ }
+ if bt == -1 {
+ let lv2 = lineadd(&mut A, &NP, &qx, &qy);
+ lv.smul(&lv2);
+ }
+ r.ssmul(&lv);
+ }
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ r.conj();
+ }
+
+ /* R-ate fixup required for BN curves */
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ A.neg();
+ }
+
+ K.copy(&P);
+ K.frob(&f);
+
+ let mut lv = lineadd(&mut A, &K, &qx, &qy);
+ K.frob(&f);
+ K.neg();
+ let lv2 = lineadd(&mut A, &K, &qx, &qy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+
+ return r;
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate double pairing e(P,Q).e(R,S) */
+pub fn ate2(P1: &ECP2, Q1: &ECP, R1: &ECP2, S1: &ECP) -> FP12 {
+ let mut f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+ let mut K = ECP2::new();
+
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ f.inverse();
+ f.norm();
+ }
+ }
+
+ let mut P = ECP2::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+ let mut R = ECP2::new();
+ R.copy(R1);
+ R.affine();
+ let mut S = ECP::new();
+ S.copy(S1);
+ S.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+
+ let sx = FP::new_copy(&S.getpx());
+ let sy = FP::new_copy(&S.getpy());
+
+ let mut A = ECP2::new();
+ let mut B = ECP2::new();
+ let mut r = FP12::new_int(1);
+
+ A.copy(&P);
+ B.copy(&R);
+
+ let mut NP = ECP2::new();
+ NP.copy(&P);
+ NP.neg();
+ let mut NR = ECP2::new();
+ NR.copy(&R);
+ NR.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb - 1).rev() {
+ r.sqr();
+ let mut lv = linedbl(&mut A, &qx, &qy);
+ let lv2 = linedbl(&mut B, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ let bt = n3.bit(i) - n.bit(i);
+ if bt == 1 {
+ lv = lineadd(&mut A, &P, &qx, &qy);
+ let lv2 = lineadd(&mut B, &R, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+ if bt == -1 {
+ lv = lineadd(&mut A, &NP, &qx, &qy);
+ let lv2 = lineadd(&mut B, &NR, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+ }
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ r.conj();
+ }
+
+ /* R-ate fixup */
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ A.neg();
+ B.neg();
+ }
+ K.copy(&P);
+ K.frob(&f);
+
+ let mut lv = lineadd(&mut A, &K, &qx, &qy);
+ K.frob(&f);
+ K.neg();
+ let mut lv2 = lineadd(&mut A, &K, &qx, &qy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+
+ K.copy(&R);
+ K.frob(&f);
+
+ lv = lineadd(&mut B, &K, &sx, &sy);
+ K.frob(&f);
+ K.neg();
+ lv2 = lineadd(&mut B, &K, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+
+ }
+
+ return r;
+}
+
+/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */
+pub fn fexp(m: &FP12) -> FP12 {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let mut x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut r = FP12::new_copy(m);
+
+ /* Easy part of final exp */
+ let mut lv = FP12::new_copy(&r);
+ lv.inverse();
+ r.conj();
+
+ r.mul(&lv);
+ lv.copy(&r);
+ r.frob(&f);
+ r.frob(&f);
+ r.mul(&lv);
+// if r.isunity() {
+// r.zero();
+// return r;
+// }
+
+ /* Hard part of final exp */
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ lv.copy(&r);
+ lv.frob(&f);
+ let mut x0 = FP12::new_copy(&lv);
+ x0.frob(&f);
+ lv.mul(&r);
+ x0.mul(&lv);
+ x0.frob(&f);
+ let mut x1 = FP12::new_copy(&r);
+ x1.conj();
+ let mut x4 = r.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::POSITIVEX {
+ x4.conj();
+ }
+
+ let mut x3 = FP12::new_copy(&x4);
+ x3.frob(&f);
+
+ let mut x2 = x4.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::POSITIVEX {
+ x2.conj();
+ }
+ let mut x5 = FP12::new_copy(&x2);
+ x5.conj();
+ lv = x2.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::POSITIVEX {
+ lv.conj();
+ }
+ x2.frob(&f);
+ r.copy(&x2);
+ r.conj();
+
+ x4.mul(&r);
+ x2.frob(&f);
+
+ r.copy(&lv);
+ r.frob(&f);
+ lv.mul(&r);
+
+ lv.usqr();
+ lv.mul(&x4);
+ lv.mul(&x5);
+ r.copy(&x3);
+ r.mul(&x5);
+ r.mul(&lv);
+ lv.mul(&x2);
+ r.usqr();
+ r.mul(&lv);
+ r.usqr();
+ lv.copy(&r);
+ lv.mul(&x1);
+ r.mul(&x0);
+ lv.usqr();
+ r.mul(&lv);
+ r.reduce();
+ } else {
+ // Ghamman & Fouotsa Method
+
+ let mut y0 = FP12::new_copy(&r);
+ y0.usqr();
+ let mut y1 = y0.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ y1.conj();
+ }
+ x.fshr(1);
+ let mut y2 = y1.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ y2.conj();
+ }
+ x.fshl(1);
+ let mut y3 = FP12::new_copy(&r);
+ y3.conj();
+ y1.mul(&y3);
+
+ y1.conj();
+ y1.mul(&y2);
+
+ y2 = y1.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ y2.conj();
+ }
+ y3 = y2.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ y3.conj();
+ }
+ y1.conj();
+ y3.mul(&y1);
+
+ y1.conj();
+ y1.frob(&f);
+ y1.frob(&f);
+ y1.frob(&f);
+ y2.frob(&f);
+ y2.frob(&f);
+ y1.mul(&y2);
+
+ y2 = y3.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ y2.conj();
+ }
+ y2.mul(&y0);
+ y2.mul(&r);
+
+ y1.mul(&y2);
+ y2.copy(&y3);
+ y2.frob(&f);
+ y1.mul(&y2);
+ r.copy(&y1);
+ r.reduce();
+ }
+ return r;
+}
+
+#[allow(non_snake_case)]
+/* GLV method */
+fn glv(e: &BIG) -> [BIG; 2] {
+ let mut u: [BIG; 2] = [BIG::new(), BIG::new()];
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ let mut t = BIG::new();
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut v: [BIG; 2] = [BIG::new(), BIG::new()];
+
+ for i in 0..2 {
+ t.copy(&BIG::new_ints(&rom::CURVE_W[i])); // why not just t=new BIG(ROM.CURVE_W[i]);
+ let mut d: DBIG = BIG::mul(&t, e);
+ v[i].copy(&d.div(&q));
+ }
+ u[0].copy(&e);
+ for i in 0..2 {
+ for j in 0..2 {
+ t = BIG::new_ints(&rom::CURVE_SB[j][i]);
+ t = BIG::modmul(&mut v[j], &mut t, &q);
+ u[i].add(&q);
+ u[i].sub(&t);
+ u[i].rmod(&q);
+ }
+ }
+ } else {
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let x = BIG::new_ints(&rom::CURVE_BNX);
+ let x2 = BIG::smul(&x, &x);
+ u[0].copy(&e);
+ u[0].rmod(&x2);
+ u[1].copy(&e);
+ u[1].div(&x2);
+ u[1].rsub(&q);
+ }
+ return u;
+}
+
+#[allow(non_snake_case)]
+/* Galbraith & Scott Method */
+pub fn gs(e: &BIG) -> [BIG; 4] {
+ let mut u: [BIG; 4] = [BIG::new(), BIG::new(), BIG::new(), BIG::new()];
+ if ecp::CURVE_PAIRING_TYPE == CurvePairingType::BN {
+ let mut t = BIG::new();
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+
+ let mut v: [BIG; 4] = [BIG::new(), BIG::new(), BIG::new(), BIG::new()];
+ for i in 0..4 {
+ t.copy(&BIG::new_ints(&rom::CURVE_WB[i]));
+ let mut d: DBIG = BIG::mul(&t, e);
+ v[i].copy(&d.div(&q));
+ }
+ u[0].copy(&e);
+ for i in 0..4 {
+ for j in 0..4 {
+ t = BIG::new_ints(&rom::CURVE_BB[j][i]);
+ t = BIG::modmul(&mut v[j], &mut t, &q);
+ u[i].add(&q);
+ u[i].sub(&t);
+ u[i].rmod(&q);
+ }
+ }
+ } else {
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut w = BIG::new_copy(&e);
+ for i in 0..3 {
+ u[i].copy(&w);
+ u[i].rmod(&x);
+ w.div(&x);
+ }
+ u[3].copy(&w);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ let mut t = BIG::new();
+ t.copy(&BIG::modneg(&mut u[1], &q));
+ u[1].copy(&t);
+ t.copy(&BIG::modneg(&mut u[3], &q));
+ u[3].copy(&t);
+ }
+ }
+ return u;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G1 */
+pub fn g1mul(P: &ECP, e: &mut BIG) -> ECP {
+ let mut R = ECP::new();
+ if rom::USE_GLV {
+ R.copy(P);
+ let mut Q = ECP::new();
+ Q.copy(P);
+ Q.affine();
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut cru = FP::new_big(&BIG::new_ints(&rom::CURVE_CRU));
+ let mut u = glv(e);
+ Q.mulx(&mut cru);
+
+ let mut np = u[0].nbits();
+ let mut t: BIG = BIG::modneg(&mut u[0], &q);
+ let mut nn = t.nbits();
+ if nn < np {
+ u[0].copy(&t);
+ R.neg();
+ }
+
+ np = u[1].nbits();
+ t = BIG::modneg(&mut u[1], &q);
+ nn = t.nbits();
+ if nn < np {
+ u[1].copy(&t);
+ Q.neg();
+ }
+ u[0].norm();
+ u[1].norm();
+ R = R.mul2(&u[0], &mut Q, &u[1]);
+ } else {
+ R = P.mul(e);
+ }
+ return R;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G2 */
+pub fn g2mul(P: &ECP2, e: &BIG) -> ECP2 {
+ let mut R = ECP2::new();
+ if rom::USE_GS_G2 {
+ let mut Q: [ECP2; 4] = [ECP2::new(), ECP2::new(), ECP2::new(), ECP2::new()];
+ let mut f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut u = gs(e);
+ let mut T = ECP2::new();
+
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ f.inverse();
+ f.norm();
+ }
+
+ let mut t = BIG::new();
+ Q[0].copy(&P);
+ for i in 1..4 {
+ T.copy(&Q[i - 1]);
+ Q[i].copy(&T);
+ Q[i].frob(&f);
+ }
+ for i in 0..4 {
+ let np = u[i].nbits();
+ t.copy(&BIG::modneg(&mut u[i], &q));
+ let nn = t.nbits();
+ if nn < np {
+ u[i].copy(&t);
+ Q[i].neg();
+ }
+ u[i].norm();
+ }
+
+ R.copy(&ECP2::mul4(&mut Q, &u));
+ } else {
+ R.copy(&P.mul(e));
+ }
+ return R;
+}
+
+/* f=f^e */
+/* Note that this method requires a lot of RAM! Better to use compressed XTR method, see FP4.java */
+pub fn gtpow(d: &FP12, e: &BIG) -> FP12 {
+ let mut r = FP12::new();
+ if rom::USE_GS_GT {
+ let mut g: [FP12; 4] = [FP12::new(), FP12::new(), FP12::new(), FP12::new()];
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut t = BIG::new();
+ let mut u = gs(e);
+ let mut w = FP12::new();
+
+ g[0].copy(&d);
+ for i in 1..4 {
+ w.copy(&g[i - 1]);
+ g[i].copy(&w);
+ g[i].frob(&f);
+ }
+ for i in 0..4 {
+ let np = u[i].nbits();
+ t.copy(&BIG::modneg(&mut u[i], &q));
+ let nn = t.nbits();
+ if nn < np {
+ u[i].copy(&t);
+ g[i].conj();
+ }
+ u[i].norm();
+ }
+ r.copy(&FP12::pow4(&mut g, &u));
+ } else {
+ r.copy(&d.pow(e));
+ }
+ return r;
+}
diff --git a/src/pair192.rs b/src/pair192.rs
new file mode 100644
index 0000000..4310b6b
--- /dev/null
+++ b/src/pair192.rs
@@ -0,0 +1,606 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+
+use super::fp::FP;
+use super::ecp::ECP;
+use super::fp2::FP2;
+use super::ecp4::ECP4;
+use super::fp4::FP4;
+use super::fp8::FP8;
+use super::fp24;
+use super::fp24::FP24;
+use super::big::BIG;
+use super::ecp;
+use super::rom;
+use types::{SexticTwist, SignOfX};
+
+#[allow(non_snake_case)]
+fn linedbl(A: &mut ECP4, qx: &FP, qy: &FP) -> FP24 {
+ let mut a = FP8::new();
+ let mut b = FP8::new();
+ let mut c = FP8::new();
+
+ let mut xx = FP4::new_copy(&A.getpx()); //X
+ let mut yy = FP4::new_copy(&A.getpy()); //Y
+ let mut zz = FP4::new_copy(&A.getpz()); //Z
+ let mut yz = FP4::new_copy(&yy); //Y
+ yz.mul(&zz); //YZ
+ xx.sqr(); //X^2
+ yy.sqr(); //Y^2
+ zz.sqr(); //Z^2
+
+ yz.imul(4);
+ yz.neg();
+ yz.norm(); //-2YZ
+ yz.qmul(qy); //-2YZ.Ys
+
+ xx.imul(6); //3X^2
+ xx.qmul(qx); //3X^2.Xs
+
+ let sb = 3 * rom::CURVE_B_I;
+ zz.imul(sb);
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ zz.div_2i();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ zz.times_i();
+ zz.dbl();
+ yz.times_i();
+ }
+
+ zz.norm(); // 3b.Z^2
+
+ yy.dbl();
+ zz.sub(&yy);
+ zz.norm(); // 3b.Z^2-Y^2
+
+ a.copy(&FP8::new_fp4s(&yz, &zz)); // -2YZ.Ys | 3b.Z^2-Y^2 | 3X^2.Xs
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.copy(&FP8::new_fp4(&xx)); // L(0,1) | L(0,0) | L(1,0)
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ c.copy(&FP8::new_fp4(&xx));
+ c.times_i();
+ }
+ A.dbl();
+ let mut res= FP24::new_fp8s(&a, &b, &c);
+ res.settype(fp24::SPARSER);
+ return res;
+}
+
+#[allow(non_snake_case)]
+fn lineadd(A: &mut ECP4, B: &ECP4, qx: &FP, qy: &FP) -> FP24 {
+ let mut a = FP8::new();
+ let mut b = FP8::new();
+ let mut c = FP8::new();
+
+ let mut x1 = FP4::new_copy(&A.getpx()); // X1
+ let mut y1 = FP4::new_copy(&A.getpy()); // Y1
+ let mut t1 = FP4::new_copy(&A.getpz()); // Z1
+ let mut t2 = FP4::new_copy(&A.getpz()); // Z1
+
+ t1.mul(&B.getpy()); // T1=Z1.Y2
+ t2.mul(&B.getpx()); // T2=Z1.X2
+
+ x1.sub(&t2);
+ x1.norm(); // X1=X1-Z1.X2
+ y1.sub(&t1);
+ y1.norm(); // Y1=Y1-Z1.Y2
+
+ t1.copy(&x1); // T1=X1-Z1.X2
+ x1.qmul(qy); // X1=(X1-Z1.X2).Ys
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ x1.times_i();
+ }
+
+ t1.mul(&B.getpy()); // T1=(X1-Z1.X2).Y2
+
+ t2.copy(&y1); // T2=Y1-Z1.Y2
+ t2.mul(&B.getpx()); // T2=(Y1-Z1.Y2).X2
+ t2.sub(&t1);
+ t2.norm(); // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2
+ y1.qmul(qx);
+ y1.neg();
+ y1.norm(); // Y1=-(Y1-Z1.Y2).Xs
+
+ a.copy(&FP8::new_fp4s(&x1, &t2)); // (X1-Z1.X2).Ys | (Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 | - (Y1-Z1.Y2).Xs
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.copy(&FP8::new_fp4(&y1));
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ c.copy(&FP8::new_fp4(&y1));
+ c.times_i();
+ }
+
+ A.add(B);
+ let mut res= FP24::new_fp8s(&a, &b, &c);
+ res.settype(fp24::SPARSER);
+ return res;
+}
+
+/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
+#[allow(non_snake_case)]
+fn lbits(n3: &mut BIG,n: &mut BIG) -> usize {
+ n.copy(&BIG::new_ints(&rom::CURVE_BNX));
+ n3.copy(&n);
+ n3.pmul(3);
+ n3.norm();
+ return n3.nbits();
+}
+
+/* prepare for multi-pairing */
+pub fn initmp() -> [FP24; rom::ATE_BITS] {
+ let r: [FP24; rom::ATE_BITS] = [FP24::new_int(1); rom::ATE_BITS];
+ return r
+}
+
+/* basic Miller loop */
+pub fn miller(r:&[FP24]) -> FP24 {
+ let mut res=FP24::new_int(1);
+ for i in (1..rom::ATE_BITS).rev() {
+ res.sqr();
+ res.ssmul(&r[i]);
+ }
+
+ if ecp::SIGN_OF_X==SignOfX::NEGATIVEX {
+ res.conj();
+ }
+ res.ssmul(&r[0]);
+ return res;
+}
+
+/* Accumulate another set of line functions for n-pairing */
+#[allow(non_snake_case)]
+pub fn another(r:&mut [FP24],P1: &ECP4,Q1: &ECP) {
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+
+// P is needed in affine form for line function, Q for (Qx,Qy) extraction
+ let mut P = ECP4::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+ let mut A = ECP4::new();
+
+ A.copy(&P);
+ let mut NP = ECP4::new();
+ NP.copy(&P);
+ NP.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb-1).rev() {
+ let mut lv=linedbl(&mut A,&qx,&qy);
+
+ let bt=n3.bit(i)-n.bit(i);
+ if bt==1 {
+ let lv2=lineadd(&mut A,&P,&qx,&qy);
+ lv.smul(&lv2);
+ }
+ if bt==-1 {
+ let lv2=lineadd(&mut A,&NP,&qx,&qy);
+ lv.smul(&lv2);
+ }
+ r[i].ssmul(&lv);
+ }
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate pairing */
+pub fn ate(P1: &ECP4, Q1: &ECP) -> FP24 {
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+
+ let mut P = ECP4::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+
+ let mut A = ECP4::new();
+ let mut r = FP24::new_int(1);
+
+ A.copy(&P);
+ let mut NP = ECP4::new();
+ NP.copy(&P);
+ NP.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb - 1).rev() {
+ r.sqr();
+
+ let mut lv = linedbl(&mut A, &qx, &qy);
+
+ let bt = n3.bit(i) - n.bit(i);
+ if bt == 1 {
+ let lv2 = lineadd(&mut A, &P, &qx, &qy);
+ lv.smul(&lv2);
+ }
+ if bt == -1 {
+ let lv2 = lineadd(&mut A, &NP, &qx, &qy);
+ lv.smul(&lv2);
+ }
+ r.ssmul(&lv);
+ }
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ r.conj();
+ }
+
+ return r;
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate double pairing e(P,Q).e(R,S) */
+pub fn ate2(P1: &ECP4, Q1: &ECP, R1: &ECP4, S1: &ECP) -> FP24 {
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+
+ let mut P = ECP4::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+ let mut R = ECP4::new();
+ R.copy(R1);
+ R.affine();
+ let mut S = ECP::new();
+ S.copy(S1);
+ S.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+
+ let sx = FP::new_copy(&S.getpx());
+ let sy = FP::new_copy(&S.getpy());
+
+ let mut A = ECP4::new();
+ let mut B = ECP4::new();
+ let mut r = FP24::new_int(1);
+
+ A.copy(&P);
+ B.copy(&R);
+
+ let mut NP = ECP4::new();
+ NP.copy(&P);
+ NP.neg();
+ let mut NR = ECP4::new();
+ NR.copy(&R);
+ NR.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb - 1).rev() {
+ r.sqr();
+ let mut lv = linedbl(&mut A, &qx, &qy);
+ let lv2 = linedbl(&mut B, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ let bt = n3.bit(i) - n.bit(i);
+ if bt == 1 {
+ lv = lineadd(&mut A, &P, &qx, &qy);
+ let lv2 = lineadd(&mut B, &R, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+ if bt == -1 {
+ lv = lineadd(&mut A, &NP, &qx, &qy);
+ let lv2 = lineadd(&mut B, &NR, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+ }
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ r.conj();
+ }
+
+ return r;
+}
+
+/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */
+pub fn fexp(m: &FP24) -> FP24 {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let mut x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut r = FP24::new_copy(m);
+
+ /* Easy part of final exp */
+ let mut lv = FP24::new_copy(&r);
+ lv.inverse();
+ r.conj();
+
+ r.mul(&lv);
+ lv.copy(&r);
+ r.frob(&f, 4);
+ r.mul(&lv);
+// if r.isunity() {
+// r.zero();
+// return r;
+// }
+ /* Hard part of final exp */
+ // Ghamman & Fouotsa Method
+
+ let mut t7 = FP24::new_copy(&r);
+ t7.usqr();
+ let mut t1 = t7.pow(&mut x);
+
+ x.fshr(1);
+ let mut t2 = t1.pow(&mut x);
+ x.fshl(1);
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+ let mut t3 = FP24::new_copy(&t1);
+ t3.conj();
+ t2.mul(&t3);
+ t2.mul(&r);
+
+ t3.copy(&t2.pow(&mut x));
+ let mut t4 = t3.pow(&mut x);
+ let mut t5 = t4.pow(&mut x);
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t3.conj();
+ t5.conj();
+ }
+
+ t3.frob(&f, 6);
+ t4.frob(&f, 5);
+ t3.mul(&t4);
+
+ let mut t6 = t5.pow(&mut x);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t6.conj();
+ }
+
+ t5.frob(&f, 4);
+ t3.mul(&t5);
+
+ let mut t0 = FP24::new_copy(&t2);
+ t0.conj();
+ t6.mul(&t0);
+
+ t5.copy(&t6);
+ t5.frob(&f, 3);
+
+ t3.mul(&t5);
+ t5.copy(&t6.pow(&mut x));
+ t6.copy(&t5.pow(&mut x));
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t5.conj();
+ }
+
+ t0.copy(&t5);
+ t0.frob(&f, 2);
+ t3.mul(&t0);
+ t0.copy(&t6);
+ t0.frob(&f, 1);
+
+ t3.mul(&t0);
+ t5.copy(&t6.pow(&mut x));
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t5.conj();
+ }
+ t2.frob(&f, 7);
+
+ t5.mul(&t7);
+ t3.mul(&t2);
+ t3.mul(&t5);
+
+ r.mul(&t3);
+
+ r.reduce();
+ return r;
+}
+
+#[allow(non_snake_case)]
+/* GLV method */
+fn glv(e: &BIG) -> [BIG; 2] {
+ let mut u: [BIG; 2] = [BIG::new(), BIG::new()];
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut x = BIG::new_ints(&rom::CURVE_BNX);
+ let x2 = BIG::smul(&x, &x);
+ x.copy(&BIG::smul(&x2, &x2));
+ u[0].copy(&e);
+ u[0].rmod(&x);
+ u[1].copy(&e);
+ u[1].div(&x);
+ u[1].rsub(&q);
+
+ return u;
+}
+
+#[allow(non_snake_case)]
+/* Galbraith & Scott Method */
+pub fn gs(e: &BIG) -> [BIG; 8] {
+ let mut u: [BIG; 8] = [
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ ];
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut w = BIG::new_copy(&e);
+ for i in 0..7 {
+ u[i].copy(&w);
+ u[i].rmod(&x);
+ w.div(&x);
+ }
+ u[7].copy(&w);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ let mut t = BIG::new();
+ t.copy(&BIG::modneg(&mut u[1], &q));
+ u[1].copy(&t);
+ t.copy(&BIG::modneg(&mut u[3], &q));
+ u[3].copy(&t);
+ t.copy(&BIG::modneg(&mut u[5], &q));
+ u[5].copy(&t);
+ t.copy(&BIG::modneg(&mut u[7], &q));
+ u[7].copy(&t);
+ }
+ return u;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G1 */
+pub fn g1mul(P: &ECP, e: &mut BIG) -> ECP {
+ let mut R = ECP::new();
+ if rom::USE_GLV {
+ R.copy(P);
+ let mut Q = ECP::new();
+ Q.copy(P);
+ Q.affine();
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut cru = FP::new_big(&BIG::new_ints(&rom::CURVE_CRU));
+ let mut u = glv(e);
+ Q.mulx(&mut cru);
+
+ let mut np = u[0].nbits();
+ let mut t: BIG = BIG::modneg(&mut u[0], &q);
+ let mut nn = t.nbits();
+ if nn < np {
+ u[0].copy(&t);
+ R.neg();
+ }
+
+ np = u[1].nbits();
+ t = BIG::modneg(&mut u[1], &q);
+ nn = t.nbits();
+ if nn < np {
+ u[1].copy(&t);
+ Q.neg();
+ }
+ u[0].norm();
+ u[1].norm();
+ R = R.mul2(&u[0], &mut Q, &u[1]);
+ } else {
+ R = P.mul(e);
+ }
+ return R;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G2 */
+pub fn g2mul(P: &ECP4, e: &BIG) -> ECP4 {
+ let mut R = ECP4::new();
+ if rom::USE_GS_G2 {
+ let mut Q: [ECP4; 8] = [
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ECP4::new(),
+ ];
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut u = gs(e);
+ let mut T = ECP4::new();
+
+ let f = ECP4::frob_constants();
+
+ let mut t = BIG::new();
+ Q[0].copy(&P);
+ for i in 1..8 {
+ T.copy(&Q[i - 1]);
+ Q[i].copy(&T);
+ Q[i].frob(&f, 1);
+ }
+ for i in 0..8 {
+ let np = u[i].nbits();
+ t.copy(&BIG::modneg(&mut u[i], &q));
+ let nn = t.nbits();
+ if nn < np {
+ u[i].copy(&t);
+ Q[i].neg();
+ }
+ u[i].norm();
+ }
+
+ R.copy(&ECP4::mul8(&mut Q, &u));
+ } else {
+ R.copy(&P.mul(e));
+ }
+ return R;
+}
+
+/* f=f^e */
+/* Note that this method requires a lot of RAM! Better to use compressed XTR method, see FP4.java */
+pub fn gtpow(d: &FP24, e: &BIG) -> FP24 {
+ let mut r = FP24::new();
+ if rom::USE_GS_GT {
+ let mut g: [FP24; 8] = [
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ FP24::new(),
+ ];
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut t = BIG::new();
+ let mut u = gs(e);
+ let mut w = FP24::new();
+
+ g[0].copy(&d);
+ for i in 1..8 {
+ w.copy(&g[i - 1]);
+ g[i].copy(&w);
+ g[i].frob(&f, 1);
+ }
+ for i in 0..8 {
+ let np = u[i].nbits();
+ t.copy(&BIG::modneg(&mut u[i], &q));
+ let nn = t.nbits();
+ if nn < np {
+ u[i].copy(&t);
+ g[i].conj();
+ }
+ u[i].norm();
+ }
+ r.copy(&FP24::pow8(&mut g, &u));
+ } else {
+ r.copy(&d.pow(e));
+ }
+ return r;
+}
diff --git a/src/pair256.rs b/src/pair256.rs
new file mode 100644
index 0000000..7cdca72
--- /dev/null
+++ b/src/pair256.rs
@@ -0,0 +1,722 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+
+use super::fp::FP;
+use super::ecp::ECP;
+use super::fp2::FP2;
+use super::ecp8::ECP8;
+use super::fp8::FP8;
+use super::fp16::FP16;
+use super::fp48;
+use super::fp48::FP48;
+use super::big::BIG;
+use super::ecp;
+use super::rom;
+use types::{SignOfX, SexticTwist};
+
+#[allow(non_snake_case)]
+fn linedbl(A: &mut ECP8, qx: &FP, qy: &FP) -> FP48 {
+ let mut a = FP16::new();
+ let mut b = FP16::new();
+ let mut c = FP16::new();
+
+ let mut xx = FP8::new_copy(&A.getpx()); //X
+ let mut yy = FP8::new_copy(&A.getpy()); //Y
+ let mut zz = FP8::new_copy(&A.getpz()); //Z
+ let mut yz = FP8::new_copy(&yy); //Y
+ yz.mul(&zz); //YZ
+ xx.sqr(); //X^2
+ yy.sqr(); //Y^2
+ zz.sqr(); //Z^2
+
+ yz.imul(4);
+ yz.neg();
+ yz.norm(); //-2YZ
+ yz.tmul(qy); //-2YZ.Ys
+
+ xx.imul(6); //3X^2
+ xx.tmul(qx); //3X^2.Xs
+
+ let sb = 3 * rom::CURVE_B_I;
+ zz.imul(sb);
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ zz.div_2i();
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ zz.times_i();
+ zz.dbl();
+ yz.times_i();
+ }
+
+ zz.norm(); // 3b.Z^2
+
+ yy.dbl();
+ zz.sub(&yy);
+ zz.norm(); // 3b.Z^2-Y^2
+
+ a.copy(&FP16::new_fp8s(&yz, &zz)); // -2YZ.Ys | 3b.Z^2-Y^2 | 3X^2.Xs
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.copy(&FP16::new_fp8(&xx)); // L(0,1) | L(0,0) | L(1,0)
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ c.copy(&FP16::new_fp8(&xx));
+ c.times_i();
+ }
+ A.dbl();
+ let mut res= FP48::new_fp16s(&a, &b, &c);
+ res.settype(fp48::SPARSER);
+ return res;
+}
+
+#[allow(non_snake_case)]
+fn lineadd(A: &mut ECP8, B: &ECP8, qx: &FP, qy: &FP) -> FP48 {
+ let mut a = FP16::new();
+ let mut b = FP16::new();
+ let mut c = FP16::new();
+
+ let mut x1 = FP8::new_copy(&A.getpx()); // X1
+ let mut y1 = FP8::new_copy(&A.getpy()); // Y1
+ let mut t1 = FP8::new_copy(&A.getpz()); // Z1
+ let mut t2 = FP8::new_copy(&A.getpz()); // Z1
+
+ t1.mul(&B.getpy()); // T1=Z1.Y2
+ t2.mul(&B.getpx()); // T2=Z1.X2
+
+ x1.sub(&t2);
+ x1.norm(); // X1=X1-Z1.X2
+ y1.sub(&t1);
+ y1.norm(); // Y1=Y1-Z1.Y2
+
+ t1.copy(&x1); // T1=X1-Z1.X2
+ x1.tmul(qy); // X1=(X1-Z1.X2).Ys
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ x1.times_i();
+ }
+
+ t1.mul(&B.getpy()); // T1=(X1-Z1.X2).Y2
+
+ t2.copy(&y1); // T2=Y1-Z1.Y2
+ t2.mul(&B.getpx()); // T2=(Y1-Z1.Y2).X2
+ t2.sub(&t1);
+ t2.norm(); // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2
+ y1.tmul(qx);
+ y1.neg();
+ y1.norm(); // Y1=-(Y1-Z1.Y2).Xs
+
+ a.copy(&FP16::new_fp8s(&x1, &t2)); // (X1-Z1.X2).Ys | (Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 | - (Y1-Z1.Y2).Xs
+ if ecp::SEXTIC_TWIST == SexticTwist::D_TYPE {
+ b.copy(&FP16::new_fp8(&y1));
+ }
+ if ecp::SEXTIC_TWIST == SexticTwist::M_TYPE {
+ c.copy(&FP16::new_fp8(&y1));
+ c.times_i();
+ }
+
+ A.add(B);
+ let mut res= FP48::new_fp16s(&a, &b, &c);
+ res.settype(fp48::SPARSER);
+ return res;
+}
+
+/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
+#[allow(non_snake_case)]
+fn lbits(n3: &mut BIG,n: &mut BIG) -> usize {
+ n.copy(&BIG::new_ints(&rom::CURVE_BNX));
+ n3.copy(&n);
+ n3.pmul(3);
+ n3.norm();
+ return n3.nbits();
+}
+
+/* prepare for multi-pairing */
+pub fn initmp() -> [FP48; rom::ATE_BITS] {
+ let r: [FP48; rom::ATE_BITS] = [FP48::new_int(1); rom::ATE_BITS];
+ return r
+}
+
+/* basic Miller loop */
+pub fn miller(r:&[FP48]) -> FP48 {
+ let mut res=FP48::new_int(1);
+ for i in (1..rom::ATE_BITS).rev() {
+ res.sqr();
+ res.ssmul(&r[i]);
+ }
+
+ if ecp::SIGN_OF_X==SignOfX::NEGATIVEX {
+ res.conj();
+ }
+ res.ssmul(&r[0]);
+ return res;
+}
+
+/* Accumulate another set of line functions for n-pairing */
+#[allow(non_snake_case)]
+pub fn another(r:&mut [FP48],P1: &ECP8,Q1: &ECP) {
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+
+// P is needed in affine form for line function, Q for (Qx,Qy) extraction
+ let mut P = ECP8::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+ let mut A = ECP8::new();
+
+ A.copy(&P);
+ let mut NP = ECP8::new();
+ NP.copy(&P);
+ NP.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb-1).rev() {
+ let mut lv=linedbl(&mut A,&qx,&qy);
+
+ let bt=n3.bit(i)-n.bit(i);
+ if bt==1 {
+ let lv2=lineadd(&mut A,&P,&qx,&qy);
+ lv.smul(&lv2);
+ }
+ if bt==-1 {
+ let lv2=lineadd(&mut A,&NP,&qx,&qy);
+ lv.smul(&lv2);
+ }
+ r[i].ssmul(&lv);
+ }
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate pairing */
+pub fn ate(P1: &ECP8, Q1: &ECP) -> FP48 {
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+
+ let mut P = ECP8::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+
+ let mut A = ECP8::new();
+ let mut r = FP48::new_int(1);
+
+ A.copy(&P);
+ let mut NP = ECP8::new();
+ NP.copy(&P);
+ NP.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb - 1).rev() {
+ r.sqr();
+ let mut lv = linedbl(&mut A, &qx, &qy);
+ let bt = n3.bit(i) - n.bit(i);
+ if bt == 1 {
+ let lv2 = lineadd(&mut A, &P, &qx, &qy);
+ lv.smul(&lv2);
+ }
+ if bt == -1 {
+ let lv2 = lineadd(&mut A, &NP, &qx, &qy);
+ lv.smul(&lv2);
+ }
+ r.ssmul(&lv);
+ }
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ r.conj();
+ }
+
+ return r;
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate double pairing e(P,Q).e(R,S) */
+pub fn ate2(P1: &ECP8, Q1: &ECP, R1: &ECP8, S1: &ECP) -> FP48 {
+ let mut n = BIG::new();
+ let mut n3 = BIG::new();
+
+ let mut P = ECP8::new();
+ P.copy(P1);
+ P.affine();
+ let mut Q = ECP::new();
+ Q.copy(Q1);
+ Q.affine();
+ let mut R = ECP8::new();
+ R.copy(R1);
+ R.affine();
+ let mut S = ECP::new();
+ S.copy(S1);
+ S.affine();
+
+ let qx = FP::new_copy(&Q.getpx());
+ let qy = FP::new_copy(&Q.getpy());
+
+ let sx = FP::new_copy(&S.getpx());
+ let sy = FP::new_copy(&S.getpy());
+
+ let mut A = ECP8::new();
+ let mut B = ECP8::new();
+ let mut r = FP48::new_int(1);
+
+ A.copy(&P);
+ B.copy(&R);
+
+ let mut NP = ECP8::new();
+ NP.copy(&P);
+ NP.neg();
+ let mut NR = ECP8::new();
+ NR.copy(&R);
+ NR.neg();
+
+ let nb=lbits(&mut n3,&mut n);
+
+ for i in (1..nb - 1).rev() {
+ r.sqr();
+ let mut lv = linedbl(&mut A, &qx, &qy);
+ let lv2 = linedbl(&mut B, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ let bt = n3.bit(i) - n.bit(i);
+ if bt == 1 {
+ lv = lineadd(&mut A, &P, &qx, &qy);
+ let lv2 = lineadd(&mut B, &R, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+ if bt == -1 {
+ lv = lineadd(&mut A, &NP, &qx, &qy);
+ let lv2 = lineadd(&mut B, &NR, &sx, &sy);
+ lv.smul(&lv2);
+ r.ssmul(&lv);
+ }
+ }
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ r.conj();
+ }
+
+ return r;
+}
+
+/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */
+pub fn fexp(m: &FP48) -> FP48 {
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let mut x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut r = FP48::new_copy(m);
+
+ /* Easy part of final exp */
+ let mut lv = FP48::new_copy(&r);
+ lv.inverse();
+ r.conj();
+
+ r.mul(&lv);
+ lv.copy(&r);
+ r.frob(&f, 8);
+ r.mul(&lv);
+// if r.isunity() {
+// r.zero();
+// return r;
+// }
+ /* Hard part of final exp */
+ // Ghamman & Fouotsa Method
+
+ let mut t7 = FP48::new_copy(&r);
+ t7.usqr();
+ let mut t1 = t7.pow(&mut x);
+
+ x.fshr(1);
+ let mut t2 = t1.pow(&mut x);
+ x.fshl(1);
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ let mut t3 = FP48::new_copy(&t1);
+ t3.conj();
+ t2.mul(&t3);
+ t2.mul(&r);
+
+ r.mul(&t7);
+
+ t1.copy(&t2.pow(&mut x));
+
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+ t3.copy(&t1);
+ t3.frob(&f, 14);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 13);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 12);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 11);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 10);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 9);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 8);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t2);
+ t3.conj();
+ t1.mul(&t3);
+ t3.copy(&t1);
+ t3.frob(&f, 7);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 6);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 5);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 4);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 3);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 2);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ t3.copy(&t1);
+ t3.frob(&f, 1);
+ r.mul(&t3);
+ lv.copy(&t1.pow(&mut x));
+ t1.copy(&lv);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ t1.conj();
+ }
+
+ r.mul(&t1);
+ t2.frob(&f, 15);
+ r.mul(&t2);
+
+ r.reduce();
+ return r;
+}
+
+#[allow(non_snake_case)]
+/* GLV method */
+fn glv(e: &BIG) -> [BIG; 2] {
+ let mut u: [BIG; 2] = [BIG::new(), BIG::new()];
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut x2 = BIG::smul(&x, &x);
+ x.copy(&BIG::smul(&x2, &x2));
+ x2.copy(&BIG::smul(&x, &x));
+ u[0].copy(&e);
+ u[0].rmod(&x2);
+ u[1].copy(&e);
+ u[1].div(&x2);
+ u[1].rsub(&q);
+
+ return u;
+}
+
+#[allow(non_snake_case)]
+/* Galbraith & Scott Method */
+pub fn gs(e: &BIG) -> [BIG; 16] {
+ let mut u: [BIG; 16] = [
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ BIG::new(),
+ ];
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let x = BIG::new_ints(&rom::CURVE_BNX);
+ let mut w = BIG::new_copy(&e);
+ for i in 0..15 {
+ u[i].copy(&w);
+ u[i].rmod(&x);
+ w.div(&x);
+ }
+ u[15].copy(&w);
+ if ecp::SIGN_OF_X == SignOfX::NEGATIVEX {
+ let mut t = BIG::new();
+ t.copy(&BIG::modneg(&mut u[1], &q));
+ u[1].copy(&t);
+ t.copy(&BIG::modneg(&mut u[3], &q));
+ u[3].copy(&t);
+ t.copy(&BIG::modneg(&mut u[5], &q));
+ u[5].copy(&t);
+ t.copy(&BIG::modneg(&mut u[7], &q));
+ u[7].copy(&t);
+ t.copy(&BIG::modneg(&mut u[9], &q));
+ u[9].copy(&t);
+ t.copy(&BIG::modneg(&mut u[11], &q));
+ u[11].copy(&t);
+ t.copy(&BIG::modneg(&mut u[13], &q));
+ u[13].copy(&t);
+ t.copy(&BIG::modneg(&mut u[15], &q));
+ u[15].copy(&t);
+ }
+ return u;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G1 */
+pub fn g1mul(P: &ECP, e: &mut BIG) -> ECP {
+ let mut R = ECP::new();
+ if rom::USE_GLV {
+ R.copy(P);
+ let mut Q = ECP::new();
+ Q.copy(P);
+ Q.affine();
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut cru = FP::new_big(&BIG::new_ints(&rom::CURVE_CRU));
+ let mut u = glv(e);
+ Q.mulx(&mut cru);
+
+ let mut np = u[0].nbits();
+ let mut t: BIG = BIG::modneg(&mut u[0], &q);
+ let mut nn = t.nbits();
+ if nn < np {
+ u[0].copy(&t);
+ R.neg();
+ }
+
+ np = u[1].nbits();
+ t = BIG::modneg(&mut u[1], &q);
+ nn = t.nbits();
+ if nn < np {
+ u[1].copy(&t);
+ Q.neg();
+ }
+ u[0].norm();
+ u[1].norm();
+ R = R.mul2(&u[0], &mut Q, &u[1]);
+ } else {
+ R = P.mul(e);
+ }
+ return R;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G2 */
+pub fn g2mul(P: &ECP8, e: &BIG) -> ECP8 {
+ let mut R = ECP8::new();
+ if rom::USE_GS_G2 {
+ let mut Q: [ECP8; 16] = [
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ECP8::new(),
+ ];
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut u = gs(e);
+ let mut T = ECP8::new();
+
+ let f = ECP8::frob_constants();
+
+ let mut t = BIG::new();
+ Q[0].copy(&P);
+ for i in 1..16 {
+ T.copy(&Q[i - 1]);
+ Q[i].copy(&T);
+ Q[i].frob(&f, 1);
+ }
+ for i in 0..16 {
+ let np = u[i].nbits();
+ t.copy(&BIG::modneg(&mut u[i], &q));
+ let nn = t.nbits();
+ if nn < np {
+ u[i].copy(&t);
+ Q[i].neg();
+ }
+ u[i].norm();
+ }
+
+ R.copy(&ECP8::mul16(&mut Q, &u));
+ } else {
+ R.copy(&P.mul(e));
+ }
+ return R;
+}
+
+/* f=f^e */
+/* Note that this method requires a lot of RAM! Better to use compressed XTR method, see FP4.java */
+pub fn gtpow(d: &FP48, e: &BIG) -> FP48 {
+ let mut r = FP48::new();
+ if rom::USE_GS_GT {
+ let mut g: [FP48; 16] = [
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ FP48::new(),
+ ];
+ let f = FP2::new_bigs(&BIG::new_ints(&rom::FRA), &BIG::new_ints(&rom::FRB));
+ let q = BIG::new_ints(&rom::CURVE_ORDER);
+ let mut t = BIG::new();
+ let mut u = gs(e);
+ let mut w = FP48::new();
+
+ g[0].copy(&d);
+ for i in 1..16 {
+ w.copy(&g[i - 1]);
+ g[i].copy(&w);
+ g[i].frob(&f, 1);
+ }
+ for i in 0..16 {
+ let np = u[i].nbits();
+ t.copy(&BIG::modneg(&mut u[i], &q));
+ let nn = t.nbits();
+ if nn < np {
+ u[i].copy(&t);
+ g[i].conj();
+ }
+ u[i].norm();
+ }
+ r.copy(&FP48::pow16(&mut g, &u));
+ } else {
+ r.copy(&d.pow(e));
+ }
+ return r;
+}
diff --git a/src/rand.rs b/src/rand.rs
new file mode 100644
index 0000000..34c264d
--- /dev/null
+++ b/src/rand.rs
@@ -0,0 +1,180 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+//mod hash256;
+
+use crate::hash256::HASH256;
+
+const RAND_NK: usize = 21;
+const RAND_NJ: usize = 6;
+const RAND_NV: usize = 8;
+
+pub struct RAND {
+ ira: [u32; RAND_NK], /* random number... */
+ rndptr: usize,
+ borrow: u32,
+ pool_ptr: usize,
+ pool: [u8; 32],
+}
+
+impl RAND {
+ pub fn new() -> RAND {
+ RAND {
+ ira: [0; RAND_NK],
+ rndptr: 0,
+ borrow: 0,
+ pool_ptr: 0,
+ pool: [0; 32],
+ }
+ }
+
+ pub fn clean(&mut self) {
+ self.pool_ptr = 0;
+ self.rndptr = 0;
+ for i in 0..32 {
+ self.pool[i] = 0
+ }
+ for i in 0..RAND_NK {
+ self.ira[i] = 0
+ }
+ self.borrow = 0;
+ }
+
+ fn sbrand(&mut self) -> u32 {
+ /* Marsaglia & Zaman random number generator */
+ self.rndptr += 1;
+ if self.rndptr < RAND_NK {
+ return self.ira[self.rndptr];
+ }
+ self.rndptr = 0;
+ let mut k = RAND_NK - RAND_NJ;
+ for i in 0..RAND_NK {
+ /* calculate next NK values */
+ if k == RAND_NK {
+ k = 0
+ }
+ let t = self.ira[k];
+ let pdiff = t.wrapping_sub(self.ira[i]).wrapping_sub(self.borrow);
+ if pdiff < t {
+ self.borrow = 0
+ }
+ if pdiff > t {
+ self.borrow = 1
+ }
+ self.ira[i] = pdiff;
+ k += 1;
+ }
+ return self.ira[0];
+ }
+
+ fn sirand(&mut self, seed: u32) {
+ let mut m: u32 = 1;
+ let mut sd = seed;
+ self.borrow = 0;
+ self.rndptr = 0;
+ self.ira[0] ^= sd;
+ for i in 1..RAND_NK {
+ /* fill initialisation vector */
+ let inn = (RAND_NV * i) % RAND_NK;
+ self.ira[inn] ^= m; /* note XOR */
+ let t = m;
+ m = sd.wrapping_sub(m);
+ sd = t;
+ }
+ for _ in 0..10000 {
+ self.sbrand();
+ } /* "warm-up" & stir the generator */
+ }
+
+ fn fill_pool(&mut self) {
+ let mut sh = HASH256::new();
+ for _ in 0..128 {
+ sh.process((self.sbrand() & 0xff) as u8)
+ }
+ let w = sh.hash();
+ for i in 0..32 {
+ self.pool[i] = w[i]
+ }
+ self.pool_ptr = 0;
+ }
+
+ fn pack(b: [u8; 4]) -> u32 {
+ /* pack 4 bytes into a 32-bit Word */
+ return (((b[3] as u32) & 0xff) << 24)
+ | (((b[2] as u32) & 0xff) << 16)
+ | (((b[1] as u32) & 0xff) << 8)
+ | ((b[0] as u32) & 0xff);
+ }
+
+ /* Initialize RNG with some real entropy from some external source */
+ pub fn seed(&mut self, rawlen: usize, raw: &[u8]) {
+ /* initialise from at least 128 byte string of raw random entropy */
+ let mut b: [u8; 4] = [0; 4];
+ let mut sh = HASH256::new();
+ self.pool_ptr = 0;
+
+ for i in 0..RAND_NK {
+ self.ira[i] = 0
+ }
+ if rawlen > 0 {
+ for i in 0..rawlen {
+ sh.process(raw[i]);
+ }
+ let digest = sh.hash();
+
+ /* initialise PRNG from distilled randomness */
+
+ for i in 0..8 {
+ b[0] = digest[4 * i];
+ b[1] = digest[4 * i + 1];
+ b[2] = digest[4 * i + 2];
+ b[3] = digest[4 * i + 3];
+ self.sirand(RAND::pack(b));
+ }
+ }
+ self.fill_pool();
+ }
+
+ /* get random byte */
+ pub fn getbyte(&mut self) -> u8 {
+ let r = self.pool[self.pool_ptr];
+ self.pool_ptr += 1;
+ if self.pool_ptr >= 32 {
+ self.fill_pool()
+ }
+ return (r & 0xff) as u8;
+ }
+}
+
+/* test main program */
+/*
+fn main() {
+ let mut raw : [u8;100]=[0;100];
+ let mut rng=RAND::new();
+
+ rng.clean();
+ for i in 0..100 {raw[i]=i as u8}
+
+ rng.seed(100,&raw);
+
+ for _ in 0..1000 {
+ print!("{:03} ",rng.getbyte());
+ }
+}
+*/
diff --git a/src/roms/rom_anssi_32.rs b/src/roms/rom_anssi_32.rs
new file mode 100644
index 0000000..403fb04
--- /dev/null
+++ b/src/roms/rom_anssi_32.rs
@@ -0,0 +1,73 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use anssi::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// anssi Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x86E9C03, 0xFCF353D, 0x8CA6DE8, 0xADBCABC, 0x35B3961, 0xE8CE424, 0xF10126D, 0xB3AD58,
+ 0x1FD178C, 0xF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x288CC9C, 0x18D2374, 0x646BD2B, 0x4929E67, 0xD6F7F2D, 0x220E6C1, 0xABCE02E, 0x751B1FD,
+ 0x7401B78, 0xE,
+];
+pub const MCONST: Chunk = 0x64E1155;
+
+// anssi Curve
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xB7BB73F, 0x75ED967, 0x1A18030, 0xC9AE4B, 0xFDFEC, 0x754A44C, 0xD4ABA, 0x5428A93, 0xE353FCA,
+ 0xE,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x6D655E1, 0xFDD459C, 0x2BF941F, 0x67E140D, 0x35B53DC, 0xE8CE424, 0xF10126D, 0xB3AD58,
+ 0x1FD178C, 0xF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x98F5CFF, 0xC97A2DD, 0x8B70164, 0xD2DCAF9, 0x3958C27, 0x4749D42, 0xB31183D, 0x56C139E,
+ 0x6B3D4C3, 0xB,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x4062CFB, 0x115A155, 0x4C9E183, 0xC307E8E, 0xF8C2701, 0xF0F3ECE, 0x11F9271, 0xC8B2049,
+ 0x142E0F7, 0x6,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_anssi_64.rs b/src/roms/rom_anssi_64.rs
new file mode 100644
index 0000000..b0add0f
--- /dev/null
+++ b/src/roms/rom_anssi_64.rs
@@ -0,0 +1,91 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use anssi::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// anssi Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFCF353D86E9C03,
+ 0xADBCABC8CA6DE8,
+ 0xE8CE42435B3961,
+ 0xB3AD58F10126D,
+ 0xF1FD178C,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x18D2374288CC9C,
+ 0x4929E67646BD2B,
+ 0x220E6C1D6F7F2D,
+ 0x751B1FDABCE02E,
+ 0xE7401B78,
+];
+pub const MCONST: Chunk = 0x97483A164E1155;
+
+// anssi Curve
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x75ED967B7BB73F,
+ 0xC9AE4B1A18030,
+ 0x754A44C00FDFEC,
+ 0x5428A9300D4ABA,
+ 0xEE353FCA,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xFDD459C6D655E1,
+ 0x67E140D2BF941F,
+ 0xE8CE42435B53DC,
+ 0xB3AD58F10126D,
+ 0xF1FD178C,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xC97A2DD98F5CFF,
+ 0xD2DCAF98B70164,
+ 0x4749D423958C27,
+ 0x56C139EB31183D,
+ 0xB6B3D4C3,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x115A1554062CFB,
+ 0xC307E8E4C9E183,
+ 0xF0F3ECEF8C2701,
+ 0xC8B204911F9271,
+ 0x6142E0F7,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls24_32.rs b/src/roms/rom_bls24_32.rs
new file mode 100644
index 0000000..72afe58
--- /dev/null
+++ b/src/roms/rom_bls24_32.rs
@@ -0,0 +1,240 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls24::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// bls24 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xA06152B, 0x2260B3A, 0xB4C36BE, 0x5FFC5D0, 0xBDB6A64, 0x5B78E2E, 0x1C1A28CA, 0x10E6441B,
+ 0x1F244061, 0xB4704F0, 0x141E5CCD, 0x9837504, 0x3F2E77E, 0xD763740, 0x1316EA0E, 0xF0079,
+ 0x555C,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x8533EA9, 0x6A02789, 0x183B24DE, 0x1E45ECF8, 0xC8F8F37, 0x10CAD209, 0x4C0C4B8, 0x9B1FABD,
+ 0xDEBE4C0, 0xDC353F9, 0x18A18E26, 0x10F489BB, 0x31206A5, 0x19673BBF, 0x6BE69F9, 0xB091169,
+ 0x9CD,
+];
+pub const MCONST: Chunk = 0x95FE7D;
+pub const FRA: [Chunk; NLEN] = [
+ 0x1BF96F1D, 0xAE53A55, 0x31BFEEB, 0x183FF17A, 0x6237469, 0x12A4F4F1, 0x12101FE3, 0x16E79D94,
+ 0xFF59267, 0x5EB4EB4, 0x78CC49F, 0x274BA33, 0x149184F3, 0x16C6DCBA, 0x1C90B694, 0x10F729CE,
+ 0x4BBC,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xE0CA60E, 0x1740D0E4, 0x83037D2, 0xDBFD456, 0x5B7F5FA, 0x1312993D, 0xA0A08E6, 0x19FEA687,
+ 0xF2EADF9, 0x55BB63C, 0xC91982E, 0x70EBAD1, 0xF61628B, 0x16AF5A85, 0x16863379, 0xF17D6AA,
+ 0x99F,
+];
+
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 19;
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x10000001, 0xD047FF, 0x1FD54464, 0x1E3CE067, 0xE322DDA, 0x1D356F3F, 0x7433B44, 0x49091F9,
+ 0x1729CC2, 0x250286C, 0x16E62ED, 0xB403E1E, 0x1001000, 0x80, 0x0, 0x0, 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xBE3CCD4, 0x33B07AF, 0x1B67D159, 0x3DFC5B5, 0xEBA1FCC, 0x1A3C1F84, 0x56BE204, 0xEF8DF1B,
+ 0x11AE2D84, 0x5FEE546, 0x161B3BF9, 0x183B20EE, 0x1EA5D99B, 0x14F0C5BF, 0xBE521B7, 0x17C682F9,
+ 0x1AB2,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x121E5245, 0x65D2E56, 0x11577DB1, 0x16DACC11, 0x14F39746, 0x459F694, 0x12483FCF, 0xC828B04,
+ 0xFD63E5A, 0x7B1D52, 0xAFDE738, 0xF349254, 0x1A4529FF, 0x10E53353, 0xF91DEE1, 0x16E18D8A,
+ 0x47FC,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0x11FF80, 0x80010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x19F415AB, 0x1E0FFDFF, 0x15AAADFF, 0xAA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xDD794A9, 0x1DE138A3, 0x2BCCE90, 0xC746127, 0x15223DDC, 0x1DD8890B, 0xED08DB7, 0xE24B9F,
+ 0xE379CE6, 0x37011AC, 0x11BAC820, 0x1EEFAD01, 0x200860F, 0x147218A6, 0xF16A209, 0xF0079,
+ 0x555C,
+];
+pub const CURVE_PXAA: [Chunk; NLEN] = [
+ 0x14E24678, 0x1F149A9B, 0x9609022, 0x1C186868, 0xCDEFC69, 0x1C87BB2E, 0x14A2235F, 0x7586755,
+ 0x5896747, 0x159BFE92, 0x3B5572E, 0x1710A521, 0x71EB14A, 0xC643C33, 0x12581DE5, 0x1BCA747D,
+ 0x959,
+];
+pub const CURVE_PXAB: [Chunk; NLEN] = [
+ 0x1FB099B8, 0x3FCF5D7, 0x4A91C0E, 0xC6EEB40, 0x11FC2385, 0x11B5AE8D, 0x1A9CC3E7, 0x194FE144,
+ 0x185DB2A5, 0x930E1C7, 0x14F85F9A, 0x1F2ED4E, 0x1D1BE5AD, 0xF26169C, 0xCF7F194, 0x1DA1062E,
+ 0x3B0D,
+];
+pub const CURVE_PXBA: [Chunk; NLEN] = [
+ 0x11AD15D3, 0xD0E6F38, 0x17DB85BB, 0x30A62F1, 0x1EA3E09A, 0x17B25FA1, 0x1B7959AC, 0x1165B19A,
+ 0x6C74FDB, 0x18F790E1, 0x12278FDA, 0x1E008F79, 0x103F329, 0x14619FF1, 0x1EBCAA8, 0xFF5A9CA,
+ 0x3EC2,
+];
+pub const CURVE_PXBB: [Chunk; NLEN] = [
+ 0x1EE0F480, 0x3D5943A, 0xF5B12E3, 0x128AADC8, 0x180E1CB9, 0x1EFD916F, 0x48BC7F, 0x1D5EE1FA,
+ 0x5698EF5, 0x11D6AED9, 0x1386BC6E, 0x196E900B, 0x1CE2E465, 0xC2A8ED3, 0x1E67DF99, 0x71B7940,
+ 0xA5B,
+];
+pub const CURVE_PYAA: [Chunk; NLEN] = [
+ 0x14781AA0, 0xC324C98, 0xEDC2AC, 0x16C13B46, 0x145FC44B, 0x12529530, 0x1310A8C4, 0x1768C5C0,
+ 0xE19AE68, 0x56E1C1D, 0x13DAF93F, 0x17E94366, 0xF901AD0, 0x76800CC, 0x10250D8B, 0x1E6BAE6D,
+ 0x5057,
+];
+pub const CURVE_PYAB: [Chunk; NLEN] = [
+ 0xEAE08FA, 0xDDF62BF, 0xA97E5AB, 0xF0EE97, 0x99A42CA, 0x1C326578, 0xF33DC11, 0x8B913F7,
+ 0xFEF8552, 0x19F35B90, 0x58DDBDE, 0xFC32FF2, 0x1587B5DF, 0xB5EB07A, 0x1A258DE0, 0x1692CC3D,
+ 0x2CE2,
+];
+pub const CURVE_PYBA: [Chunk; NLEN] = [
+ 0x5F0CC41, 0xB9813B5, 0x14C2A87D, 0xFF1264A, 0x19AF8A14, 0x6CE6C3, 0x2A7F8A2, 0x121DCA7D,
+ 0x7D37153, 0x19D21078, 0x15466DC7, 0x1362982B, 0x1DD3CB5B, 0x1CFC0D1C, 0x18C69AF8, 0x8CC7DC,
+ 0x1807,
+];
+pub const CURVE_PYBB: [Chunk; NLEN] = [
+ 0x115C1CAE, 0x78D9732, 0x16C26237, 0x5A81A6A, 0x1C38A777, 0x56121FE, 0x4DAD9D7, 0x1BEBA670,
+ 0xA1D72FC, 0xD60B274, 0x19734258, 0x1D621775, 0x4691771, 0x14206B68, 0x17B22DE4, 0x29D5B37,
+ 0x499D,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 60;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 479;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 49;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
diff --git a/src/roms/rom_bls24_64.rs b/src/roms/rom_bls24_64.rs
new file mode 100644
index 0000000..0c500da
--- /dev/null
+++ b/src/roms/rom_bls24_64.rs
@@ -0,0 +1,288 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls24::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// bls24 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x44C1674A06152B,
+ 0xFFE2E82D30DAF8,
+ 0x6F1C5CBDB6A642,
+ 0x3220DF068A328B,
+ 0xE09E1F24406187,
+ 0xBA825079733568,
+ 0x6E803F2E77E4C1,
+ 0x3CCC5BA839AEC,
+ 0x555C0078,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x6A4A1FE013DF5B,
+ 0xE8E46D4D1BDE65,
+ 0x1F841391F45C67,
+ 0x9148A4516FB28,
+ 0x4398524EDF4C88,
+ 0x41C0E241B6DCE8,
+ 0xE42C208C19411,
+ 0xA7FE6FD73A7B1C,
+ 0xFCCCA76,
+];
+pub const MCONST: Chunk = 0xBD5D7D8095FE7D;
+pub const FRA: [Chunk; NLEN] = [
+ 0x5CA74ABBF96F1D,
+ 0x1FF8BD0C6FFBAD,
+ 0x49E9E26237469C,
+ 0x3CECA48407F8E5,
+ 0x69D68FF59267B7,
+ 0x5D199E33127CBD,
+ 0xB97549184F313A,
+ 0x4E77242DA52D8D,
+ 0x4BBC87B9,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xE81A1C8E0CA60E,
+ 0xDFEA2B20C0DF4A,
+ 0x25327A5B7F5FA6,
+ 0xF5343A828239A6,
+ 0x76C78F2EADF9CF,
+ 0x5D68B24660B8AB,
+ 0xB50AF61628B387,
+ 0xB555A18CDE6D5E,
+ 0x99F78BE,
+];
+
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 19;
+pub const CURVE_B: [Chunk; NLEN] = [0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1A08FFF0000001,
+ 0x1E7033FF551190,
+ 0x6ADE7EE322DDAF,
+ 0x848FC9D0CED13A,
+ 0x50D81729CC224,
+ 0x1F0F05B98BB44A,
+ 0x10010010005A0,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x6760F5EBE3CCD4,
+ 0xEFE2DAED9F4564,
+ 0x783F08EBA1FCC1,
+ 0xC6F8D95AF88134,
+ 0xDCA8D1AE2D8477,
+ 0x9077586CEFE4BF,
+ 0x8B7FEA5D99BC1D,
+ 0x17CAF9486DE9E1,
+ 0x1AB2BE34,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xCBA5CAD21E5245,
+ 0x6D6608C55DF6C4,
+ 0xB3ED294F39746B,
+ 0x145824920FF3C8,
+ 0x63AA4FD63E5A64,
+ 0x492A2BF79CE00F,
+ 0x66A7A4529FF79A,
+ 0x6C53E477B861CA,
+ 0x47FCB70C,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [0x100020011FF80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0xC1FFBFF9F415AB,
+ 0x5556AAB7FF,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xBC27146DD794A9,
+ 0x3A30938AF33A43,
+ 0xB112175223DDC6,
+ 0x125CFBB4236DFB,
+ 0x2358E379CE607,
+ 0xD680C6EB20806E,
+ 0x314C200860FF77,
+ 0x3CBC5A88268E4,
+ 0x555C0078,
+];
+pub const CURVE_PXAA: [Chunk; NLEN] = [
+ 0xE2935374E24678,
+ 0xC34342582408B,
+ 0xF765CCDEFC69E,
+ 0xC33AAD2888D7F9,
+ 0x7FD2458967473A,
+ 0x52908ED55CBAB3,
+ 0x786671EB14AB88,
+ 0xA3EC96077958C8,
+ 0x959DE53,
+];
+pub const CURVE_PXAB: [Chunk; NLEN] = [
+ 0x7F9EBAFFB099B8,
+ 0x3775A012A47038,
+ 0x6B5D1B1FC23856,
+ 0x7F0A26A730F9E3,
+ 0x1C38F85DB2A5CA,
+ 0x76A753E17E6926,
+ 0x2D39D1BE5AD0F9,
+ 0x31733DFC651E4C,
+ 0x3B0DED08,
+];
+pub const CURVE_PXBA: [Chunk; NLEN] = [
+ 0xA1CDE711AD15D3,
+ 0x853178DF6E16ED,
+ 0x64BF43EA3E09A1,
+ 0x2D8CD6DE566B2F,
+ 0xF21C26C74FDB8B,
+ 0x47BCC89E3F6B1E,
+ 0x3FE2103F329F00,
+ 0x4E507AF2AA28C3,
+ 0x3EC27FAD,
+];
+pub const CURVE_PXBB: [Chunk; NLEN] = [
+ 0x7AB2875EE0F480,
+ 0x4556E43D6C4B8C,
+ 0xFB22DF80E1CB99,
+ 0xF70FD0122F1FFD,
+ 0xD5DB25698EF5EA,
+ 0x4805CE1AF1BA3A,
+ 0x1DA7CE2E465CB7,
+ 0xCA0799F7E65855,
+ 0xA5B38DB,
+];
+pub const CURVE_PYAA: [Chunk; NLEN] = [
+ 0x86499314781AA0,
+ 0x609DA303B70AB1,
+ 0xA52A6145FC44BB,
+ 0x462E04C42A3124,
+ 0xC383AE19AE68BB,
+ 0xA1B34F6BE4FCAD,
+ 0x198F901AD0BF4,
+ 0x736C094362CED0,
+ 0x5057F35D,
+];
+pub const CURVE_PYAB: [Chunk; NLEN] = [
+ 0xBBEC57EEAE08FA,
+ 0x78774BAA5F96AD,
+ 0x64CAF099A42CA0,
+ 0xC89FBBCCF70478,
+ 0x6B720FEF855245,
+ 0x97F916376F7B3E,
+ 0x60F5587B5DF7E1,
+ 0x61EE89637816BD,
+ 0x2CE2B496,
+];
+pub const CURVE_PYBA: [Chunk; NLEN] = [
+ 0x730276A5F0CC41,
+ 0xF89325530AA1F5,
+ 0xD9CD879AF8A147,
+ 0xEE53E8A9FE2880,
+ 0x420F07D3715390,
+ 0x4C15D519B71F3A,
+ 0x1A39DD3CB5B9B1,
+ 0x3EE631A6BE39F8,
+ 0x18070466,
+];
+pub const CURVE_PYBB: [Chunk; NLEN] = [
+ 0xF1B2E6515C1CAE,
+ 0xD40D355B0988DC,
+ 0xC243FDC38A7772,
+ 0x5D338136B675CA,
+ 0x164E8A1D72FCDF,
+ 0xBBAE5CD0961AC,
+ 0xD6D04691771EB1,
+ 0xD9BDEC8B792840,
+ 0x499D14EA,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 60;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 479;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 25;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 49;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
diff --git a/src/roms/rom_bls381_32.rs b/src/roms/rom_bls381_32.rs
new file mode 100644
index 0000000..1ba0fe5
--- /dev/null
+++ b/src/roms/rom_bls381_32.rs
@@ -0,0 +1,209 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls381::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// bls381 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFAAAB, 0xFF7FFFF, 0x14FFFFEE, 0x17FFFD62, 0xF6241EA, 0x9507B58, 0xAFD9CC3, 0x109E70A2,
+ 0x1764774B, 0x121A5D66, 0x12C6E9ED, 0x12FFCD34, 0x111EA3, 0xD,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x15BEF7AE, 0x1031CD0E, 0x2DD93E8, 0x9226323, 0xE6E2CD2, 0x11684DAA, 0x1170E5DB, 0x88E25B1,
+ 0x1B366399, 0x1C536F47, 0xD1F9CBC, 0x278B67F, 0x1EA66A2B, 0xC,
+];
+pub const MCONST: Chunk = 0x1FFCFFFD;
+pub const FRA: [Chunk; NLEN] = [
+ 0x12235FB8, 0x83BAF6C, 0x19E04F63, 0x1D4A7AC7, 0xB9C4F67, 0x1EBC25D, 0x1D3DEC91, 0x1FA797AB,
+ 0x1F0FD603, 0x1016068, 0x108C6FAD, 0x5760CCF, 0x104D3BF0, 0xC,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xDDC4AF3, 0x7BC5093, 0x1B1FB08B, 0x1AB5829A, 0x3C5F282, 0x764B8FB, 0xDBFB032, 0x10F6D8F6,
+ 0x1854A147, 0x1118FCFD, 0x23A7A40, 0xD89C065, 0xFC3E2B3, 0x0,
+];
+
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 4;
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1, 0x1FFFFFF8, 0x1F96FFBF, 0x1B4805FF, 0x1D80553B, 0xC0404D0, 0x1520CCE7, 0xA6533AF,
+ 0x73EDA7, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x1B22C6BB, 0x19D78056, 0x1E86BBFE, 0xBD07FF2, 0x1AC586C5, 0x1D1F8B8D, 0x4168538, 0x9F2EE97,
+ 0xFC3688C, 0x27D4D60, 0x9A558E3, 0x32FAF28, 0x1F1D3A73, 0xB,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x6C5E7E1, 0x551194A, 0x222B903, 0x198E8945, 0xB3EDD03, 0xC659602, 0xBD8036C, 0x12BABA01,
+ 0x4FCF5E0, 0xBA0EC57, 0x8278C3B, 0x75541E3, 0xB3F481E, 0x4,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0x10000, 0x10080000, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0xAAAB, 0x55558, 0x157855A3, 0x191800AA, 0x396, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x1FFEFFFE, 0x100FFFFF, 0x280008B, 0xFB026C4, 0x9688DE1, 0x149DF37C, 0x1FAB76CE, 0xED41EE,
+ 0x11BA69C6, 0x1EFBB672, 0x17C659CB, 0x0, 0x0, 0x0,
+];
+
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x121BDB8, 0x402B646, 0x16EFBF5, 0x18064D50, 0x1D1770BA, 0x5B23D71, 0xC0AD144, 0x1A9F4807,
+ 0x11C6E47A, 0x196E2882, 0x9820149, 0x11E1522, 0x4AA2B2F, 0x1,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x1D042B7E, 0xD63E82A, 0x51755F9, 0x19E22427, 0x15049334, 0x10DDEE3F, 0x186AD769, 0x1A132416,
+ 0x5596BD0, 0x4413A7B, 0x1F6B34E8, 0x4E33EC0, 0x1E02B605, 0x9,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x8B82801, 0xC9AA430, 0xB28A278, 0x15939877, 0xD12C923, 0xD34A8B0, 0xE9DB50A, 0x155197BA,
+ 0x1AADFD9B, 0x16D171A8, 0x3327371, 0x4FADC23, 0xE5D5277, 0x6,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x105F79BE, 0x15483AFF, 0x1B07686A, 0xE1A4EB9, 0x99AB3F3, 0x955AB97, 0xEBC99D2, 0xFD0B4EC,
+ 0x19CB3E28, 0x15E145C, 0xCAB34AC, 0x1D4E6998, 0x6C4A02, 0x3,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 381;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 65;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls381_64.rs b/src/roms/rom_bls381_64.rs
new file mode 100644
index 0000000..08df12c
--- /dev/null
+++ b/src/roms/rom_bls381_64.rs
@@ -0,0 +1,211 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls381::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 58
+// bls381 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FEFFFFFFFFAAAB,
+ 0x2FFFFAC54FFFFEE,
+ 0x12A0F6B0F6241EA,
+ 0x213CE144AFD9CC3,
+ 0x2434BACD764774B,
+ 0x25FF9A692C6E9ED,
+ 0x1A0111EA3,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x20639A1D5BEF7AE,
+ 0x1244C6462DD93E8,
+ 0x22D09B54E6E2CD2,
+ 0x111C4B63170E5DB,
+ 0x38A6DE8FB366399,
+ 0x4F16CFED1F9CBC,
+ 0x19EA66A2B,
+];
+pub const MCONST: Chunk = 0x1F3FFFCFFFCFFFD;
+pub const FRA: [Chunk; NLEN] = [
+ 0x10775ED92235FB8,
+ 0x3A94F58F9E04F63,
+ 0x3D784BAB9C4F67,
+ 0x3F4F2F57D3DEC91,
+ 0x202C0D1F0FD603,
+ 0xAEC199F08C6FAD,
+ 0x1904D3BF0,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xF78A126DDC4AF3,
+ 0x356B0535B1FB08B,
+ 0xEC971F63C5F282,
+ 0x21EDB1ECDBFB032,
+ 0x2231F9FB854A147,
+ 0x1B1380CA23A7A40,
+ 0xFC3E2B3,
+];
+
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 4;
+pub const CURVE_B: [Chunk; NLEN] = [0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x3FFFFFF00000001,
+ 0x36900BFFF96FFBF,
+ 0x180809A1D80553B,
+ 0x14CA675F520CCE7,
+ 0x73EDA7,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x33AF00ADB22C6BB,
+ 0x17A0FFE5E86BBFE,
+ 0x3A3F171BAC586C5,
+ 0x13E5DD2E4168538,
+ 0x4FA9AC0FC3688C,
+ 0x65F5E509A558E3,
+ 0x17F1D3A73,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xAA232946C5E7E1,
+ 0x331D128A222B903,
+ 0x18CB2C04B3EDD03,
+ 0x25757402BD8036C,
+ 0x1741D8AE4FCF5E0,
+ 0xEAA83C68278C3B,
+ 0x8B3F481E,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [0x201000000010000, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0xAAAB0000AAAB, 0x3230015557855A3, 0x396, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x201FFFFFFFEFFFE,
+ 0x1F604D88280008B,
+ 0x293BE6F89688DE1,
+ 0x1DA83DDFAB76CE,
+ 0x3DF76CE51BA69C6,
+ 0x17C659CB,
+ 0x0,
+];
+
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x8056C8C121BDB8,
+ 0x300C9AA016EFBF5,
+ 0xB647AE3D1770BA,
+ 0x353E900EC0AD144,
+ 0x32DC51051C6E47A,
+ 0x23C2A449820149,
+ 0x24AA2B2F,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x1AC7D055D042B7E,
+ 0x33C4484E51755F9,
+ 0x21BBDC7F5049334,
+ 0x3426482D86AD769,
+ 0x88274F65596BD0,
+ 0x9C67D81F6B34E8,
+ 0x13E02B605,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x193548608B82801,
+ 0x2B2730EEB28A278,
+ 0x1A695160D12C923,
+ 0x2AA32F74E9DB50A,
+ 0x2DA2E351AADFD9B,
+ 0x9F5B8463327371,
+ 0xCE5D5277,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x2A9075FF05F79BE,
+ 0x1C349D73B07686A,
+ 0x12AB572E99AB3F3,
+ 0x1FA169D8EBC99D2,
+ 0x2BC28B99CB3E28,
+ 0x3A9CD330CAB34AC,
+ 0x606C4A02,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 58;
+
+pub const MODBITS: usize = 381;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 25;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 65;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls383_32.rs b/src/roms/rom_bls383_32.rs
new file mode 100644
index 0000000..0ccb42d
--- /dev/null
+++ b/src/roms/rom_bls383_32.rs
@@ -0,0 +1,207 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls383::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x5AAB0AB, 0x11B8EB24, 0x19214AF6, 0x187E5314, 0x124F47A8, 0x1C00B4B0, 0x1446B0C6, 0x59E6CB4,
+ 0x4A0AD46, 0xFF5494, 0x81B6B71, 0x956DD6B, 0x16556956, 0x2A,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x116907F4, 0x405B700, 0x1752AC11, 0x67A9E7C, 0x1941C581, 0x1AEA38C4, 0xB1E4D22, 0xCE841AE,
+ 0xA0FC49B, 0xB4B1F48, 0x13852312, 0x1B3FDCED, 0x1FECE397, 0x26,
+];
+pub const MCONST: Chunk = 0x73435FD;
+pub const FRA: [Chunk; NLEN] = [
+ 0x1311DAC1, 0x296B969, 0x19DCF806, 0x126901FC, 0xD8C8A36, 0x1A2572A8, 0xA1A0959, 0x1A47F743,
+ 0x110E4C6C, 0x1608DA97, 0xCE2E7F0, 0x4FED178, 0xACD5BF0, 0x11,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x1298D5EA, 0xF2231BA, 0x1F4452F0, 0x6155117, 0x4C2BD72, 0x1DB4208, 0xA2CA76D, 0xB567571,
+ 0x139260D9, 0xAF679FC, 0x1B388380, 0x4580BF2, 0xB880D66, 0x19,
+];
+
+pub const CURVE_A: isize = 0;
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x15169EAB, 0xA82AB0A, 0xAAEFFED, 0x15558001, 0x555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0,
+];
+pub const CURVE_B_I: isize = 15;
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1EBC0001, 0x1904CF5F, 0x834E5CE, 0xBE12B42, 0xB381DE0, 0xE40B4C, 0x270110, 0x10018017,
+ 0x1002001, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x8734573, 0x623B9C8, 0x1D1DC11E, 0xBB7E107, 0x1E3445C5, 0x1D6C2578, 0x10B0BE1E, 0xED6103E,
+ 0x10F31D9F, 0x296ED82, 0x18E0D7D0, 0x12F3D9C9, 0x1FCBA55B, 0x20,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x3F224, 0x968B2F4, 0x1FE63F48, 0xFA93D90, 0x14D2DDE5, 0x54A56F5, 0x12441D4C, 0x18CD76C8,
+ 0x199D0DAD, 0xE18E236, 0x92BA73, 0x99F6600, 0x8F16727, 0x3,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0x1001200, 0x400000, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xEAAC2A9, 0x61B3A81, 0x17D974B7, 0xBED0345, 0xA341BC2, 0x17A51A6F, 0x5738948, 0x69B7BAE,
+ 0x14605445, 0x374A43, 0x8116AD1, 0x956DD69, 0x16556956, 0x2A,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0xD7F2D86, 0x1E59DB1, 0x17474F85, 0x1FB56CF2, 0x572EE81, 0xE487AB1, 0x96F51FC, 0x190A5AAE,
+ 0x6432501, 0x13E58F3A, 0x101E6425, 0xFD807D1, 0x34D2240, 0x3,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x452DE15, 0x1ECF20F6, 0x1FF9837B, 0x95651AA, 0xD5D75B5, 0x5D44749, 0x12277F66, 0x1DB3A0B9,
+ 0x1D24F498, 0x19441B0E, 0x1CDE9DC5, 0x2C975, 0xD78006, 0x18,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x1408CB41, 0x34785DC, 0x3586597, 0x13DBC9E4, 0x1A2E75B4, 0x1D65489, 0xCF9A25E, 0x1ACE7933,
+ 0x1B6E990E, 0x19FF31A3, 0x12527615, 0x1A44A68F, 0x1792CF93, 0x19,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x1F479093, 0x16C2321B, 0x1889218E, 0x87961BC, 0x1BC98B01, 0x197A24FB, 0xA3DEBC2, 0x88D67DF,
+ 0x1CE0D, 0x1E8AD3D7, 0x93B9EE9, 0x59B18D6, 0xE5247DD, 0x10,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 383;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 65;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls383_64.rs b/src/roms/rom_bls383_64.rs
new file mode 100644
index 0000000..71bef66
--- /dev/null
+++ b/src/roms/rom_bls383_64.rs
@@ -0,0 +1,218 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls383::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 58
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x2371D6485AAB0AB,
+ 0x30FCA6299214AF6,
+ 0x3801696124F47A8,
+ 0xB3CD969446B0C6,
+ 0x1FEA9284A0AD46,
+ 0x12ADBAD681B6B71,
+ 0x556556956,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x80B6E0116907F4,
+ 0xCF53CF9752AC11,
+ 0x35D47189941C581,
+ 0x19D0835CB1E4D22,
+ 0x16963E90A0FC49B,
+ 0x367FB9DB3852312,
+ 0x4DFECE397,
+];
+pub const MCONST: Chunk = 0x1BC0571073435FD;
+pub const FRA: [Chunk; NLEN] = [
+ 0x52D72D3311DAC1,
+ 0x24D203F99DCF806,
+ 0x344AE550D8C8A36,
+ 0x348FEE86A1A0959,
+ 0x2C11B52F10E4C6C,
+ 0x9FDA2F0CE2E7F0,
+ 0x22ACD5BF0,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x1E446375298D5EA,
+ 0xC2AA22FF4452F0,
+ 0x3B684104C2BD72,
+ 0x16ACEAE2A2CA76D,
+ 0x15ECF3F939260D9,
+ 0x8B017E5B388380,
+ 0x32B880D66,
+];
+
+// Base Bits= 58
+
+pub const CURVE_A: isize = 0;
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x150556155169EAB,
+ 0x2AAB0002AAEFFED,
+ 0x555,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_B_I: isize = 15;
+pub const CURVE_B: [Chunk; NLEN] = [0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x32099EBFEBC0001,
+ 0x17C25684834E5CE,
+ 0x1C81698B381DE0,
+ 0x2003002E0270110,
+ 0x1002001,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xC4773908734573,
+ 0x176FC20FD1DC11E,
+ 0x3AD84AF1E3445C5,
+ 0x1DAC207D0B0BE1E,
+ 0x52DDB050F31D9F,
+ 0x25E7B3938E0D7D0,
+ 0x41FCBA55B,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x12D165E8003F224,
+ 0x1F527B21FE63F48,
+ 0xA94ADEB4D2DDE5,
+ 0x319AED912441D4C,
+ 0x1C31C46D99D0DAD,
+ 0x133ECC00092BA73,
+ 0x68F16727,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [0x8000001001200, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xC367502EAAC2A9,
+ 0x17DA068B7D974B7,
+ 0x2F4A34DEA341BC2,
+ 0xD36F75C5738948,
+ 0x6E94874605445,
+ 0x12ADBAD28116AD1,
+ 0x556556956,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x3CB3B62D7F2D86,
+ 0x3F6AD9E57474F85,
+ 0x1C90F562572EE81,
+ 0x3214B55C96F51FC,
+ 0x27CB1E746432501,
+ 0x1FB00FA301E6425,
+ 0x634D2240,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x3D9E41EC452DE15,
+ 0x12ACA355FF9837B,
+ 0xBA88E92D5D75B5,
+ 0x3B6741732277F66,
+ 0x3288361DD24F498,
+ 0x592EBCDE9DC5,
+ 0x300D78006,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x68F0BB9408CB41,
+ 0x27B793C83586597,
+ 0x3ACA913A2E75B4,
+ 0x359CF266CF9A25E,
+ 0x33FE6347B6E990E,
+ 0x34894D1F2527615,
+ 0x33792CF93,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x2D846437F479093,
+ 0x10F2C379889218E,
+ 0x32F449F7BC98B01,
+ 0x111ACFBEA3DEBC2,
+ 0x3D15A7AE001CE0D,
+ 0xB3631AC93B9EE9,
+ 0x20E5247DD,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 58;
+
+pub const MODBITS: usize = 383;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 23;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 65;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls461_32.rs b/src/roms/rom_bls461_32.rs
new file mode 100644
index 0000000..c452a9f
--- /dev/null
+++ b/src/roms/rom_bls461_32.rs
@@ -0,0 +1,209 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls461::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// bls461 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xAAAAAAB, 0xAC0000A, 0x54AAAAA, 0x5555, 0x400020, 0x91557F0, 0xF26AA, 0xFA5C1CC, 0xB42A8DF,
+ 0x7B14848, 0x8BACCA4, 0x6F1E32D, 0x4935FBD, 0x55D6941, 0xD5A555A, 0x5545554, 0x1555,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xC9B6A33, 0x2ECD087, 0x3CCB2B1, 0xCD461FE, 0x8CB5AB2, 0xC5B9635, 0x5312E92, 0xB659F64,
+ 0x3B596FA, 0x8679006, 0xA92E2B3, 0x3CE05E3, 0x363550F, 0x7C07A8E, 0x382C083, 0x6347FEA, 0xBD,
+];
+pub const MCONST: Chunk = 0xFFFFFFD;
+pub const FRA: [Chunk; NLEN] = [
+ 0xB812A3A, 0x7117BF9, 0x99C400F, 0xC6308A5, 0x5BF8A1, 0x510E075, 0x45FA5A6, 0xCE4858D,
+ 0x770B31A, 0xBC2CB04, 0xE2FC61E, 0xD073588, 0x4366190, 0x4DFEFA8, 0x69E55E2, 0x504B7F, 0x12E4,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xF298071, 0x3AE8410, 0xBAE6A9B, 0x39D4CAF, 0xFE4077E, 0x404777A, 0xBAF8104, 0x2C13C3E,
+ 0x3D1F5C5, 0xBEE7D44, 0xA8B0685, 0x9EAADA4, 0x5CFE2C, 0x7D7999, 0x6BBFF78, 0x50409D5, 0x271,
+];
+
+// bls461 Curve
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 9;
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1, 0x0, 0xFFFFC00, 0x7FEFFFE, 0x110000, 0x7FFC800, 0x801FC01, 0x5FD000E, 0x17FE0, 0xFFFC018,
+ 0xFFFFFF7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xADEE93D, 0x4D026A8, 0x74B7411, 0xD9C00EE, 0x31AC7F2, 0xC3981B5, 0x9218229, 0xD3564DC,
+ 0xA096650, 0x6F7C292, 0x9743616, 0xBE922B1, 0x12CF668, 0xC81327, 0x463B73A, 0xE74E99B, 0xAD0,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xAD1D465, 0xF763157, 0xC4FF470, 0x17884C8, 0xB8D215D, 0xA819E66, 0xF4959D0, 0xE5C3245,
+ 0xB84910A, 0xB8BFA40, 0xBE96EEC, 0x8BF9F8C, 0xF277ACC, 0x5F1C3F2, 0x5F68C9, 0xCDB14B3, 0x77B,
+];
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0x0, 0xFBFFFE0, 0x1FFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0xAAAAAAB, 0xA7FFFEA, 0x1556AA, 0xD55AAAB, 0x554FFFF, 0x1555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xFFFFFFE, 0x40001F, 0xFE00000, 0xFFE7FFF, 0xF0FFF6F, 0x7200C47, 0x7BCC604, 0x15796DB,
+ 0xCF47771, 0x9875433, 0x613F0E8, 0x5000502, 0xEBFFF60, 0x1FFFFF, 0x0, 0x0, 0x0,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x6D0A37C, 0x5B50318, 0x75DCC46, 0xC2E492E, 0xD6878A9, 0xE01F919, 0xF92F564, 0x86DB74F,
+ 0x66803F0, 0x46D581A, 0x7ED78D, 0x2F97C29, 0xC270C89, 0xF679453, 0x6A50A9A, 0x54138A0, 0x10CC,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x2C1C0AD, 0xF85CA8C, 0x25CADE9, 0x6CD66C4, 0xA289609, 0xC612951, 0xEE2401A, 0x529ABEB,
+ 0xF65B17D, 0xBA09D33, 0xD4C5AF5, 0x4D4371E, 0x46A672E, 0xA279D22, 0xACEA37C, 0x1FB4FE5, 0x95C,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x2FB006, 0xCCD0C1B, 0xA12A337, 0x3D194A4, 0xC92C895, 0x4960CFC, 0x39FC68B, 0x3A9B00F,
+ 0xED1BA0F, 0xA7DBBC5, 0xA9CDFD8, 0x27CC2F7, 0x4E73ED2, 0x6070F4F, 0xEBA7E67, 0xAC848E7, 0x226,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0xDF1457C, 0xA506ADF, 0x4C20A8, 0xD6A31DC, 0x36E3FB4, 0xEA9A8F1, 0x92F5668, 0x3C3BE44,
+ 0x67A1297, 0x74BEABA, 0x56A20BE, 0x4C42E38, 0x45157F0, 0x2AB1D00, 0xBB402EA, 0x101B4FA, 0xE38,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 58;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 461;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 78;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls461_64.rs b/src/roms/rom_bls461_64.rs
new file mode 100644
index 0000000..500ef04
--- /dev/null
+++ b/src/roms/rom_bls461_64.rs
@@ -0,0 +1,232 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls461::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+// bls461 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xAAC0000AAAAAAAB,
+ 0x20000555554AAAA,
+ 0x6AA91557F004000,
+ 0xA8DFFA5C1CC00F2,
+ 0xACCA47B14848B42,
+ 0x935FBD6F1E32D8B,
+ 0xD5A555A55D69414,
+ 0x15555545554,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x96D08774614DDA8,
+ 0xCD45F539225D5BD,
+ 0xD712EB760C95AB1,
+ 0xB3B687155F30B55,
+ 0xC4E62A05C3F5B81,
+ 0xBA1151676CA3CD0,
+ 0x7EDD8A958F442BE,
+ 0x12B89DD3F91,
+];
+pub const MCONST: Chunk = 0xC0005FFFFFFFD;
+pub const FRA: [Chunk; NLEN] = [
+ 0xF7117BF9B812A3A,
+ 0xA1C6308A599C400,
+ 0x5A6510E07505BF8,
+ 0xB31ACE4858D45FA,
+ 0xFC61EBC2CB04770,
+ 0x366190D073588E2,
+ 0x69E55E24DFEFA84,
+ 0x12E40504B7F,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xB3AE8410F298071,
+ 0x7E39D4CAFBAE6A9,
+ 0x104404777AFE407,
+ 0xF5C52C13C3EBAF8,
+ 0xB0685BEE7D443D1,
+ 0x5CFE2C9EAADA4A8,
+ 0x6BBFF7807D79990,
+ 0x27150409D5,
+];
+
+// bls461 Curve
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 9;
+pub const CURVE_B: [Chunk; NLEN] = [0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1,
+ 0x7FEFFFEFFFFC0,
+ 0xC017FFC80001100,
+ 0x7FE05FD000E801F,
+ 0xFFFF7FFFC018001,
+ 0xFF,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x14D026A8ADEE93D,
+ 0xF2D9C00EE74B741,
+ 0x229C3981B531AC7,
+ 0x6650D3564DC9218,
+ 0x436166F7C292A09,
+ 0x2CF668BE922B197,
+ 0x463B73A0C813271,
+ 0xAD0E74E99B,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xF763157AD1D465,
+ 0x5D17884C8C4FF47,
+ 0x9D0A819E66B8D21,
+ 0x910AE5C3245F495,
+ 0x96EECB8BFA40B84,
+ 0x277ACC8BF9F8CBE,
+ 0x5F68C95F1C3F2F,
+ 0x77BCDB14B3,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [0xFFBFFFE00000000, 0x1FFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0xAA7FFFEAAAAAAAB,
+ 0xFFD55AAAB01556A,
+ 0x1555554FF,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x40001FFFFFFFE,
+ 0x6FFFE7FFFFE0000,
+ 0x6047200C47F0FFF,
+ 0x777115796DB7BCC,
+ 0x3F0E89875433CF4,
+ 0xBFFF60500050261,
+ 0x1FFFFFE,
+ 0x0,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x65B503186D0A37C,
+ 0xA9C2E492E75DCC4,
+ 0x564E01F919D6878,
+ 0x3F086DB74FF92F,
+ 0xED78D46D581A668,
+ 0x270C892F97C2907,
+ 0x6A50A9AF679453C,
+ 0x10CC54138A0,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x9F85CA8C2C1C0AD,
+ 0x96CD66C425CADE,
+ 0x1AC612951A2896,
+ 0xB17D529ABEBEE24,
+ 0xC5AF5BA09D33F65,
+ 0x6A672E4D4371ED4,
+ 0xACEA37CA279D224,
+ 0x95C1FB4FE5,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x7CCD0C1B02FB006,
+ 0x953D194A4A12A33,
+ 0x68B4960CFCC92C8,
+ 0xBA0F3A9B00F39FC,
+ 0xCDFD8A7DBBC5ED1,
+ 0xE73ED227CC2F7A9,
+ 0xEBA7E676070F4F4,
+ 0x226AC848E7,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x8A506ADFDF1457C,
+ 0xB4D6A31DC04C20A,
+ 0x668EA9A8F136E3F,
+ 0x12973C3BE4492F5,
+ 0xA20BE74BEABA67A,
+ 0x5157F04C42E3856,
+ 0xBB402EA2AB1D004,
+ 0xE38101B4FA,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 58;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 461;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 19;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 78;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bls48_32.rs b/src/roms/rom_bls48_32.rs
new file mode 100644
index 0000000..83517a8
--- /dev/null
+++ b/src/roms/rom_bls48_32.rs
@@ -0,0 +1,309 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls48::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// bls48 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1CF6AC0B, 0x17B7307F, 0x19877E7B, 0x12CE0134, 0x14228402, 0x1BD4C386, 0x1DACBB04, 0x40410D0,
+ 0x25A415, 0x980B53E, 0xDE6E250, 0x15D9AAD6, 0x5DA950, 0x1029B7A, 0x54AB351, 0x14AD90CE,
+ 0x3729047, 0x1FE7E2D9, 0x145F610B, 0x1F,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xD59D0FA, 0x12F01FD0, 0xDE8FD41, 0x35AAEE1, 0xB937F48, 0x50700E8, 0x1F50EFCE, 0x1019B13C,
+ 0x3470A2F, 0x11094115, 0xF9FB72D, 0x6AD10E2, 0x1CFD9F8, 0x44F4785, 0x2B48793, 0x1148ED3,
+ 0xF609E61, 0x1EE34BC7, 0x1735D29E, 0x0,
+];
+pub const MCONST: Chunk = 0x9DA805D;
+pub const FRA: [Chunk; NLEN] = [
+ 0x1325BF89, 0x1311E7EC, 0xCD0A56F, 0x1A0FD46E, 0xE83BCCA, 0xCA97DD0, 0x18D1D297, 0x5F1E137,
+ 0x7AB9F2C, 0x13FC255F, 0x1C9DECEB, 0x9DEF4A2, 0x3C0F60B, 0x1D9909E4, 0x1FF27FF7, 0x1DBF8208,
+ 0x89BB36C, 0x40044E0, 0x62E01EE, 0x5,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x1325BF89, 0x1311E7EC, 0xCD0A56F, 0x1A0FD46E, 0xE83BCCA, 0xCA97DD0, 0x18D1D297, 0x5F1E137,
+ 0x7AB9F2C, 0x13FC255F, 0x1C9DECEB, 0x9DEF4A2, 0x3C0F60B, 0x1D9909E4, 0x1FF27FF7, 0x1DBF8208,
+ 0x89BB36C, 0x40044E0, 0x62E01EE, 0x5,
+];
+
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 17;
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1, 0x17FFF800, 0xA769C21, 0x8AA813C, 0x2029C21, 0xA68F58B, 0xB6307F4, 0x1184DA51, 0x6DFED78,
+ 0x1A3C85E9, 0x571037B, 0x1637F1F9, 0x1C465FB0, 0x98354B9, 0x118DF17A, 0x1422355D, 0x43BF73E,
+ 0x6, 0x0, 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x5D71D33, 0x1943697B, 0x18CB783F, 0x1B00AA9F, 0x1711EE0B, 0x7F80B23, 0x129FD8CC, 0x1345E03F,
+ 0x9A80F66, 0x7038173, 0xC056511, 0x142801F5, 0x42B2C3A, 0x1AF09869, 0x7924166, 0x8381264,
+ 0x957EDD7, 0xBACAEDC, 0xA27A4A1, 0x13,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xA6ED83A, 0x14D2D9FF, 0xA29C33D, 0x1B8972A9, 0x6958677, 0x19C8F547, 0x1DED7E3E, 0x14F9E3DC,
+ 0x18FB7229, 0x27171C0, 0x1551E32D, 0xE6184CC, 0x6260E3C, 0x733D204, 0x579C437, 0x1534665C,
+ 0x2B3349D, 0x3162FD7, 0xB634253, 0x1,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0x1DE40020, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x1F12ABEB, 0x516887B, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xCBBA429, 0x1B273F3, 0xD3DD160, 0x19C61452, 0x308093A, 0x146E1E34, 0xAE0E768, 0x1185948,
+ 0x1B73BC2D, 0x93D855C, 0x1B1A639C, 0x118C919B, 0xFF04AE3, 0xF1CCD77, 0x91318E5, 0x10644780,
+ 0x3A79F7, 0x1BE77919, 0x145F60F3, 0x1F,
+];
+pub const CURVE_PXAAA: [Chunk; NLEN] = [
+ 0x923CE4A, 0x14697474, 0xAE04F4A, 0x17AE205A, 0x1313A20C, 0x10B2EC50, 0x18DF074F, 0x15FE3FE8,
+ 0x7C90B98, 0x959BF85, 0xE57BD37, 0x14376C96, 0xBF57375, 0xE20B625, 0x12EE2172, 0x1CBBCE85,
+ 0x1A5D9487, 0xD0E024B, 0x195E3602, 0x1C,
+];
+pub const CURVE_PXAAB: [Chunk; NLEN] = [
+ 0xC0A1BE1, 0x138E6E2D, 0x1DF5FDC, 0x151FC760, 0x33972C5, 0x56AA3C2, 0x2491D8C, 0x115B9FD7,
+ 0x140A11FA, 0x1873AE35, 0x1F259C26, 0x74B0647, 0x12D18B04, 0x4672431, 0x1C27F419, 0x1CAA4D35,
+ 0x18DB48B6, 0x13A54BDA, 0x5080497, 0x5,
+];
+pub const CURVE_PXABA: [Chunk; NLEN] = [
+ 0x170C5DC4, 0x11D39263, 0x16B3BCB6, 0x152C95BB, 0x19BEC736, 0x8849A12, 0x49AB2A8, 0xC7162D3,
+ 0xC58CD55, 0x15C2659, 0x11EE8B90, 0xB40CAFC, 0xE233167, 0x7BEC8BE, 0x129335BD, 0x151C7DBB,
+ 0x78B689B, 0x1B6B8EED, 0x14BFBE3D, 0x16,
+];
+pub const CURVE_PXABB: [Chunk; NLEN] = [
+ 0x1A64B740, 0x6B14B34, 0x12481578, 0x23FA931, 0x323ADD1, 0x206B82A, 0xD789E1B, 0x1FCFA666,
+ 0x1F4EEA7, 0xF1E39E2, 0x1968610, 0xAF3EBD3, 0x590D3B, 0xDA0C35A, 0x17306AAF, 0xCF9DD2B,
+ 0x3F63B1A, 0x96FF2F9, 0xE102A76, 0x12,
+];
+pub const CURVE_PXBAA: [Chunk; NLEN] = [
+ 0x12F1E01F, 0xDD8630B, 0x12C29802, 0x186239A6, 0x19218788, 0x4C87D1, 0x16AE2501, 0x775C076,
+ 0x870C80B, 0x1A394429, 0x1637D478, 0x4A420E8, 0x1C3AD4D4, 0x10E5E713, 0x111E6AD5, 0x514FCF0,
+ 0x7CC49D3, 0xC678A2, 0x1787BDFD, 0x1B,
+];
+pub const CURVE_PXBAB: [Chunk; NLEN] = [
+ 0x637383D, 0x1851C11C, 0x661F866, 0x14404A7F, 0x15D3D212, 0x9AE28F6, 0x8051F25, 0x1E1CE2BF,
+ 0x137D882F, 0xB231CEB, 0xA8DB8FC, 0x18957645, 0x5E54DA8, 0x1FF41C44, 0x1A297414, 0x17E1CBC5,
+ 0x1014F91F, 0x4282AB7, 0xB6CE9E3, 0x10,
+];
+pub const CURVE_PXBBA: [Chunk; NLEN] = [
+ 0x1711939C, 0xB41ED9E, 0x69066BA, 0x137CA3AD, 0xCF2F6C0, 0x5E6DAB9, 0x2CE1323, 0x946E448,
+ 0xF353D1C, 0x14D9919F, 0x46B7046, 0x1A12015, 0x3D6070, 0x18C3E8D2, 0x1F23BA45, 0x1F1A337C,
+ 0x435A9CC, 0x6CA1DF1, 0x8A9CE1, 0x15,
+];
+pub const CURVE_PXBBB: [Chunk; NLEN] = [
+ 0x56F4899, 0x196A0854, 0xA959750, 0x38A3D72, 0x190BC9BC, 0x145752BC, 0x1E9E26DA, 0x1403F88,
+ 0x71895E3, 0x14162F5D, 0x19FEC5FF, 0x14190B16, 0x7597C, 0x19A3CF18, 0x26A4B00, 0x113D1BB6,
+ 0x7857A32, 0xE0B78AB, 0x1DD51E0F, 0x1B,
+];
+pub const CURVE_PYAAA: [Chunk; NLEN] = [
+ 0x14137844, 0x1704BE7D, 0x1FD3CCDD, 0x189D8C93, 0x1C768851, 0xF5C37D5, 0xE29C659, 0x20AB1C1,
+ 0xF8896E0, 0x1E08663E, 0x1D1D539C, 0x117E1C47, 0x156CDD39, 0x161F1017, 0x143E8C72, 0x174B22FD,
+ 0x18706190, 0x49AA47E, 0x19BB42E1, 0xE,
+];
+pub const CURVE_PYAAB: [Chunk; NLEN] = [
+ 0xDC83190, 0x12F19247, 0x1AA26424, 0x15D55E88, 0xC418D32, 0xB0E91DD, 0x47CBFF7, 0x2D992C1,
+ 0xDE03C1F, 0x7694AE5, 0x5C741A2, 0x1D423AC6, 0x5E02B9E, 0x1E903F10, 0x4EA6513, 0x433A1F1,
+ 0x8EFA1C4, 0xED54713, 0x1E72CE4F, 0x4,
+];
+pub const CURVE_PYABA: [Chunk; NLEN] = [
+ 0x1985C0D, 0xEE2FE82, 0x64770FA, 0x11A809B4, 0x1483ACE9, 0x18BCD2FA, 0x171F32C, 0x1612D58D,
+ 0x1E658341, 0x1CBE2201, 0x186E971, 0x73F0E1, 0xB0A5F40, 0xAC90FB0, 0x1635E008, 0x237498B,
+ 0x1F3140D6, 0xBF789A9, 0x1166F259, 0x1A,
+];
+pub const CURVE_PYABB: [Chunk; NLEN] = [
+ 0x159D42F8, 0x1B7F0540, 0x45895D7, 0x14875FA2, 0x1E9E7F2B, 0x10139D87, 0x10F3FD7D, 0x11D3717F,
+ 0x69E5006, 0xF9BB3C4, 0x13C9ED8D, 0x16516DA, 0x102F51DE, 0x2725FEC, 0x1F125B66, 0xFFC324,
+ 0x1ED80731, 0x1C16C4D, 0x383AAA8, 0x14,
+];
+pub const CURVE_PYBAA: [Chunk; NLEN] = [
+ 0x1F38039F, 0x6A8959C, 0x13C68984, 0x11DD12AF, 0x58093CF, 0x1C8550A0, 0xFFA1622, 0xFF85979,
+ 0x1F2ABB75, 0x18862E62, 0x1EB6A2C9, 0x1EC80B64, 0x8EC2F18, 0xE7BF713, 0xC36B65A, 0x19C5DD89,
+ 0x18A1D1AB, 0xF772C8D, 0xC11927C, 0x5,
+];
+pub const CURVE_PYBAB: [Chunk; NLEN] = [
+ 0x95F7865, 0x134F0379, 0x1CE9A0E, 0x17E0EADD, 0x1DACADD7, 0x1B18F9F8, 0x181D3943, 0x186679A,
+ 0x2505BB0, 0x1FDF1DC8, 0x11B36A49, 0x11E254E9, 0xA438576, 0x102B09AE, 0x139984F4, 0x15BC0233,
+ 0x1B6F180E, 0x960562B, 0x48CA65B, 0x6,
+];
+pub const CURVE_PYBBA: [Chunk; NLEN] = [
+ 0x7CC1979, 0xEC1D4FB, 0x1D89E6F0, 0x955F38E, 0x1635FDA9, 0x123D8E10, 0x10076209, 0x494404A,
+ 0xD733D7, 0x17678BCF, 0x153841F9, 0x10696FFD, 0x5BC9FE8, 0x1A20D8B2, 0xE22EC9D, 0x18449116,
+ 0x108C86C5, 0x1B4CD720, 0x34967, 0x19,
+];
+pub const CURVE_PYBBB: [Chunk; NLEN] = [
+ 0xFC9F25B, 0x7E44AB1, 0xE9AB5D3, 0x589F00D, 0x1C9D264F, 0xC7478B4, 0x16B24A13, 0x1D2C146B,
+ 0xEF84D9A, 0xF47ECDE, 0x1BFEE16A, 0x1B69071E, 0x11AB4C1C, 0xBE9D9EF, 0x390F005, 0x78C8288,
+ 0x1B9BF549, 0x9320730, 0x3D84D97, 0x14,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 70;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 556;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 32;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_bls48_64.rs b/src/roms/rom_bls48_64.rs
new file mode 100644
index 0000000..129c776
--- /dev/null
+++ b/src/roms/rom_bls48_64.rs
@@ -0,0 +1,401 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bls48::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 58
+// bls48 Modulus
+
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x2F6E60FFCF6AC0B,
+ 0x259C02699877E7B,
+ 0x37A9870D4228402,
+ 0x80821A1DACBB04,
+ 0x13016A7C025A415,
+ 0x2BB355ACDE6E250,
+ 0x20536F405DA950,
+ 0x295B219C54AB351,
+ 0x3FCFC5B23729047,
+ 0x3F45F610B,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x25E03FA0D59D0FA,
+ 0x6B55DC2DE8FD41,
+ 0xA0E01D0B937F48,
+ 0x20336279F50EFCE,
+ 0x2212822A3470A2F,
+ 0xD5A21C4F9FB72D,
+ 0x89E8F0A1CFD9F8,
+ 0x2291DA62B48793,
+ 0x3DC6978EF609E61,
+ 0x1735D29E,
+];
+pub const MCONST: Chunk = 0x21BFCBCA9DA805D;
+pub const FRA: [Chunk; NLEN] = [
+ 0x2623CFD9325BF89,
+ 0x341FA8DCCD0A56F,
+ 0x1952FBA0E83BCCA,
+ 0xBE3C26F8D1D297,
+ 0x27F84ABE7AB9F2C,
+ 0x13BDE945C9DECEB,
+ 0x3B3213C83C0F60B,
+ 0x3B7F0411FF27FF7,
+ 0x80089C089BB36C,
+ 0xA62E01EE,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x2623CFD9325BF89,
+ 0x341FA8DCCD0A56F,
+ 0x1952FBA0E83BCCA,
+ 0xBE3C26F8D1D297,
+ 0x27F84ABE7AB9F2C,
+ 0x13BDE945C9DECEB,
+ 0x3B3213C83C0F60B,
+ 0x3B7F0411FF27FF7,
+ 0x80089C089BB36C,
+ 0xA62E01EE,
+];
+
+pub const CURVE_COF_I: isize = 0;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 17;
+pub const CURVE_B: [Chunk; NLEN] = [0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x2FFFF0000000001,
+ 0x11550278A769C21,
+ 0x14D1EB162029C21,
+ 0x2309B4A2B6307F4,
+ 0x34790BD26DFED78,
+ 0x2C6FE3F2571037B,
+ 0x1306A973C465FB0,
+ 0x28446ABB18DF17A,
+ 0xC43BF73E,
+ 0x0,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x3286D2F65D71D33,
+ 0x3601553F8CB783F,
+ 0xFF01647711EE0B,
+ 0x268BC07F29FD8CC,
+ 0xE0702E69A80F66,
+ 0x285003EAC056511,
+ 0x35E130D242B2C3A,
+ 0x107024C87924166,
+ 0x17595DB8957EDD7,
+ 0x26A27A4A1,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x29A5B3FEA6ED83A,
+ 0x3712E552A29C33D,
+ 0x3391EA8E6958677,
+ 0x29F3C7B9DED7E3E,
+ 0x4E2E3818FB7229,
+ 0x1CC30999551E32D,
+ 0xE67A4086260E3C,
+ 0x2A68CCB8579C437,
+ 0x62C5FAE2B3349D,
+ 0x2B634253,
+];
+
+pub const CURVE_BNX: [Chunk; NLEN] = [0x7DE40020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0xA2D10F7F12ABEB,
+ 0x5,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x364E7E6CBBA429,
+ 0x338C28A4D3DD160,
+ 0x28DC3C68308093A,
+ 0x230B290AE0E768,
+ 0x127B0AB9B73BC2D,
+ 0x23192337B1A639C,
+ 0x1E399AEEFF04AE3,
+ 0x20C88F0091318E5,
+ 0x37CEF23203A79F7,
+ 0x3F45F60F3,
+];
+pub const CURVE_PXAAA: [Chunk; NLEN] = [
+ 0x28D2E8E8923CE4A,
+ 0x2F5C40B4AE04F4A,
+ 0x2165D8A1313A20C,
+ 0x2BFC7FD18DF074F,
+ 0x12B37F0A7C90B98,
+ 0x286ED92CE57BD37,
+ 0x1C416C4ABF57375,
+ 0x39779D0B2EE2172,
+ 0x1A1C0497A5D9487,
+ 0x3995E3602,
+];
+pub const CURVE_PXAAB: [Chunk; NLEN] = [
+ 0x271CDC5AC0A1BE1,
+ 0x2A3F8EC01DF5FDC,
+ 0xAD5478433972C5,
+ 0x22B73FAE2491D8C,
+ 0x30E75C6B40A11FA,
+ 0xE960C8FF259C26,
+ 0x8CE48632D18B04,
+ 0x39549A6BC27F419,
+ 0x274A97B58DB48B6,
+ 0xA5080497,
+];
+pub const CURVE_PXABA: [Chunk; NLEN] = [
+ 0x23A724C770C5DC4,
+ 0x2A592B776B3BCB6,
+ 0x110934259BEC736,
+ 0x18E2C5A649AB2A8,
+ 0x2B84CB2C58CD55,
+ 0x168195F91EE8B90,
+ 0xF7D917CE233167,
+ 0x2A38FB7729335BD,
+ 0x36D71DDA78B689B,
+ 0x2D4BFBE3D,
+];
+pub const CURVE_PXABB: [Chunk; NLEN] = [
+ 0xD629669A64B740,
+ 0x47F52632481578,
+ 0x40D7054323ADD1,
+ 0x3F9F4CCCD789E1B,
+ 0x1E3C73C41F4EEA7,
+ 0x15E7D7A61968610,
+ 0x1B4186B40590D3B,
+ 0x19F3BA577306AAF,
+ 0x12DFE5F23F63B1A,
+ 0x24E102A76,
+];
+pub const CURVE_PXBAA: [Chunk; NLEN] = [
+ 0x1BB0C6172F1E01F,
+ 0x30C4734D2C29802,
+ 0x990FA39218788,
+ 0xEEB80ED6AE2501,
+ 0x34728852870C80B,
+ 0x94841D1637D478,
+ 0x21CBCE27C3AD4D4,
+ 0xA29F9E111E6AD5,
+ 0x18CF1447CC49D3,
+ 0x37787BDFD,
+];
+pub const CURVE_PXBAB: [Chunk; NLEN] = [
+ 0x30A38238637383D,
+ 0x288094FE661F866,
+ 0x135C51ED5D3D212,
+ 0x3C39C57E8051F25,
+ 0x164639D737D882F,
+ 0x312AEC8AA8DB8FC,
+ 0x3FE838885E54DA8,
+ 0x2FC3978BA297414,
+ 0x850556F014F91F,
+ 0x20B6CE9E3,
+];
+pub const CURVE_PXBBA: [Chunk; NLEN] = [
+ 0x1683DB3D711939C,
+ 0x26F9475A69066BA,
+ 0xBCDB572CF2F6C0,
+ 0x128DC8902CE1323,
+ 0x29B3233EF353D1C,
+ 0x342402A46B7046,
+ 0x3187D1A403D6070,
+ 0x3E3466F9F23BA45,
+ 0xD943BE2435A9CC,
+ 0x2A08A9CE1,
+];
+pub const CURVE_PXBBB: [Chunk; NLEN] = [
+ 0x32D410A856F4899,
+ 0x7147AE4A959750,
+ 0x28AEA57990BC9BC,
+ 0x2807F11E9E26DA,
+ 0x282C5EBA71895E3,
+ 0x2832162D9FEC5FF,
+ 0x33479E30007597C,
+ 0x227A376C26A4B00,
+ 0x1C16F1567857A32,
+ 0x37DD51E0F,
+];
+pub const CURVE_PYAAA: [Chunk; NLEN] = [
+ 0x2E097CFB4137844,
+ 0x313B1927FD3CCDD,
+ 0x1EB86FABC768851,
+ 0x4156382E29C659,
+ 0x3C10CC7CF8896E0,
+ 0x22FC388FD1D539C,
+ 0x2C3E202F56CDD39,
+ 0x2E9645FB43E8C72,
+ 0x93548FD8706190,
+ 0x1D9BB42E1,
+];
+pub const CURVE_PYAAB: [Chunk; NLEN] = [
+ 0x25E3248EDC83190,
+ 0x2BAABD11AA26424,
+ 0x161D23BAC418D32,
+ 0x5B3258247CBFF7,
+ 0xED295CADE03C1F,
+ 0x3A84758C5C741A2,
+ 0x3D207E205E02B9E,
+ 0x86743E24EA6513,
+ 0x1DAA8E268EFA1C4,
+ 0x9E72CE4F,
+];
+pub const CURVE_PYABA: [Chunk; NLEN] = [
+ 0x1DC5FD041985C0D,
+ 0x2350136864770FA,
+ 0x3179A5F5483ACE9,
+ 0x2C25AB1A171F32C,
+ 0x397C4403E658341,
+ 0xE7E1C2186E971,
+ 0x15921F60B0A5F40,
+ 0x46E9317635E008,
+ 0x17EF1353F3140D6,
+ 0x35166F259,
+];
+pub const CURVE_PYABB: [Chunk; NLEN] = [
+ 0x36FE0A8159D42F8,
+ 0x290EBF4445895D7,
+ 0x20273B0FE9E7F2B,
+ 0x23A6E2FF0F3FD7D,
+ 0x1F37678869E5006,
+ 0x2CA2DB53C9ED8D,
+ 0x4E4BFD902F51DE,
+ 0x1FF8649F125B66,
+ 0x382D89BED80731,
+ 0x28383AAA8,
+];
+pub const CURVE_PYBAA: [Chunk; NLEN] = [
+ 0xD512B39F38039F,
+ 0x23BA255F3C68984,
+ 0x390AA14058093CF,
+ 0x1FF0B2F2FFA1622,
+ 0x310C5CC5F2ABB75,
+ 0x3D9016C9EB6A2C9,
+ 0x1CF7EE268EC2F18,
+ 0x338BBB12C36B65A,
+ 0x1EEE591B8A1D1AB,
+ 0xAC11927C,
+];
+pub const CURVE_PYBAB: [Chunk; NLEN] = [
+ 0x269E06F295F7865,
+ 0x2FC1D5BA1CE9A0E,
+ 0x3631F3F1DACADD7,
+ 0x30CCF3581D3943,
+ 0x3FBE3B902505BB0,
+ 0x23C4A9D31B36A49,
+ 0x2056135CA438576,
+ 0x2B78046739984F4,
+ 0x12C0AC57B6F180E,
+ 0xC48CA65B,
+];
+pub const CURVE_PYBBA: [Chunk; NLEN] = [
+ 0x1D83A9F67CC1979,
+ 0x12ABE71DD89E6F0,
+ 0x247B1C21635FDA9,
+ 0x92880950076209,
+ 0x2ECF179E0D733D7,
+ 0x20D2DFFB53841F9,
+ 0x3441B1645BC9FE8,
+ 0x3089222CE22EC9D,
+ 0x3699AE4108C86C5,
+ 0x320034967,
+];
+pub const CURVE_PYBBB: [Chunk; NLEN] = [
+ 0xFC89562FC9F25B,
+ 0xB13E01AE9AB5D3,
+ 0x18E8F169C9D264F,
+ 0x3A5828D76B24A13,
+ 0x1E8FD9BCEF84D9A,
+ 0x36D20E3DBFEE16A,
+ 0x17D3B3DF1AB4C1C,
+ 0xF190510390F005,
+ 0x12640E61B9BF549,
+ 0x283D84D97,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 70;
+pub const BASEBITS: usize = 58;
+
+pub const MODBITS: usize = 556;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BLS;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 32;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_bn254CX_32.rs b/src/roms/rom_bn254CX_32.rs
new file mode 100644
index 0000000..e1cff0d
--- /dev/null
+++ b/src/roms/rom_bn254CX_32.rs
@@ -0,0 +1,183 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bn254CX::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// bn254CX Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xC1B55B3, 0x6623EF5, 0x93EE1BE, 0xD6EE180, 0x6D3243F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x8A0800A, 0x466A061, 0x43056A3, 0x2B3A225, 0x9C6600, 0x148515B, 0x6BDF50, 0xEC9EA56,
+ 0xC992E66, 0x1,
+];
+pub const MCONST: Chunk = 0x9789E85;
+pub const FRA: [Chunk; NLEN] = [
+ 0x5C80EA3, 0xD908335, 0x3F8215B, 0x7326F17, 0x8986867, 0x8AACA71, 0x4AFE18B, 0xA63A016,
+ 0x359082F, 0x1,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x6534710, 0x8D1BBC0, 0x546C062, 0x63C7269, 0xE3ABBD8, 0xD9CDBC4, 0x900DC53, 0x623628A,
+ 0xA6F7D0, 0x1,
+];
+
+// bn254CX Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 2;
+pub const CURVE_B: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x6EB1F6D, 0x11C0A63, 0x906CEBE, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xC1B55B2, 0x6623EF5, 0x93EE1BE, 0xD6EE180, 0x6D3243F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_BNX: [Chunk; NLEN] = [0x3C012B1, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x4235C97, 0xE093179, 0xF875631, 0xDF6471E, 0xF1440BD, 0xCA83, 0x480000, 0x0, 0x0, 0x0,
+];
+
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x4D2EC74, 0x851CEEE, 0xE2726C0, 0x85BFA03, 0xBBB907C, 0xF5C34, 0x6358B25, 0x7053B25,
+ 0x9682D2C, 0x1,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0xE29CFE1, 0xA58E8B2, 0x9C30F47, 0x97B0C20, 0x743F81B, 0x37A8E99, 0xAA011C9, 0x3E19F64,
+ 0x466B9EC, 0x1,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0xF0BE09F, 0xFBFCEBC, 0xEC1B30C, 0xB33D847, 0x2096361, 0x157DAEE, 0xDD81E22, 0x72332B8,
+ 0xA79EDD9, 0x0,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x898EE9D, 0x904B228, 0x2EDEBED, 0x4EA569D, 0x461C286, 0x512D8D3, 0x35C6E4, 0xECC4C09,
+ 0x6160C39, 0x0,
+];
+
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x62FEB83, 0x5463491, 0x381200, 0xB4, 0x6000, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0xDB010E4, 0x5463491, 0x381280, 0xB4, 0x6000, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0xBB33EA, 0xBD5D5D2, 0x8CEBCBD, 0xD6EE018, 0x6D2643F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x67A84B0, 0x1C21185, 0x12B040, 0x3C, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xE220475, 0xCDF995B, 0xA7F9A36, 0x94EDA8C, 0xA0DC07E, 0x8702, 0x300000, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xF10B93, 0x66FCCAE, 0x53FCD3B, 0x4A76D46, 0x506E03F, 0x4381, 0x180000, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xDFAAA11, 0x1C21185, 0x12B0C0, 0x3C, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x32B0CBD, 0x11C0A63, 0x906CE7E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ [
+ 0x32B0CBC, 0x11C0A63, 0x906CE7E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ [
+ 0x32B0CBC, 0x11C0A63, 0x906CE7E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ [0x7802562, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0x32B0CBC, 0x11C0A63, 0x906CE7E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ [
+ 0x32B0CBD, 0x11C0A63, 0x906CE7E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ [
+ 0x32B0CBC, 0x11C0A63, 0x906CE7E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ ],
+ [
+ [0x7802562, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x7802561, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x3C012B2, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0xF004AC2, 0x0, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0xF6AFA0A, 0x11C0A62, 0x906CE3E, 0xD6EE0CC, 0x6D2C43F, 0x647A636, 0xDB0BDDF, 0x8702A0,
+ 0x4000000, 0x2,
+ ],
+ [0x3C012B2, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 254;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::D_TYPE;
+pub const ATE_BITS: usize = 66;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bn254CX_64.rs b/src/roms/rom_bn254CX_64.rs
new file mode 100644
index 0000000..7f6d274
--- /dev/null
+++ b/src/roms/rom_bn254CX_64.rs
@@ -0,0 +1,242 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bn254CX::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+
+// Base Bits= 56
+// bn254CX Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x6623EF5C1B55B3,
+ 0xD6EE18093EE1BE,
+ 0x647A6366D3243F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x466A0618A0800A,
+ 0x2B3A22543056A3,
+ 0x148515B09C6600,
+ 0xEC9EA5606BDF50,
+ 0x1C992E66,
+];
+pub const MCONST: Chunk = 0x4E205BF9789E85;
+pub const FRA: [Chunk; NLEN] = [
+ 0xD9083355C80EA3,
+ 0x7326F173F8215B,
+ 0x8AACA718986867,
+ 0xA63A0164AFE18B,
+ 0x1359082F,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x8D1BBC06534710,
+ 0x63C7269546C062,
+ 0xD9CDBC4E3ABBD8,
+ 0x623628A900DC53,
+ 0x10A6F7D0,
+];
+
+// bn254CX Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 2;
+pub const CURVE_B: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x11C0A636EB1F6D,
+ 0xD6EE0CC906CEBE,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x6623EF5C1B55B2,
+ 0xD6EE18093EE1BE,
+ 0x647A6366D3243F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_BNX: [Chunk; NLEN] = [0x3C012B1, 0x40, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xE0931794235C97,
+ 0xDF6471EF875631,
+ 0xCA83F1440BD,
+ 0x480000,
+ 0x0,
+];
+
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x851CEEE4D2EC74,
+ 0x85BFA03E2726C0,
+ 0xF5C34BBB907C,
+ 0x7053B256358B25,
+ 0x19682D2C,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0xA58E8B2E29CFE1,
+ 0x97B0C209C30F47,
+ 0x37A8E99743F81B,
+ 0x3E19F64AA011C9,
+ 0x1466B9EC,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0xFBFCEBCF0BE09F,
+ 0xB33D847EC1B30C,
+ 0x157DAEE2096361,
+ 0x72332B8DD81E22,
+ 0xA79EDD9,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x904B228898EE9D,
+ 0x4EA569D2EDEBED,
+ 0x512D8D3461C286,
+ 0xECC4C09035C6E4,
+ 0x6160C39,
+];
+
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x546349162FEB83, 0xB40381200, 0x6000, 0x0, 0x0],
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x5463491DB010E4, 0xB40381280, 0x6000, 0x0, 0x0],
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+ [
+ 0xBD5D5D20BB33EA,
+ 0xD6EE0188CEBCBD,
+ 0x647A6366D2643F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x1C2118567A84B0, 0x3C012B040, 0x2000, 0x0, 0x0],
+ [
+ 0xCDF995BE220475,
+ 0x94EDA8CA7F9A36,
+ 0x8702A0DC07E,
+ 0x300000,
+ 0x0,
+ ],
+ [
+ 0x66FCCAE0F10B93,
+ 0x4A76D4653FCD3B,
+ 0x4381506E03F,
+ 0x180000,
+ 0x0,
+ ],
+ [0x1C21185DFAAA11, 0x3C012B0C0, 0x2000, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x11C0A6332B0CBD,
+ 0xD6EE0CC906CE7E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ [
+ 0x11C0A6332B0CBC,
+ 0xD6EE0CC906CE7E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ [
+ 0x11C0A6332B0CBC,
+ 0xD6EE0CC906CE7E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ [0x7802562, 0x80, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+ [
+ 0x11C0A6332B0CBC,
+ 0xD6EE0CC906CE7E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ [
+ 0x11C0A6332B0CBD,
+ 0xD6EE0CC906CE7E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ [
+ 0x11C0A6332B0CBC,
+ 0xD6EE0CC906CE7E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ ],
+ [
+ [0x7802562, 0x80, 0x0, 0x0, 0x0],
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+ [0x7802561, 0x80, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x3C012B2, 0x40, 0x0, 0x0, 0x0],
+ [0xF004AC2, 0x100, 0x0, 0x0, 0x0],
+ [
+ 0x11C0A62F6AFA0A,
+ 0xD6EE0CC906CE3E,
+ 0x647A6366D2C43F,
+ 0x8702A0DB0BDDF,
+ 0x24000000,
+ ],
+ [0x3C012B2, 0x40, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = true;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 254;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 64;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::D_TYPE;
+pub const ATE_BITS: usize = 66;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bn254_32.rs b/src/roms/rom_bn254_32.rs
new file mode 100644
index 0000000..c9ae5ec
--- /dev/null
+++ b/src/roms/rom_bn254_32.rs
@@ -0,0 +1,171 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bn254::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x13, 0x0, 0x13A7, 0x0, 0x86121, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482, 0x2,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xF5E7E39, 0x2F2A96F, 0xB96F13C, 0x64E8642, 0xC7146, 0x9926F7B, 0x4DACD24, 0x8321E7B,
+ 0xD127A2E, 0x1,
+];
+pub const MCONST: Chunk = 0x79435E5;
+pub const FRA: [Chunk; NLEN] = [
+ 0xF2A6DE9, 0x7DE6C06, 0xF77C2E1, 0x74924D3, 0x53F8509, 0x50A8469, 0xCB6499B, 0x212E7C8,
+ 0xB377619, 0x1,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xD5922A, 0x82193F9, 0x8850C5, 0x8B6DB2C, 0xAC8DC17, 0x2F57B96, 0x503EAB2, 0x1ED1837,
+ 0x9EBEE69, 0x0,
+];
+
+// BN254 Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 2;
+pub const CURVE_B: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xD, 0x0, 0x10A1, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482, 0x2,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x12, 0x0, 0x13A7, 0x0, 0x86121, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482, 0x2,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_BNX: [Chunk; NLEN] = [0x1, 0x8000000, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x7, 0x8000000, 0x6CD, 0x0, 0x24909, 0x4000000, 0x49B362, 0x0, 0x0, 0x0,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x803FB2B, 0xEE4224C, 0x8BF0D91, 0x8BBB489, 0xDB6A464, 0x7E8C61E, 0xFEB8D8C, 0x519EB62,
+ 0x61A10BB, 0x0,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x7D54CF3, 0x8C34C1E, 0x784B70D, 0x746BAE3, 0xA5B1F4D, 0x8C5982A, 0x3310AA7, 0xBA73783,
+ 0x516AAF9, 0x0,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x1CD2B9A, 0xF0E0789, 0xE09BD19, 0xAE6BDB, 0x22329BD, 0x96698C8, 0x39A90E0, 0x6BAF934,
+ 0x21897A0, 0x0,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0xB3ACE9B, 0x2D1AEC6, 0x9C9578A, 0x6FFD73, 0xD37B090, 0x56F5F38, 0x68F6D44, 0x7C8B152,
+ 0xEBB2B0E, 0x0,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x3, 0x0, 0x204, 0x8000000, 0x6181, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x4, 0x0, 0x285, 0x8000000, 0x6181, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0xA, 0x0, 0xE9D, 0x0, 0x79E1E, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482, 0x2,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x0, 0x8000000, 0x40, 0x8000000, 0x2080, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x5, 0x8000000, 0x54A, 0x0, 0x1C707, 0x8000000, 0x312241, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x3, 0x8000000, 0x2C5, 0x8000000, 0xE383, 0xC000000, 0x189120, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1, 0x8000000, 0xC1, 0x8000000, 0x2080, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0xD, 0x8000000, 0x1060, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482,
+ 0x2,
+ ],
+ [
+ 0xC, 0x8000000, 0x1060, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482,
+ 0x2,
+ ],
+ [
+ 0xC, 0x8000000, 0x1060, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482,
+ 0x2,
+ ],
+ [0x2, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0xC, 0x8000000, 0x1060, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482,
+ 0x2,
+ ],
+ [
+ 0xD, 0x8000000, 0x1060, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482,
+ 0x2,
+ ],
+ [
+ 0xC, 0x8000000, 0x1060, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482,
+ 0x2,
+ ],
+ ],
+ [
+ [0x2, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1, 0x0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x2, 0x8000000, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x2, 0x0, 0x102, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0xA, 0x0, 0x1020, 0x8000000, 0x7FF9F, 0x8000000, 0x1BA344D, 0x4000000, 0x5236482, 0x2,
+ ],
+ [0x2, 0x8000000, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 254;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::D_TYPE;
+pub const ATE_BITS: usize = 66;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_bn254_64.rs b/src/roms/rom_bn254_64.rs
new file mode 100644
index 0000000..f61b542
--- /dev/null
+++ b/src/roms/rom_bn254_64.rs
@@ -0,0 +1,208 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use bn254::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// BN254 Modulus
+// Base Bits= 56
+pub const MODULUS: [Chunk; NLEN] = [0x13, 0x13A7, 0x80000000086121, 0x40000001BA344D, 0x25236482];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x2F2A96FF5E7E39,
+ 0x64E8642B96F13C,
+ 0x9926F7B00C7146,
+ 0x8321E7B4DACD24,
+ 0x1D127A2E,
+];
+pub const MCONST: Chunk = 0x435E50D79435E5;
+pub const FRA: [Chunk; NLEN] = [
+ 0x7DE6C06F2A6DE9,
+ 0x74924D3F77C2E1,
+ 0x50A846953F8509,
+ 0x212E7C8CB6499B,
+ 0x1B377619,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x82193F90D5922A,
+ 0x8B6DB2C08850C5,
+ 0x2F57B96AC8DC17,
+ 0x1ED1837503EAB2,
+ 0x9EBEE69,
+];
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 2;
+pub const CURVE_B: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xD,
+ 0x800000000010A1,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0x12, 0x13A7, 0x80000000086121, 0x40000001BA344D, 0x25236482];
+pub const CURVE_GY: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_BNX: [Chunk; NLEN] = [0x80000000000001, 0x40, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [0x80000000000007, 0x6CD, 0x40000000024909, 0x49B362, 0x0];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0xEE4224C803FB2B,
+ 0x8BBB4898BF0D91,
+ 0x7E8C61EDB6A464,
+ 0x519EB62FEB8D8C,
+ 0x61A10BB,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x8C34C1E7D54CF3,
+ 0x746BAE3784B70D,
+ 0x8C5982AA5B1F4D,
+ 0xBA737833310AA7,
+ 0x516AAF9,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0xF0E07891CD2B9A,
+ 0xAE6BDBE09BD19,
+ 0x96698C822329BD,
+ 0x6BAF93439A90E0,
+ 0x21897A0,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x2D1AEC6B3ACE9B,
+ 0x6FFD739C9578A,
+ 0x56F5F38D37B090,
+ 0x7C8B15268F6D44,
+ 0xEBB2B0E,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0x3, 0x80000000000204, 0x6181, 0x0, 0x0],
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0x4, 0x80000000000285, 0x6181, 0x0, 0x0],
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+ [0xA, 0xE9D, 0x80000000079E1E, 0x40000001BA344D, 0x25236482],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x80000000000000, 0x80000000000040, 0x2080, 0x0, 0x0],
+ [0x80000000000005, 0x54A, 0x8000000001C707, 0x312241, 0x0],
+ [
+ 0x80000000000003,
+ 0x800000000002C5,
+ 0xC000000000E383,
+ 0x189120,
+ 0x0,
+ ],
+ [0x80000000000001, 0x800000000000C1, 0x2080, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x8000000000000D,
+ 0x80000000001060,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ [
+ 0x8000000000000C,
+ 0x80000000001060,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ [
+ 0x8000000000000C,
+ 0x80000000001060,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ [0x2, 0x81, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+ [
+ 0x8000000000000C,
+ 0x80000000001060,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ [
+ 0x8000000000000D,
+ 0x80000000001060,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ [
+ 0x8000000000000C,
+ 0x80000000001060,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ ],
+ [
+ [0x2, 0x81, 0x0, 0x0, 0x0],
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+ [0x1, 0x81, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x80000000000002, 0x40, 0x0, 0x0, 0x0],
+ [0x2, 0x102, 0x0, 0x0, 0x0],
+ [
+ 0xA,
+ 0x80000000001020,
+ 0x8000000007FF9F,
+ 0x40000001BA344D,
+ 0x25236482,
+ ],
+ [0x80000000000002, 0x40, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 254;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 26;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::D_TYPE;
+pub const ATE_BITS: usize = 66;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
\ No newline at end of file
diff --git a/src/roms/rom_brainpool_32.rs b/src/roms/rom_brainpool_32.rs
new file mode 100644
index 0000000..b788632
--- /dev/null
+++ b/src/roms/rom_brainpool_32.rs
@@ -0,0 +1,74 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Note that the original curve has been transformed to an isomorphic curve with A=-3 */
+
+use brainpool::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// brainpool Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xF6E5377, 0x13481D1, 0x6202820, 0xF623D52, 0xD726E3B, 0x909D838, 0xC3E660A, 0xA1EEA9B,
+ 0x9FB57DB, 0xA,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xB9A3787, 0x9E04F49, 0x8F3CF49, 0x2931721, 0xF1DBC89, 0x54E8C3C, 0xF7559CA, 0xBB411A3,
+ 0x773E15F, 0x9,
+];
+pub const MCONST: Chunk = 0xEFD89B9;
+
+// brainpool Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xEE92B04, 0xE58101F, 0xF49256A, 0xEBC4AF2, 0x6B7BF93, 0x733D0B7, 0x4FE66A7, 0x30D84EA,
+ 0x62C61C4, 0x6,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x74856A7, 0x1E0E829, 0x1A6F790, 0x7AA3B56, 0xD718C39, 0x909D838, 0xC3E660A, 0xA1EEA9B,
+ 0x9FB57DB, 0xA,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xE1305F4, 0xA191562, 0xFBC2B79, 0x42C47AA, 0x149AFA1, 0xB23A656, 0x7732213, 0xC1CFE7B,
+ 0x3E8EB3C, 0xA,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xB25C9BE, 0xABE8F35, 0x27001D, 0xB6DE39D, 0x17E69BC, 0xE146444, 0xD7F7B22, 0x3439C56,
+ 0xD996C82, 0x2,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_brainpool_64.rs b/src/roms/rom_brainpool_64.rs
new file mode 100644
index 0000000..8191561
--- /dev/null
+++ b/src/roms/rom_brainpool_64.rs
@@ -0,0 +1,92 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Note that the original curve has been transformed to an isomorphic curve with A=-3 */
+
+use brainpool::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// brainpool Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x13481D1F6E5377,
+ 0xF623D526202820,
+ 0x909D838D726E3B,
+ 0xA1EEA9BC3E660A,
+ 0xA9FB57DB,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x9E04F49B9A3787,
+ 0x29317218F3CF49,
+ 0x54E8C3CF1DBC89,
+ 0xBB411A3F7559CA,
+ 0x9773E15F,
+];
+pub const MCONST: Chunk = 0xA75590CEFD89B9;
+
+// brainpool Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xE58101FEE92B04,
+ 0xEBC4AF2F49256A,
+ 0x733D0B76B7BF93,
+ 0x30D84EA4FE66A7,
+ 0x662C61C4,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1E0E82974856A7,
+ 0x7AA3B561A6F790,
+ 0x909D838D718C39,
+ 0xA1EEA9BC3E660A,
+ 0xA9FB57DB,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xA191562E1305F4,
+ 0x42C47AAFBC2B79,
+ 0xB23A656149AFA1,
+ 0xC1CFE7B7732213,
+ 0xA3E8EB3C,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xABE8F35B25C9BE,
+ 0xB6DE39D027001D,
+ 0xE14644417E69BC,
+ 0x3439C56D7F7B22,
+ 0x2D996C82,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const ATE_BITS: usize = 0;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_c25519_32.rs b/src/roms/rom_c25519_32.rs
new file mode 100644
index 0000000..6da6a05
--- /dev/null
+++ b/src/roms/rom_c25519_32.rs
@@ -0,0 +1,59 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use c25519::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// Curve25519 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFFED, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x7FFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x169000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x13;
+
+// c25519 Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = 486662;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1CF5D3ED, 0x9318D2, 0x1DE73596, 0x1DF3BD45, 0x14D, 0x0, 0x0, 0x0, 0x100000,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 255;
+pub const MOD8: usize = 5;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 6;
+
+pub const CURVETYPE: CurveType = CurveType::MONTGOMERY;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_c25519_64.rs b/src/roms/rom_c25519_64.rs
new file mode 100644
index 0000000..9a8c59f
--- /dev/null
+++ b/src/roms/rom_c25519_64.rs
@@ -0,0 +1,61 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use c25519::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// Curve25519 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFED,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0x7FFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0xA4000000000000, 0x5, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x13;
+
+// c25519 Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = 486662;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] =
+ [0x12631A5CF5D3ED, 0xF9DEA2F79CD658, 0x14DE, 0x0, 0x10000000];
+pub const CURVE_GX: [Chunk; NLEN] = [0x9, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [0x0, 0x0, 0x0, 0x0, 0x0];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 255;
+pub const MOD8: usize = 5;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 25;
+
+pub const CURVETYPE: CurveType = CurveType::MONTGOMERY;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_c41417_32.rs b/src/roms/rom_c41417_32.rs
new file mode 100644
index 0000000..a8330cb
--- /dev/null
+++ b/src/roms/rom_c41417_32.rs
@@ -0,0 +1,71 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use c41417::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// c41417 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFFEF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0xFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x0, 0x242000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x11;
+
+// c41417 Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = 3617;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xE21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x106AF79, 0x18738D2F, 0x18F3C606, 0x1806715A, 0x22B36F1, 0xA67B830, 0xCF32490, 0x1FFFFFFD,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1F,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x13CBC595, 0x7E9C097, 0x14DF1931, 0x14E7F550, 0x1A111301, 0x15A6B6B5, 0xD526292, 0x18FEAFFE,
+ 0x1F44C03E, 0x1E6A31B4, 0x70C9B97, 0x43180C6, 0x1443300, 0x19A4828A, 0x68,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+
+pub const MODBYTES: usize = 52;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 414;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_c41417_64.rs b/src/roms/rom_c41417_64.rs
new file mode 100644
index 0000000..52b51b1
--- /dev/null
+++ b/src/roms/rom_c41417_64.rs
@@ -0,0 +1,78 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use c41417::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+// c41417 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFFEF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x121000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x11;
+
+// c41417 Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = 3617;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0xE21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xB0E71A5E106AF79,
+ 0x1C0338AD63CF181,
+ 0x414CF706022B36F,
+ 0xFFFFFFFFEB3CC92,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0x7FFFFFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x4FD3812F3CBC595,
+ 0x1A73FAA8537C64C,
+ 0x4AB4D6D6BA11130,
+ 0x3EC7F57FF35498A,
+ 0xE5FCD46369F44C0,
+ 0x300218C0631C326,
+ 0x1A334905141443,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+
+pub const MODBYTES: usize = 52;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 414;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 6;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_ed25519_32.rs b/src/roms/rom_ed25519_32.rs
new file mode 100644
index 0000000..be1d156
--- /dev/null
+++ b/src/roms/rom_ed25519_32.rs
@@ -0,0 +1,68 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use ed25519::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// Curve25519 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFFED, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x7FFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x169000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x13;
+
+// Ed25519 Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = -1;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x135978A3, 0xF5A6E50, 0x10762ADD, 0x149A82, 0x1E898007, 0x3CBBBC, 0x19CE331D, 0x1DC56DFF,
+ 0x52036C,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1CF5D3ED, 0x9318D2, 0x1DE73596, 0x1DF3BD45, 0x14D, 0x0, 0x0, 0x0, 0x100000,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xF25D51A, 0xAB16B04, 0x969ECB2, 0x198EC12A, 0xDC5C692, 0x1118FEEB, 0xFFB0293, 0x1A79ADCA,
+ 0x216936,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x6666658, 0x13333333, 0x19999999, 0xCCCCCCC, 0x6666666, 0x13333333, 0x19999999, 0xCCCCCCC,
+ 0x666666,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 255;
+pub const MOD8: usize = 5;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 6;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_ed25519_64.rs b/src/roms/rom_ed25519_64.rs
new file mode 100644
index 0000000..cf23672
--- /dev/null
+++ b/src/roms/rom_ed25519_64.rs
@@ -0,0 +1,79 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use ed25519::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// Curve25519 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFED,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0x7FFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0xA4000000000000, 0x5, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x13;
+
+// Ed25519 Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = -1;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xEB4DCA135978A3,
+ 0xA4D4141D8AB75,
+ 0x797779E8980070,
+ 0x2B6FFE738CC740,
+ 0x52036CEE,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] =
+ [0x12631A5CF5D3ED, 0xF9DEA2F79CD658, 0x14DE, 0x0, 0x10000000];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x562D608F25D51A,
+ 0xC7609525A7B2C9,
+ 0x31FDD6DC5C692C,
+ 0xCD6E53FEC0A4E2,
+ 0x216936D3,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x66666666666658,
+ 0x66666666666666,
+ 0x66666666666666,
+ 0x66666666666666,
+ 0x66666666,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 255;
+pub const MOD8: usize = 5;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 25;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_fp256bn_32.rs b/src/roms/rom_fp256bn_32.rs
new file mode 100644
index 0000000..e3cabe1
--- /dev/null
+++ b/src/roms/rom_fp256bn_32.rs
@@ -0,0 +1,180 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use fp256bn::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+
+// Base Bits= 28
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xED33013, 0x292DDBA, 0x80A82D3, 0x65FB129, 0x49F0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x3B9F8B, 0xEDE3363, 0xFEC54E8, 0x92FFEE9, 0x3C55F79, 0x13C1C06, 0xC0123FA, 0xA12F2EA,
+ 0xE559B2A, 0x8,
+];
+pub const MCONST: Chunk = 0x537E5E5;
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 3;
+pub const CURVE_B: [Chunk; NLEN] = [0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x10B500D, 0x2D536CD, 0x9921AF6, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+
+pub const FRA: [Chunk; NLEN] = [
+ 0xF943106, 0x760328A, 0xAB28F74, 0x71511E3, 0x7CF39A1, 0x8DDB086, 0x52D1A6E, 0xCA786F3,
+ 0xD617662, 0x3,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xF3EFF0D, 0xB32AB2F, 0xD57F35E, 0xF4A9F45, 0xCCFD33A, 0xD113693, 0x819CB83, 0x3584819,
+ 0x29E899D, 0xC,
+];
+pub const CURVE_BNX: [Chunk; NLEN] = [0xB0A801, 0x82F5C03, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x3A1B807, 0x1C0A24A, 0x32D1EDB, 0xD79DF19, 0x8659BCD, 0x4092101, 0x13988E1, 0x0, 0x0, 0x0,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x9C09EFB, 0x2616B68, 0xF843CD2, 0x539A12B, 0x13ACE1C, 0x577C289, 0x28560F, 0xB4C96C2,
+ 0xE0C3350, 0xF,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x37E6A2B, 0x69ED34A, 0x3589D2, 0x78E287D, 0x3B924DD, 0xC637D81, 0x4DB5AE1, 0x738AC05,
+ 0xEA66057, 0x4,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0xEDC27FF, 0x9B481B, 0x15848E9, 0x24758D6, 0xE51EFCB, 0x75124E3, 0x376770D, 0xC542A3B,
+ 0x2046E7, 0x7,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0xAAD049B, 0x1281114, 0xA98B3E0, 0xBE80821, 0x29F8B4C, 0x49297EB, 0x42EEA6, 0xD388C29,
+ 0x554E3BC, 0x0,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0xB054003, 0xF0036E1, 0xE78663A, 0xFFFFFFF, 0xFFFF, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0xC669004, 0xF5EEEE7, 0xE78670B, 0xFFFFFFF, 0xFFFF, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0x606100A, 0x3D4FFEB, 0xB19B4BB, 0x65FB129, 0x49D0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0xD30A800, 0x20678F0, 0x4D2CC10, 0x5555555, 0x5555, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xD7DC805, 0xD6764C0, 0xBC3AD1A, 0x8FBEA10, 0x4467DE, 0x8061601, 0xD105EB, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xF173803, 0xACB6061, 0x5E1D6C1, 0x47DF508, 0x82233EF, 0xC030B00, 0x6882F5, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xE91F801, 0x26530F6, 0x4D2CCE1, 0x5555555, 0x5555, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x5AA80D, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ [
+ 0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ [
+ 0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ [0x1615002, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ [
+ 0x5AA80D, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ [
+ 0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ ],
+ [
+ [0x1615002, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0xB0A802, 0x82F5C03, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ [
+ 0x2C2A002, 0xBD700C, 0x1A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0xFAA000A, 0x2767EC6, 0x9921A25, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C,
+ 0xFFFFFFF, 0xF,
+ ],
+ [0xB0A802, 0x82F5C03, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 66;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_fp256bn_64.rs b/src/roms/rom_fp256bn_64.rs
new file mode 100644
index 0000000..bde7639
--- /dev/null
+++ b/src/roms/rom_fp256bn_64.rs
@@ -0,0 +1,233 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use fp256bn::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// fp256bn Modulus
+// Base Bits= 56
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x292DDBAED33013,
+ 0x65FB12980A82D3,
+ 0x5EEE71A49F0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xEDE336303B9F8B,
+ 0x92FFEE9FEC54E8,
+ 0x13C1C063C55F79,
+ 0xA12F2EAC0123FA,
+ 0x8E559B2A,
+];
+pub const MCONST: Chunk = 0x6C964E0537E5E5;
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 3;
+pub const CURVE_B: [Chunk; NLEN] = [0x3, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x2D536CD10B500D,
+ 0x65FB1299921AF6,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0];
+
+pub const FRA: [Chunk; NLEN] = [
+ 0x760328AF943106,
+ 0x71511E3AB28F74,
+ 0x8DDB0867CF39A1,
+ 0xCA786F352D1A6E,
+ 0x3D617662,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xB32AB2FF3EFF0D,
+ 0xF4A9F45D57F35E,
+ 0xD113693CCFD33A,
+ 0x3584819819CB83,
+ 0xC29E899D,
+];
+pub const CURVE_BNX: [Chunk; NLEN] = [0x82F5C030B0A801, 0x68, 0x0, 0x0, 0x0];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x1C0A24A3A1B807,
+ 0xD79DF1932D1EDB,
+ 0x40921018659BCD,
+ 0x13988E1,
+ 0x0,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0x2616B689C09EFB,
+ 0x539A12BF843CD2,
+ 0x577C28913ACE1C,
+ 0xB4C96C2028560F,
+ 0xFE0C3350,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x69ED34A37E6A2B,
+ 0x78E287D03589D2,
+ 0xC637D813B924DD,
+ 0x738AC054DB5AE1,
+ 0x4EA66057,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x9B481BEDC27FF,
+ 0x24758D615848E9,
+ 0x75124E3E51EFCB,
+ 0xC542A3B376770D,
+ 0x702046E7,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x1281114AAD049B,
+ 0xBE80821A98B3E0,
+ 0x49297EB29F8B4C,
+ 0xD388C29042EEA6,
+ 0x554E3BC,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [0xF0036E1B054003, 0xFFFFFFFE78663A, 0xFFFF, 0x0, 0x0],
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [0xF5EEEE7C669004, 0xFFFFFFFE78670B, 0xFFFF, 0x0, 0x0],
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+ [
+ 0x3D4FFEB606100A,
+ 0x65FB129B19B4BB,
+ 0x5EEE71A49D0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [0x20678F0D30A800, 0x55555554D2CC10, 0x5555, 0x0, 0x0],
+ [
+ 0xD6764C0D7DC805,
+ 0x8FBEA10BC3AD1A,
+ 0x806160104467DE,
+ 0xD105EB,
+ 0x0,
+ ],
+ [
+ 0xACB6061F173803,
+ 0x47DF5085E1D6C1,
+ 0xC030B0082233EF,
+ 0x6882F5,
+ 0x0,
+ ],
+ [0x26530F6E91F801, 0x55555554D2CCE1, 0x5555, 0x0, 0x0],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0xAA5DACA05AA80D,
+ 0x65FB1299921A8D,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0xAA5DACA05AA80C,
+ 0x65FB1299921A8D,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0xAA5DACA05AA80C,
+ 0x65FB1299921A8D,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ [0x5EB8061615002, 0xD1, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+ [
+ 0xAA5DACA05AA80C,
+ 0x65FB1299921A8D,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0xAA5DACA05AA80D,
+ 0x65FB1299921A8D,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0xAA5DACA05AA80C,
+ 0x65FB1299921A8D,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ ],
+ [
+ [0x5EB8061615002, 0xD1, 0x0, 0x0, 0x0],
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+ [0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0],
+ ],
+ [
+ [0x82F5C030B0A802, 0x68, 0x0, 0x0, 0x0],
+ [0xBD700C2C2A002, 0x1A2, 0x0, 0x0, 0x0],
+ [
+ 0x2767EC6FAA000A,
+ 0x65FB1299921A25,
+ 0x5EEE71A49E0CDC,
+ 0xFFFCF0CD46E5F2,
+ 0xFFFFFFFF,
+ ],
+ [0x82F5C030B0A802, 0x68, 0x0, 0x0, 0x0],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 66;
+pub const SIGN_OF_X: SignOfX = SignOfX::NEGATIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_fp512bn_32.rs b/src/roms/rom_fp512bn_32.rs
new file mode 100644
index 0000000..cdc44af
--- /dev/null
+++ b/src/roms/rom_fp512bn_32.rs
@@ -0,0 +1,249 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use fp512bn::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x2ADEF33, 0x7594049, 0x131919ED, 0x14AB9CBE, 0x16FE1916, 0x12EF5591, 0x2E39231, 0x3D597D3,
+ 0x55146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xFD68B47, 0xFCF5D2C, 0x437675A, 0x1BBC3FBF, 0x1411E413, 0x13453559, 0x10B5639, 0x1C34CE79,
+ 0x6D476BF, 0xFD05F2B, 0x15D17C28, 0x6C9F76E, 0x1C2375B3, 0x78CCE9B, 0x15F0AB33, 0x1960F32E,
+ 0x1A8D44E, 0x57A38,
+];
+pub const MCONST: Chunk = 0x1CCC5C05;
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 3;
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x119A09ED, 0x153252FA, 0x1E68AD01, 0x627C09, 0x79A34A1, 0x12EF5593, 0x2E39231, 0x3D597D3,
+ 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+
+pub const FRA: [Chunk; NLEN] = [
+ 0x14B73AB2, 0x4B0BD8F, 0xABB47D, 0x2A29EC4, 0x18681E17, 0x104069DE, 0x12EED67D, 0x1553D0A5,
+ 0x398E9F8, 0x7971034, 0xAC9AF23, 0x52DEF23, 0x14EA18A5, 0x1463E345, 0x6DE465A, 0x17F212B4,
+ 0x1AA9CF5B, 0xF7B8,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0xDF6B481, 0x2A882B9, 0x126D6570, 0x1208FDFA, 0x1E95FAFF, 0x2AEEBB2, 0xFF4BBB4, 0xE81C72D,
+ 0x1B85CD6, 0xF67746, 0x56549CD, 0xC68B6EC, 0x776A178, 0x8925C3B, 0x1921B9A5, 0x80DED4B,
+ 0x55630A4, 0x70847,
+];
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0x1E1BD80F, 0x59835DA, 0xC3DFC04, 0x5EB8061, 0x688, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0x1C79298A, 0x1838B104, 0x2C5F052, 0x1DCCF337, 0x6092AEC, 0x4B35F29, 0x1EB361E, 0x11384EA,
+ 0x3074B20, 0x17BB08FD, 0x3A8B3E3, 0xD70D66F, 0x3D2A614, 0x1CF63EE4, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0xDB646B5, 0x183D4B70, 0x1CBFFA3, 0x11F0E632, 0x1C78F221, 0x1F10DE5D, 0x171B715E, 0xF0C6A29,
+ 0x10B02453, 0xBE63C66, 0xE6D5F69, 0x166B1E1B, 0x4BBBD29, 0x179E750F, 0x6E9D04, 0xC912B10,
+ 0x1339E138, 0x1D8B2,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0x1A8AE0E9, 0xDAE5F7E, 0x22446CF, 0x1948239B, 0x15ADCE40, 0xB709C1E, 0x18357943, 0xE50AA4D,
+ 0x19781E22, 0x12B35CA6, 0x11DAA2C0, 0x18D8DDE4, 0x5EA656D, 0x15F45A41, 0xD311A02, 0xCFCD913,
+ 0x13CBF850, 0x240E0,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0xDDE67A1, 0x12401895, 0x17BEE178, 0x142F5AC2, 0xB7BC5CD, 0x92A1404, 0x1A3B748C, 0x17BD82A7,
+ 0x14B6CD18, 0xAC34CE, 0x1740FB97, 0x1ECC15F9, 0x17085B1D, 0x1D1BA793, 0x1BD6AC32, 0x18F70525,
+ 0xC84C827, 0x3780F,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x84F8E8B, 0xC5B8C36, 0xFDD85A1, 0xB84449, 0x19C08DFF, 0x56BF713, 0x1C5290C4, 0x187C5CA0,
+ 0x1DA2897F, 0x24B0CA0, 0x326D8F4, 0x2310CF6, 0x1021438C, 0xFBAEC8F, 0xD9030C5, 0x1CF06358,
+ 0x1CEC8B04, 0x28D1D,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x9834583, 0x887C4BA, 0x5A85CFC, 0xBF7223A, 0xF63FE96, 0x1FFFFFFE, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0xFFFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1C37B01F, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0xD4B9564, 0x1D575904, 0xD2C64F3, 0x202177, 0xF63F186, 0x1FFFFFFE, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0xFFFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x156259CE, 0xA01E744, 0x5ECB4F9, 0x148B7B47, 0x79A2790, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ ],
+ [
+ [
+ 0x1C37B01F, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x9834583, 0x887C4BA, 0x5A85CFC, 0xBF7223A, 0xF63FE96, 0x1FFFFFFE, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0xFFFFFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x155A29F0, 0x16D59B55, 0xF4C305, 0x18858C0B, 0x5215FBF, 0xAAAAAAA, 0x15555555, 0xAAAAAAA,
+ 0x555555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x2355D4B, 0x1758095D, 0x1FE13C5F, 0x41F83FA, 0xBB5E5CF, 0x97D4EF1, 0xB503D62, 0x172C0C9B,
+ 0x16315274, 0x15E1A9A8, 0x859835D, 0x2C3DFC0, 0x105EB806, 0x68, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x289AAD, 0x1E781F9C, 0x60F9C31, 0x1505822E, 0x15DAF62B, 0x4BEA778, 0x15A81EB1, 0xB96064D,
+ 0xB18A93A, 0x1AF0D4D4, 0x42CC1AE, 0x161EFE0, 0x82F5C03, 0x34, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x192279D1, 0xBA52F9F, 0x878CAFD, 0xCAE8B48, 0x52152AF, 0xAAAAAAA, 0x15555555, 0xAAAAAAA,
+ 0x555555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0x1E1BD810, 0x59835DA, 0xC3DFC04, 0x5EB8061, 0x688, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1E1BD80F, 0x59835DA, 0xC3DFC04, 0x5EB8061, 0x688, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1E1BD80F, 0x59835DA, 0xC3DFC04, 0x5EB8061, 0x688, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x156259CF, 0xA01E744, 0x5ECB4F9, 0x148B7B47, 0x79A2790, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ ],
+ [
+ [
+ 0x1C37B01F, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x137E31DE, 0xF9A1D1F, 0x122AB0FD, 0x1A76FBA8, 0x79A2E18, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ [
+ 0x137E31DD, 0xF9A1D1F, 0x122AB0FD, 0x1A76FBA8, 0x79A2E18, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ [
+ 0x137E31DE, 0xF9A1D1F, 0x122AB0FD, 0x1A76FBA8, 0x79A2E18, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ ],
+ [
+ [
+ 0x1C37B01E, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1C37B01F, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1C37B01F, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x1C37B01F, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ ],
+ [
+ [
+ 0x137E31DF, 0xF9A1D1F, 0x122AB0FD, 0x1A76FBA8, 0x79A2E18, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ [
+ 0x192AA9AF, 0x1ED17B8E, 0xD70BCF0, 0x8B47A84, 0x79A1A80, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ [
+ 0x1C37B01D, 0xB306BB5, 0x187BF808, 0xBD700C2, 0xD10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ],
+ [
+ 0x137E31DF, 0xF9A1D1F, 0x122AB0FD, 0x1A76FBA8, 0x79A2E18, 0x12EF5593, 0x2E39231,
+ 0x3D597D3, 0x45146CF, 0x88D877A, 0x102EF8F0, 0x1196A60F, 0x1C60BA1D, 0x1CF63F80,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FFFF,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 512;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 10;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 130;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_fp512bn_64.rs b/src/roms/rom_fp512bn_64.rs
new file mode 100644
index 0000000..54d85c4
--- /dev/null
+++ b/src/roms/rom_fp512bn_64.rs
@@ -0,0 +1,482 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use fp512bn::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x4EB280922ADEF33,
+ 0x6A55CE5F4C6467B,
+ 0xC65DEAB236FE191,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF455146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x1FA6DCEF99812E9,
+ 0xAB3452895A0B74E,
+ 0xC53EA988C079E1E,
+ 0x1E90E033BA630B9,
+ 0xF1EA41C0714D8B0,
+ 0xE72785387509E28,
+ 0xD86794F834DAB00,
+ 0x9757C2ACCD342A1,
+ 0x44ECB079,
+];
+pub const MCONST: Chunk = 0x692A189FCCC5C05;
+
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = 0;
+pub const CURVE_B_I: isize = 3;
+pub const CURVE_B: [Chunk; NLEN] = [0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x6A64A5F519A09ED,
+ 0x10313E04F9A2B40,
+ 0xC65DEAB2679A34A,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+
+pub const FRA: [Chunk; NLEN] = [
+ 0x49617B1F4B73AB2,
+ 0x71514F6202AED1F,
+ 0xF6080D3BD8681E1,
+ 0xF8AA9E852CBBB59,
+ 0xC8CF2E2068398E9,
+ 0x8A5296F791AB26B,
+ 0x196A8C7C68B4EA1,
+ 0xCF5BBF9095A1B79,
+ 0x1EF71AA9,
+];
+pub const FRB: [Chunk; NLEN] = [
+ 0x5510572DF6B481,
+ 0xF9047EFD49B595C,
+ 0xD055DD765E95FAF,
+ 0xD6740E396BFD2EE,
+ 0x7341ECEE8C1B85C,
+ 0x1786345B7615952,
+ 0xE695124B876776A,
+ 0x30A4406F6A5E486,
+ 0xE108E556,
+];
+pub const CURVE_BNX: [Chunk; NLEN] = [
+ 0xB306BB5E1BD80F,
+ 0x82F5C030B0F7F01,
+ 0x68,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+];
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_CRU: [Chunk; NLEN] = [
+ 0xB0716209C79298A,
+ 0xCEE6799B8B17C14,
+ 0x78966BE526092AE,
+ 0x20089C27507ACD8,
+ 0xF8EF7611FA3074B,
+ 0x6146B86B378EA2C,
+ 0xFFFF9EC7DC83D2A,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_PXA: [Chunk; NLEN] = [
+ 0xF07A96E0DB646B5,
+ 0x18F87319072FFE8,
+ 0x7BE21BCBBC78F22,
+ 0x537863514DC6DC5,
+ 0xDA57CC78CD0B024,
+ 0xD29B358F0DB9B57,
+ 0x7412F3CEA1E4BBB,
+ 0xE138648958801BA,
+ 0x3B165339,
+];
+pub const CURVE_PXB: [Chunk; NLEN] = [
+ 0xDB5CBEFDA8AE0E9,
+ 0xCA411CD88911B3,
+ 0xD6E1383D5ADCE4,
+ 0x227285526E0D5E5,
+ 0xB02566B94D9781E,
+ 0x56DC6C6EF2476A8,
+ 0x680ABE8B4825EA6,
+ 0xF85067E6C89B4C4,
+ 0x481C13CB,
+];
+pub const CURVE_PYA: [Chunk; NLEN] = [
+ 0x2480312ADDE67A1,
+ 0xDA17AD615EFB85E,
+ 0x312542808B7BC5C,
+ 0x18BDEC153E8EDD2,
+ 0xE5C158699D4B6CD,
+ 0xB1DF660AFCDD03E,
+ 0xB0CBA374F277085,
+ 0xC827C7B8292EF5A,
+ 0x6F01EC84,
+];
+pub const CURVE_PYB: [Chunk; NLEN] = [
+ 0x58B7186C84F8E8B,
+ 0xF05C2224BF76168,
+ 0x10AD7EE279C08DF,
+ 0x7FC3E2E50714A43,
+ 0x3D04961941DA289,
+ 0x38C118867B0C9B6,
+ 0xC315F75D91F0214,
+ 0x8B04E7831AC3640,
+ 0x51A3BCEC,
+];
+pub const CURVE_W: [[Chunk; NLEN]; 2] = [
+ [
+ 0x110F89749834583,
+ 0x65FB911D16A173F,
+ 0xFFFFFFFFCF63FE9,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFF,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x1660D76BC37B01F,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+];
+pub const CURVE_SB: [[[Chunk; NLEN]; 2]; 2] = [
+ [
+ [
+ 0xFAAEB208D4B9564,
+ 0x601010BBB4B193C,
+ 0xFFFFFFFFCF63F18,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFF,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x5403CE8956259CE,
+ 0xA45BDA397B2D3E,
+ 0xC65DEAB2679A279,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ ],
+ [
+ [
+ 0x1660D76BC37B01F,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x110F89749834583,
+ 0x65FB911D16A173F,
+ 0xFFFFFFFFCF63FE9,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFF,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ ],
+];
+pub const CURVE_WB: [[Chunk; NLEN]; 4] = [
+ [
+ 0x6DAB36AB55A29F0,
+ 0xFC42C60583D30C1,
+ 0x5555555545215FB,
+ 0x555555555555555,
+ 0x5555,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0xEEB012BA2355D4B,
+ 0xF20FC1FD7F84F17,
+ 0x892FA9DE2BB5E5C,
+ 0x74B96064DAD40F5,
+ 0xD76BC3535163152,
+ 0x806161EFE021660,
+ 0xD105EB,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x7CF03F380289AAD,
+ 0xBA82C117183E70C,
+ 0xC497D4EF15DAF62,
+ 0x3A5CB0326D6A07A,
+ 0x6BB5E1A9A8B18A9,
+ 0xC030B0F7F010B30,
+ 0x6882F5,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x574A5F3F92279D1,
+ 0xF65745A421E32BF,
+ 0x55555555452152A,
+ 0x555555555555555,
+ 0x5555,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+];
+pub const CURVE_BB: [[[Chunk; NLEN]; 4]; 4] = [
+ [
+ [
+ 0xB306BB5E1BD810,
+ 0x82F5C030B0F7F01,
+ 0x68,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0xB306BB5E1BD80F,
+ 0x82F5C030B0F7F01,
+ 0x68,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0xB306BB5E1BD80F,
+ 0x82F5C030B0F7F01,
+ 0x68,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x5403CE8956259CF,
+ 0xA45BDA397B2D3E,
+ 0xC65DEAB2679A279,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ ],
+ [
+ [
+ 0x1660D76BC37B01F,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x5F343A3F37E31DE,
+ 0x8D3B7DD448AAC3F,
+ 0xC65DEAB2679A2E1,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0x5F343A3F37E31DD,
+ 0x8D3B7DD448AAC3F,
+ 0xC65DEAB2679A2E1,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0x5F343A3F37E31DE,
+ 0x8D3B7DD448AAC3F,
+ 0xC65DEAB2679A2E1,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ ],
+ [
+ [
+ 0x1660D76BC37B01E,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x1660D76BC37B01F,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x1660D76BC37B01F,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x1660D76BC37B01F,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ ],
+ [
+ [
+ 0x5F343A3F37E31DF,
+ 0x8D3B7DD448AAC3F,
+ 0xC65DEAB2679A2E1,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0x3DA2F71D92AA9AF,
+ 0x45A3D4235C2F3C,
+ 0xC65DEAB2679A1A8,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ [
+ 0x1660D76BC37B01D,
+ 0x5EB806161EFE02,
+ 0xD1,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ ],
+ [
+ 0x5F343A3F37E31DF,
+ 0x8D3B7DD448AAC3F,
+ 0xC65DEAB2679A2E1,
+ 0xCF1EACBE98B8E48,
+ 0x3C111B0EF445146,
+ 0xA1D8CB5307C0BBE,
+ 0xFFFF9EC7F01C60B,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+ ],
+ ],
+];
+
+pub const USE_GLV: bool = true;
+pub const USE_GS_G2: bool = true;
+pub const USE_GS_GT: bool = true;
+pub const GT_STRONG: bool = false;
+
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 512;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 28;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::BN;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::M_TYPE;
+pub const ATE_BITS: usize = 130;
+pub const SIGN_OF_X: SignOfX = SignOfX::POSITIVEX;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_goldilocks_32.rs b/src/roms/rom_goldilocks_32.rs
new file mode 100644
index 0000000..5d5f8bb
--- /dev/null
+++ b/src/roms/rom_goldilocks_32.rs
@@ -0,0 +1,73 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use goldilocks::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// Goldilocks modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FDFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x1;
+
+// Goldilocks curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -39081;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x1FFF6756, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FDFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xB5844F3, 0x1BC61495, 0x1163D548, 0x1984E51B, 0x3690216, 0xDA4D76B, 0xFA7113B, 0x1FEF9944,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7FF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x15555555, 0xAAAAAAA, 0x15555555, 0xAAAAAAA, 0x15555555, 0xAAAAAAA, 0x15555555, 0x152AAAAA,
+ 0xAAAAAAA, 0x15555555, 0xAAAAAAA, 0x15555555, 0xAAAAAAA, 0x15555555, 0xAAAAAAA, 0x1555,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xA9386ED, 0x1757DE6F, 0x13681AF6, 0x19657DA3, 0x3098BBB, 0x12C19D15, 0x12E03595, 0xE515B18,
+ 0x17B7E36D, 0x1AC426E, 0xDBB5E8, 0x10D8560, 0x159D6205, 0xB8246D9, 0x17A58D2B, 0x15C0,
+];
+
+pub const MODBYTES: usize = 56;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 448;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::GENERALISED_MERSENNE;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_goldilocks_64.rs b/src/roms/rom_goldilocks_64.rs
new file mode 100644
index 0000000..d6cadf1
--- /dev/null
+++ b/src/roms/rom_goldilocks_64.rs
@@ -0,0 +1,99 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use goldilocks::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 58
+// Goldilocks modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FBFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x200000000, 0x0, 0x0, 0x0, 0x3000000, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x1;
+
+// Goldilocks curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -39081;
+pub const CURVE_COF: [Chunk; NLEN] = [0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x3FFFFFFFFFF6756,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FBFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x378C292AB5844F3,
+ 0x3309CA37163D548,
+ 0x1B49AED63690216,
+ 0x3FDF3288FA7113B,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0xFFFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x155555555555555,
+ 0x155555555555555,
+ 0x155555555555555,
+ 0x2A5555555555555,
+ 0x2AAAAAAAAAAAAAA,
+ 0x2AAAAAAAAAAAAAA,
+ 0x2AAAAAAAAAAAAAA,
+ 0x2AAAAAAAAAA,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x2EAFBCDEA9386ED,
+ 0x32CAFB473681AF6,
+ 0x25833A2A3098BBB,
+ 0x1CA2B6312E03595,
+ 0x35884DD7B7E36D,
+ 0x21B0AC00DBB5E8,
+ 0x17048DB359D6205,
+ 0x2B817A58D2B,
+];
+
+pub const MODBYTES: usize = 56;
+pub const BASEBITS: usize = 58;
+
+pub const MODBITS: usize = 448;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::GENERALISED_MERSENNE;
+pub const SH: usize = 16;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_hifive_32.rs b/src/roms/rom_hifive_32.rs
new file mode 100644
index 0000000..cfa9f59
--- /dev/null
+++ b/src/roms/rom_hifive_32.rs
@@ -0,0 +1,68 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use hifive::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+
+// hifive Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFFFD, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x9000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x3;
+
+// hifive Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = 11111;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x2B67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1E9FA805, 0x197CACB9, 0x1E4EEA9E, 0x17AD70F, 0x1FA9850C, 0x38A0A, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x4000,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0xC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x5FE8632, 0x15F63428, 0xD976C4, 0x1AACA194, 0x35B6DB5, 0x8E3F7A, 0x52D1B0E, 0xF0A7A36,
+ 0x1C161D00, 0x8170C70, 0x1185AD59, 0x181B,
+];
+
+pub const MODBYTES: usize = 42;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 336;
+pub const MOD8: usize = 5;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 12;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
diff --git a/src/roms/rom_hifive_64.rs b/src/roms/rom_hifive_64.rs
new file mode 100644
index 0000000..b2eebb9
--- /dev/null
+++ b/src/roms/rom_hifive_64.rs
@@ -0,0 +1,77 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use hifive::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+
+// Base Bits= 60
+// hifive Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFFFD,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x9000000000000, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x3;
+
+// hifive Curve
+pub const CURVE_COF_I: isize = 8;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = 11111;
+pub const CURVE_COF: [Chunk; NLEN] = [0x8, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0x2B67, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xB2F95973E9FA805,
+ 0xC0BD6B87F93BAA7,
+ 0x71415FA9850,
+ 0x0,
+ 0x0,
+ 0x200000000,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [0xC, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x2BEC68505FE8632,
+ 0x5D5650CA0365DB1,
+ 0x3811C7EF435B6DB,
+ 0x7853D1B14B46C,
+ 0x56502E18E1C161D,
+ 0xC0DC616B,
+];
+
+pub const MODBYTES: usize = 42;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 336;
+pub const MOD8: usize = 5;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
diff --git a/src/roms/rom_nist256_32.rs b/src/roms/rom_nist256_32.rs
new file mode 100644
index 0000000..6859da5
--- /dev/null
+++ b/src/roms/rom_nist256_32.rs
@@ -0,0 +1,74 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Fixed Data in ROM - Field and Curve parameters */
+
+use nist256::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+
+// Base Bits= 28
+// nist256 modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFF, 0x0, 0x0, 0x1000000, 0x0, 0xFFFFFFF, 0xF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x50000, 0x300000, 0x0, 0x0, 0xFFFFFFA, 0xFFFFFBF, 0xFFFFEFF, 0xFFFAFFF, 0x2FFFF, 0x0,
+];
+pub const MCONST: Chunk = 0x1;
+
+// nist256 curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x7D2604B, 0xCE3C3E2, 0x3B0F63B, 0x6B0CC5, 0x6BC651D, 0x5576988, 0x7B3EBBD, 0xAA3A93E,
+ 0xAC635D8, 0x5,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xC632551, 0xB9CAC2F, 0x79E84F3, 0xFAADA71, 0xFFFBCE6, 0xFFFFFFF, 0xFFFFFF, 0x0, 0xFFFFFFF,
+ 0xF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x898C296, 0xA13945D, 0xB33A0F4, 0x7D812DE, 0xF27703, 0xE563A44, 0x7F8BCE6, 0xE12C424,
+ 0xB17D1F2, 0x6,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x7BF51F5, 0xB640683, 0x15ECECB, 0x33576B3, 0xE162BCE, 0x4A7C0F9, 0xB8EE7EB, 0xFE1A7F9,
+ 0xFE342E2, 0x4,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_nist256_64.rs b/src/roms/rom_nist256_64.rs
new file mode 100644
index 0000000..015bbb3
--- /dev/null
+++ b/src/roms/rom_nist256_64.rs
@@ -0,0 +1,86 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Fixed Data in ROM - Field and Curve parameters */
+
+use nist256::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// nist256 modulus
+pub const MODULUS: [Chunk; NLEN] = [0xFFFFFFFFFFFFFF, 0xFFFFFFFFFF, 0x0, 0x1000000, 0xFFFFFFFF];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x3000000050000,
+ 0x0,
+ 0xFFFFFBFFFFFFFA,
+ 0xFFFAFFFFFFFEFF,
+ 0x2FFFF,
+];
+pub const MCONST: Chunk = 0x1;
+
+// nist256 curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xCE3C3E27D2604B,
+ 0x6B0CC53B0F63B,
+ 0x55769886BC651D,
+ 0xAA3A93E7B3EBBD,
+ 0x5AC635D8,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xB9CAC2FC632551,
+ 0xFAADA7179E84F3,
+ 0xFFFFFFFFFFBCE6,
+ 0xFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xA13945D898C296,
+ 0x7D812DEB33A0F4,
+ 0xE563A440F27703,
+ 0xE12C4247F8BCE6,
+ 0x6B17D1F2,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xB6406837BF51F5,
+ 0x33576B315ECECB,
+ 0x4A7C0F9E162BCE,
+ 0xFE1A7F9B8EE7EB,
+ 0x4FE342E2,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_nist384_32.rs b/src/roms/rom_nist384_32.rs
new file mode 100644
index 0000000..48d7826
--- /dev/null
+++ b/src/roms/rom_nist384_32.rs
@@ -0,0 +1,76 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nist384::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+
+// Base Bits= 29
+// nist384 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFFFF, 0x7, 0x0, 0x1FFFFE00, 0x1FFFEFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x0, 0x8000, 0x1FF80000, 0x1FFFFF, 0x2000000, 0x0, 0x0, 0x1FFFFFFC, 0xF, 0x100, 0x400, 0x0,
+ 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x1;
+
+// nist384 Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x13EC2AEF, 0x142E476E, 0xBB4674A, 0xC731B14, 0x1875AC65, 0x447A809, 0x4480C50, 0xDDFD028,
+ 0x19181D9C, 0x1F1FC168, 0x623815A, 0x47DCFC9, 0x1312FA7E, 0x59,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xCC52973, 0x760CB56, 0xC29DEBB, 0x141B6491, 0x12DDF581, 0x6C0FA1B, 0x1FFF1D8D, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x12760AB7, 0x12A2F1C3, 0x154A5B0E, 0x5E4BB7E, 0x2A38550, 0xF0412A, 0xE6167DD, 0xC5174F3,
+ 0x146E1D3B, 0x1799056B, 0x3AC71C7, 0x1D160A6F, 0x87CA22B, 0x55,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x10EA0E5F, 0x1218EBE4, 0x1FA0675E, 0x1639C3A, 0xB8C00A6, 0x1889DAF8, 0x11F3A768, 0x17A51342,
+ 0x9F8F41D, 0x1C9496E1, 0x1767A62F, 0xC4C58DE, 0x17DE4A9, 0x1B,
+];
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 384;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
diff --git a/src/roms/rom_nist384_64.rs b/src/roms/rom_nist384_64.rs
new file mode 100644
index 0000000..f0f5c69
--- /dev/null
+++ b/src/roms/rom_nist384_64.rs
@@ -0,0 +1,104 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nist384::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+
+// nist384 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFF,
+ 0xFFFF0000000000,
+ 0xFFFFFFFFFEFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xFE000000010000,
+ 0xFFFFFF,
+ 0x2,
+ 0xFFFFFFFE00,
+ 0x1000000020000,
+ 0x0,
+ 0x0,
+];
+pub const MCONST: Chunk = 0x100000001;
+
+
+// nist384 Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x85C8EDD3EC2AEF,
+ 0x398D8A2ED19D2A,
+ 0x8F5013875AC656,
+ 0xFE814112031408,
+ 0xF82D19181D9C6E,
+ 0xE7E4988E056BE3,
+ 0xB3312FA7E23E,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xEC196ACCC52973,
+ 0xDB248B0A77AEC,
+ 0x81F4372DDF581A,
+ 0xFFFFFFFFC7634D,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x545E3872760AB7,
+ 0xF25DBF55296C3A,
+ 0xE082542A385502,
+ 0x8BA79B9859F741,
+ 0x20AD746E1D3B62,
+ 0x5378EB1C71EF3,
+ 0xAA87CA22BE8B,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x431D7C90EA0E5F,
+ 0xB1CE1D7E819D7A,
+ 0x13B5F0B8C00A60,
+ 0x289A147CE9DA31,
+ 0x92DC29F8F41DBD,
+ 0x2C6F5D9E98BF92,
+ 0x3617DE4A9626,
+];
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 384;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 8;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
diff --git a/src/roms/rom_nist521_32.rs b/src/roms/rom_nist521_32.rs
new file mode 100644
index 0000000..55cbf30
--- /dev/null
+++ b/src/roms/rom_nist521_32.rs
@@ -0,0 +1,79 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nist521::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// nist521 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xFFFFFFF, 0x1FFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x400000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0,
+];
+pub const MCONST: Chunk = 0x1;
+
+// nist521 Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xB503F00, 0x451FD46, 0xC34F1EF, 0xDF883D2, 0xF073573, 0xBD3BB1B, 0xB1652C0, 0xEC7E937,
+ 0x6193951, 0xF109E15, 0x489918E, 0x15F3B8B, 0x25B99B3, 0xEEA2DA7, 0xB68540, 0x929A21A,
+ 0xE1C9A1F, 0x3EB9618, 0x5195,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1386409, 0x6FB71E9, 0xC47AEBB, 0xC9B8899, 0x5D03BB5, 0x48F709A, 0xB7FCC01, 0xBF2F966,
+ 0x1868783, 0xFFFFFA5, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xFFFFFFF, 0x1FFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x2E5BD66, 0x7E7E31C, 0xA429BF9, 0xB3C1856, 0x8DE3348, 0x27A2FFA, 0x8FE1DC1, 0xEFE7592,
+ 0x14B5E77, 0x4D3DBAA, 0x8AF606B, 0xB521F82, 0x139053F, 0x429C648, 0x62395B4, 0x9E3ECB6,
+ 0x404E9CD, 0x8E06B70, 0xC685,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xFD16650, 0xBE94769, 0x2C24088, 0x7086A27, 0x761353C, 0x13FAD0, 0xC550B9, 0x5EF4264,
+ 0x7EE7299, 0x3E662C9, 0xFBD1727, 0x446817A, 0x449579B, 0xD998F54, 0x42C7D1B, 0x5C8A5FB,
+ 0xA3BC004, 0x296A789, 0x11839,
+];
+
+pub const MODBYTES: usize = 66;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 521;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 11;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_nist521_64.rs b/src/roms/rom_nist521_64.rs
new file mode 100644
index 0000000..bf241b2
--- /dev/null
+++ b/src/roms/rom_nist521_64.rs
@@ -0,0 +1,104 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nist521::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+// nist521 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0x1FFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x4000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x1;
+
+// nist521 Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 0;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xF451FD46B503F00,
+ 0x73DF883D2C34F1E,
+ 0x2C0BD3BB1BF0735,
+ 0x3951EC7E937B165,
+ 0x9918EF109E15619,
+ 0x5B99B315F3B8B48,
+ 0xB68540EEA2DA72,
+ 0x8E1C9A1F929A21A,
+ 0x51953EB961,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xB6FB71E91386409,
+ 0xB5C9B8899C47AEB,
+ 0xC0148F709A5D03B,
+ 0x8783BF2F966B7FC,
+ 0xFFFFFFFFFFA5186,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0x1FFFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x97E7E31C2E5BD66,
+ 0x48B3C1856A429BF,
+ 0xDC127A2FFA8DE33,
+ 0x5E77EFE75928FE1,
+ 0xF606B4D3DBAA14B,
+ 0x39053FB521F828A,
+ 0x62395B4429C6481,
+ 0x404E9CD9E3ECB6,
+ 0xC6858E06B7,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x8BE94769FD16650,
+ 0x3C7086A272C2408,
+ 0xB9013FAD076135,
+ 0x72995EF42640C55,
+ 0xD17273E662C97EE,
+ 0x49579B446817AFB,
+ 0x42C7D1BD998F544,
+ 0x9A3BC0045C8A5FB,
+ 0x11839296A78,
+];
+
+pub const MODBYTES: usize = 66;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 521;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 19;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_nums256e_32.rs b/src/roms/rom_nums256e_32.rs
new file mode 100644
index 0000000..45506bd
--- /dev/null
+++ b/src/roms/rom_nums256e_32.rs
@@ -0,0 +1,71 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums256e::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+
+// Base Bits= 29
+// nums256 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFF43, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0xFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x22E2400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0xBD;
+
+// nums256e Curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -15342;
+pub const CURVE_COF: [Chunk; NLEN] = [0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x1FFFC355, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0xFFFFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xEDD4AF5, 0x123D8C87, 0x1650E6C6, 0xAB54A5E, 0x419, 0x0, 0x0, 0x0, 0x400000,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xEED13DA, 0x6F60481, 0x20D61A8, 0x13141DC6, 0x9BD60C3, 0x1EAFB490, 0xDF73478, 0x1F6D5D44,
+ 0x8A7514,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x198A89E6, 0x1D30B73B, 0x15BB4CB, 0x1EC3B021, 0x18010715, 0x12ECD325, 0x171F3A59, 0x13FB3B24,
+ 0x44D53E,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 5;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
+
diff --git a/src/roms/rom_nums256e_64.rs b/src/roms/rom_nums256e_64.rs
new file mode 100644
index 0000000..4382924
--- /dev/null
+++ b/src/roms/rom_nums256e_64.rs
@@ -0,0 +1,80 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums256e::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// nums256 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFF43,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x89000000000000, 0x8B, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0xBD;
+
+// nums256e Curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -15342;
+pub const CURVE_COF: [Chunk; NLEN] = [0x4, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFC355,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] =
+ [0x47B190EEDD4AF5, 0x5AA52F59439B1A, 0x4195, 0x0, 0x40000000];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xDEC0902EED13DA,
+ 0x8A0EE3083586A0,
+ 0x5F69209BD60C39,
+ 0x6AEA237DCD1E3D,
+ 0x8A7514FB,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xA616E7798A89E6,
+ 0x61D810856ED32F,
+ 0xD9A64B8010715F,
+ 0xD9D925C7CE9665,
+ 0x44D53E9F,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
+
diff --git a/src/roms/rom_nums256w_32.rs b/src/roms/rom_nums256w_32.rs
new file mode 100644
index 0000000..b768380
--- /dev/null
+++ b/src/roms/rom_nums256w_32.rs
@@ -0,0 +1,66 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums256w::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// nums256 modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFF43, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x0, 0x8900000, 0x8B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0xBD;
+
+// nums256w curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 152961;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0x25581, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x751A825, 0xAB20294, 0x65C6020, 0x8275EA2, 0xFFFE43C, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x21AACB1, 0x52EE1EB, 0x4C73ABC, 0x9B0903D, 0xB098357, 0xA04F42C, 0x1297A95, 0x5AAADB6,
+ 0xC9ED6B6, 0xB,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x184DE9F, 0xB5B9CB2, 0x10FBB80, 0xC3D1153, 0x35C955, 0xF77E04E, 0x673448B, 0x3399B6A,
+ 0x8FC0F1, 0xD,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_nums256w_64.rs b/src/roms/rom_nums256w_64.rs
new file mode 100644
index 0000000..5b5d491
--- /dev/null
+++ b/src/roms/rom_nums256w_64.rs
@@ -0,0 +1,78 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums256w::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// nums256 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFF43,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x89000000000000, 0x8B, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0xBD;
+
+// nums256w Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 152961;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0x25581, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xAB20294751A825,
+ 0x8275EA265C6020,
+ 0xFFFFFFFFFFE43C,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x52EE1EB21AACB1,
+ 0x9B0903D4C73ABC,
+ 0xA04F42CB098357,
+ 0x5AAADB61297A95,
+ 0xBC9ED6B6,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xB5B9CB2184DE9F,
+ 0xC3D115310FBB80,
+ 0xF77E04E035C955,
+ 0x3399B6A673448B,
+ 0xD08FC0F1,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_nums384e_32.rs b/src/roms/rom_nums384e_32.rs
new file mode 100644
index 0000000..eaad1c8
--- /dev/null
+++ b/src/roms/rom_nums384e_32.rs
@@ -0,0 +1,74 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums384e::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// nums384 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFEC3, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x0, 0x4448000, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x13D;
+
+// nums384e Curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -11556;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x1FFFD19F, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x6A3897D, 0x5CEE627, 0xD721E48, 0x8AAB556, 0x1E1CF61E, 0xD0E5A35, 0x1FFF891C, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1F,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xC206BDE, 0x6AA0723, 0x116504D4, 0x52562CA, 0x163406FF, 0x1FD47998, 0x10015D8F, 0x8DCB7C9,
+ 0x15B30BF4, 0x14D72AED, 0x102DA884, 0xB524CD9, 0x1B111FB4, 0x30,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x10729392, 0xC681F0F, 0x1B123727, 0x561F28D, 0x1964B007, 0xC7BFB22, 0x1D5A0C3E, 0xE9E284B,
+ 0x1716AD82, 0x11D886E, 0x1CE2C69, 0x134DDD61, 0x983E67B, 0x41,
+];
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 384;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
+
diff --git a/src/roms/rom_nums384e_64.rs b/src/roms/rom_nums384e_64.rs
new file mode 100644
index 0000000..08d83c2
--- /dev/null
+++ b/src/roms/rom_nums384e_64.rs
@@ -0,0 +1,95 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums384e::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+// nums384 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFEC3,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x188890000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x13D;
+
+// nums384e Curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -11556;
+pub const CURVE_COF: [Chunk; NLEN] = [0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFD19F,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xB9DCC4E6A3897D,
+ 0x555AAB35C87920,
+ 0x1CB46BE1CF61E4,
+ 0xFFFFFFFFE2471A,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xD540E46C206BDE,
+ 0x92B16545941350,
+ 0xA8F33163406FF2,
+ 0xE5BE4C005763FF,
+ 0xE55DB5B30BF446,
+ 0x266CC0B6A2129A,
+ 0x61B111FB45A9,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x8D03E1F0729392,
+ 0xB0F946EC48DC9D,
+ 0xF7F645964B0072,
+ 0xF1425F56830F98,
+ 0xB10DD716AD8274,
+ 0xEEB08738B1A423,
+ 0x82983E67B9A6,
+];
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 384;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 8;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
+
diff --git a/src/roms/rom_nums384w_32.rs b/src/roms/rom_nums384w_32.rs
new file mode 100644
index 0000000..92181a6
--- /dev/null
+++ b/src/roms/rom_nums384w_32.rs
@@ -0,0 +1,74 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums384w::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// nums384 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFEC3, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x0, 0x4448000, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x13D;
+
+// nums384w Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = -34568;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x1FFF77BB, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1B0E61B9, 0x26C0FB3, 0xDF89E98, 0x153A7A98, 0x16881BED, 0x178F75AE, 0x1FFF587A, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x7F,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x98152A, 0x1CE5D021, 0x18711EFA, 0x1DDA201E, 0xC742522, 0x148D9536, 0x7D3CEF4, 0x19BF703F,
+ 0x60225C1, 0x12082F8D, 0x12203288, 0x2DE3038, 0x17956F0B, 0x3A,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x6180716, 0x3A5C763, 0x1D2B4997, 0xD69B77F, 0x837EBCD, 0x1BE890D, 0xE72E482, 0xEFF0FEE,
+ 0x1EB00469, 0x2C267B, 0x15F8CF4C, 0x3371C71, 0xDEE368E, 0x56,
+];
+
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 384;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
+
diff --git a/src/roms/rom_nums384w_64.rs b/src/roms/rom_nums384w_64.rs
new file mode 100644
index 0000000..3f51d94
--- /dev/null
+++ b/src/roms/rom_nums384w_64.rs
@@ -0,0 +1,94 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums384w::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 58
+// nums384 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x3FFFFFFFFFFFEC3,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0xFFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x88900000000000, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x13D;
+
+// nums384w Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = -34568;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x3FFFFFFFFFF77BB,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0xFFFFFFFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x4D81F67B0E61B9,
+ 0x2A74F530DF89E98,
+ 0x2F1EEB5D6881BED,
+ 0x3FFFFFFFFFF587A,
+ 0x3FFFFFFFFFFFFFF,
+ 0x3FFFFFFFFFFFFFF,
+ 0xFFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x39CBA042098152A,
+ 0x3BB4403D8711EFA,
+ 0x291B2A6CC742522,
+ 0x337EE07E7D3CEF4,
+ 0x24105F1A60225C1,
+ 0x5BC60712203288,
+ 0x757956F0B,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x74B8EC66180716,
+ 0x1AD36EFFD2B4997,
+ 0x37D121A837EBCD,
+ 0x1DFE1FDCE72E482,
+ 0x584CF7EB00469,
+ 0x66E38E35F8CF4C,
+ 0xACDEE368E,
+];
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 58;
+
+pub const MODBITS: usize = 384;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 22;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 48;
+pub const AESKEY: usize = 24;
+
diff --git a/src/roms/rom_nums512e_32.rs b/src/roms/rom_nums512e_32.rs
new file mode 100644
index 0000000..8d53f9f
--- /dev/null
+++ b/src/roms/rom_nums512e_32.rs
@@ -0,0 +1,79 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums512e::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// nums512 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFDC7, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xB100000, 0x278, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0,
+];
+pub const MCONST: Chunk = 0x239;
+
+// nums512e Curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -78296;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x1FFECBEF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x1BEED46D, 0x1A3467A8, 0x1BFB3FD9, 0xC0AF0DB, 0x86F52A4, 0xC64B85B, 0x6EA78FF, 0xDA5F9F2,
+ 0x1FB4F063, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x19EC57FE, 0xDCD594C, 0x113C0571, 0xA4A84F9, 0x104AD0FE, 0x4C92B44, 0xC3DE2F7, 0x9DDC8CE,
+ 0x74621C1, 0x1139DC0A, 0x9E85FAF, 0x1B894704, 0x1D1E79F4, 0x9E29997, 0x32DE223, 0x16D38F43,
+ 0x116D128D, 0x6FC71,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x1E2F5E1, 0x136EF606, 0x1C7407CC, 0xDA71537, 0xC1FD026, 0x3431576, 0x15898068, 0x1E5D32C6,
+ 0x120CA53, 0xC84F41A, 0xA4ADAE5, 0x104B3A45, 0x76F726D, 0x1512B772, 0x3D5DEA0, 0x194E3316,
+ 0x1FF39D49, 0x3684D,
+];
+
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 512;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 10;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_nums512e_64.rs b/src/roms/rom_nums512e_64.rs
new file mode 100644
index 0000000..298f3cc
--- /dev/null
+++ b/src/roms/rom_nums512e_64.rs
@@ -0,0 +1,104 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums512e::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+// nums512 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFDC7,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x100000000000000, 0x4F0B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x239;
+
+// nums512e Curve
+pub const CURVE_COF_I: isize = 4;
+pub const CURVE_A: isize = 1;
+pub const CURVE_B_I: isize = -78296;
+pub const CURVE_COF: [Chunk; NLEN] = [0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFECBEF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x7468CF51BEED46D,
+ 0x4605786DEFECFF6,
+ 0xFD8C970B686F52A,
+ 0x636D2FCF91BA9E3,
+ 0xFFFFFFFFFFFB4F0,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0x3FFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x5B9AB2999EC57FE,
+ 0xE525427CC4F015C,
+ 0xDC992568904AD0F,
+ 0xC14EEE46730F78B,
+ 0xEBE273B81474621,
+ 0x9F4DC4A38227A17,
+ 0x888D3C5332FD1E7,
+ 0x128DB69C7A18CB7,
+ 0xDF8E316D,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x26DDEC0C1E2F5E1,
+ 0x66D38A9BF1D01F3,
+ 0xA06862AECC1FD02,
+ 0x53F2E9963562601,
+ 0xB95909E834120CA,
+ 0x26D8259D22A92B6,
+ 0x7A82A256EE476F7,
+ 0x9D49CA7198B0F57,
+ 0x6D09BFF3,
+];
+
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 512;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 28;
+
+pub const CURVETYPE: CurveType = CurveType::EDWARDS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_nums512w_32.rs b/src/roms/rom_nums512w_32.rs
new file mode 100644
index 0000000..785070c
--- /dev/null
+++ b/src/roms/rom_nums512w_32.rs
@@ -0,0 +1,77 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums512w::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 29
+// nums512 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0x1FFFFDC7, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0xB100000, 0x278, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0,
+];
+pub const MCONST: Chunk = 0x239;
+
+// nums512w Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 121243;
+pub const CURVE_COF: [Chunk; NLEN] = [
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_B: [Chunk; NLEN] = [
+ 0x1D99B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x433555D, 0x10A9F9C8, 0x1F3490F3, 0xD166CC0, 0xBDC63B5, 0xC76CBE8, 0xC6D3F09, 0x1F729CF0,
+ 0x1F5B3CA4, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
+ 0x1FFFFFFF, 0x7FFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xCABAE57, 0x4143CAC, 0x1BD778B7, 0x1AC026FA, 0x15831D5, 0x14312AB, 0x167A4DE5, 0xA20ED66,
+ 0x195021A1, 0x129836CF, 0x1141B830, 0xA03ED0A, 0xCAD83BB, 0x1E9DA94C, 0xDC00A80, 0x1527B45,
+ 0x1447141D, 0x1D601,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x183527A6, 0x1D043B01, 0x1F43FA48, 0x16B83C99, 0x5602CF2, 0x1420592D, 0x17A70486, 0x1B5161DD,
+ 0x14A28415, 0x3DE8A78, 0x3D2C983, 0x17797719, 0x197DBDEA, 0x15D88025, 0x1BBB718F, 0xAD679C1,
+ 0x14CA29AD, 0x4A1D2,
+];
+
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 29;
+
+pub const MODBITS: usize = 512;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 10;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_nums512w_64.rs b/src/roms/rom_nums512w_64.rs
new file mode 100644
index 0000000..6868c87
--- /dev/null
+++ b/src/roms/rom_nums512w_64.rs
@@ -0,0 +1,94 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use nums512w::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 60
+// nums512 Modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFFFFFFFFDC7,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0x100000000000000, 0x4F0B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const MCONST: Chunk = 0x239;
+
+// nums512w Curve
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_A: isize = -3;
+pub const CURVE_B_I: isize = 121243;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B: [Chunk; NLEN] = [0x1D99B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xE153F390433555D,
+ 0x568B36607CD243C,
+ 0x258ED97D0BDC63B,
+ 0xA4FB94E7831B4FC,
+ 0xFFFFFFFFFFF5B3C,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xC8287958CABAE57,
+ 0x5D60137D6F5DE2D,
+ 0x94286255615831D,
+ 0xA151076B359E937,
+ 0xC25306D9F95021,
+ 0x3BB501F6854506E,
+ 0x2A03D3B5298CAD8,
+ 0x141D0A93DA2B700,
+ 0x3AC03447,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x3A08760383527A6,
+ 0x2B5C1E4CFD0FE92,
+ 0x1A840B25A5602CF,
+ 0x15DA8B0EEDE9C12,
+ 0x60C7BD14F14A284,
+ 0xDEABBCBB8C8F4B2,
+ 0xC63EBB1004B97DB,
+ 0x29AD56B3CE0EEED,
+ 0x943A54CA,
+];
+
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 60;
+
+pub const MODBITS: usize = 512;
+pub const MOD8: usize = 3;
+pub const MODTYPE: ModType = ModType::PSEUDO_MERSENNE;
+pub const SH: usize = 28;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 64;
+pub const AESKEY: usize = 32;
diff --git a/src/roms/rom_rsa2048_32.rs b/src/roms/rom_rsa2048_32.rs
new file mode 100644
index 0000000..6dd06a6
--- /dev/null
+++ b/src/roms/rom_rsa2048_32.rs
@@ -0,0 +1,3 @@
+pub const MODBYTES: usize = 128;
+pub const BASEBITS: usize = 28;
+pub const FFLEN: usize = 2;
\ No newline at end of file
diff --git a/src/roms/rom_rsa2048_64.rs b/src/roms/rom_rsa2048_64.rs
new file mode 100644
index 0000000..be3ba0d
--- /dev/null
+++ b/src/roms/rom_rsa2048_64.rs
@@ -0,0 +1,3 @@
+pub const MODBYTES: usize = 128;
+pub const BASEBITS: usize = 58;
+pub const FFLEN: usize = 2;
\ No newline at end of file
diff --git a/src/roms/rom_rsa3072_32.rs b/src/roms/rom_rsa3072_32.rs
new file mode 100644
index 0000000..d5622e2
--- /dev/null
+++ b/src/roms/rom_rsa3072_32.rs
@@ -0,0 +1,3 @@
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 28;
+pub const FFLEN: usize = 8;
\ No newline at end of file
diff --git a/src/roms/rom_rsa3072_64.rs b/src/roms/rom_rsa3072_64.rs
new file mode 100644
index 0000000..4d1ed2b
--- /dev/null
+++ b/src/roms/rom_rsa3072_64.rs
@@ -0,0 +1,3 @@
+pub const MODBYTES: usize = 48;
+pub const BASEBITS: usize = 58;
+pub const FFLEN: usize = 8;
\ No newline at end of file
diff --git a/src/roms/rom_rsa4096_32.rs b/src/roms/rom_rsa4096_32.rs
new file mode 100644
index 0000000..223cb7d
--- /dev/null
+++ b/src/roms/rom_rsa4096_32.rs
@@ -0,0 +1,3 @@
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 29;
+pub const FFLEN: usize = 8;
\ No newline at end of file
diff --git a/src/roms/rom_rsa4096_64.rs b/src/roms/rom_rsa4096_64.rs
new file mode 100644
index 0000000..77d3eb6
--- /dev/null
+++ b/src/roms/rom_rsa4096_64.rs
@@ -0,0 +1,3 @@
+pub const MODBYTES: usize = 64;
+pub const BASEBITS: usize = 60;
+pub const FFLEN: usize = 8;
\ No newline at end of file
diff --git a/src/roms/rom_secp256k1_32.rs b/src/roms/rom_secp256k1_32.rs
new file mode 100644
index 0000000..94bbbaa
--- /dev/null
+++ b/src/roms/rom_secp256k1_32.rs
@@ -0,0 +1,70 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Fixed Data in ROM - Field and Curve parameters */
+
+use secp256k1::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 28
+// secp256k1 modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFC2F, 0xFFFFFEF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xF,
+];
+pub const R2MODP: [Chunk; NLEN] = [
+ 0x0, 0xA100000, 0x2000E90, 0x7A, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
+];
+pub const MCONST: Chunk = 0x2253531;
+
+// secp256k1 curve
+pub const CURVE_A: isize = 0;
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B_I: isize = 7;
+pub const CURVE_B: [Chunk; NLEN] = [0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0x364141, 0xD25E8CD, 0x8A03BBF, 0xDCE6AF4, 0xFFEBAAE, 0xFFFFFFF, 0xFFFFFFF, 0xFFFFFFF,
+ 0xFFFFFFF, 0xF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0x6F81798, 0xF2815B1, 0xE28D959, 0xFCDB2DC, 0xB07029B, 0x95CE870, 0xC55A062, 0xF9DCBBA,
+ 0x9BE667E, 0x7,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0xB10D4B8, 0x47D08FF, 0x554199C, 0xB448A68, 0x8A8FD17, 0xFC0E110, 0x55DA4FB, 0x26A3C46,
+ 0x83ADA77, 0x4,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 28;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 14;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/roms/rom_secp256k1_64.rs b/src/roms/rom_secp256k1_64.rs
new file mode 100644
index 0000000..b22d875
--- /dev/null
+++ b/src/roms/rom_secp256k1_64.rs
@@ -0,0 +1,81 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Fixed Data in ROM - Field and Curve parameters */
+
+use secp256k1::big::NLEN;
+use super::super::arch::Chunk;
+use types::{ModType, CurveType, CurvePairingType, SexticTwist, SignOfX};
+
+// Base Bits= 56
+
+// secp256k1 modulus
+pub const MODULUS: [Chunk; NLEN] = [
+ 0xFFFFFEFFFFFC2F,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const R2MODP: [Chunk; NLEN] = [0xA1000000000000, 0x7A2000E90, 0x1, 0x0, 0x0];
+pub const MCONST: Chunk = 0x38091DD2253531;
+
+// secp256k1 curve
+pub const CURVE_A: isize = 0;
+pub const CURVE_COF_I: isize = 1;
+pub const CURVE_COF: [Chunk; NLEN] = [0x1, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_B_I: isize = 7;
+pub const CURVE_B: [Chunk; NLEN] = [0x7, 0x0, 0x0, 0x0, 0x0];
+pub const CURVE_ORDER: [Chunk; NLEN] = [
+ 0xD25E8CD0364141,
+ 0xDCE6AF48A03BBF,
+ 0xFFFFFFFFFEBAAE,
+ 0xFFFFFFFFFFFFFF,
+ 0xFFFFFFFF,
+];
+pub const CURVE_GX: [Chunk; NLEN] = [
+ 0xF2815B16F81798,
+ 0xFCDB2DCE28D959,
+ 0x95CE870B07029B,
+ 0xF9DCBBAC55A062,
+ 0x79BE667E,
+];
+pub const CURVE_GY: [Chunk; NLEN] = [
+ 0x47D08FFB10D4B8,
+ 0xB448A68554199C,
+ 0xFC0E1108A8FD17,
+ 0x26A3C4655DA4FB,
+ 0x483ADA77,
+];
+
+pub const MODBYTES: usize = 32;
+pub const BASEBITS: usize = 56;
+
+pub const MODBITS: usize = 256;
+pub const MOD8: usize = 7;
+pub const MODTYPE: ModType = ModType::NOT_SPECIAL;
+pub const SH: usize = 24;
+
+pub const CURVETYPE: CurveType = CurveType::WEIERSTRASS;
+pub const CURVE_PAIRING_TYPE: CurvePairingType = CurvePairingType::NOT;
+pub const SEXTIC_TWIST: SexticTwist = SexticTwist::NOT;
+pub const ATE_BITS: usize = 0;
+pub const SIGN_OF_X: SignOfX = SignOfX::NOT;
+pub const HASH_TYPE: usize = 32;
+pub const AESKEY: usize = 16;
diff --git a/src/rsa.rs b/src/rsa.rs
new file mode 100644
index 0000000..1a59f7a
--- /dev/null
+++ b/src/rsa.rs
@@ -0,0 +1,469 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+use super::big;
+use super::ff;
+use super::ff::FF;
+
+use crate::hash256::HASH256;
+use crate::hash384::HASH384;
+use crate::hash512::HASH512;
+use crate::rand::RAND;
+
+pub const RFS: usize = (big::MODBYTES as usize) * ff::FFLEN;
+pub const SHA256: usize = 32;
+pub const SHA384: usize = 48;
+pub const SHA512: usize = 64;
+
+pub const HASH_TYPE: usize = SHA256;
+
+pub struct RsaPrivateKey {
+ p: FF,
+ q: FF,
+ dp: FF,
+ dq: FF,
+ c: FF,
+}
+
+pub struct RsaPublicKey {
+ e: isize,
+ n: FF,
+}
+
+pub fn new_private_key(n: usize) -> RsaPrivateKey {
+ RsaPrivateKey {
+ p: FF::new_int(n),
+ q: FF::new_int(n),
+ dp: FF::new_int(n),
+ dq: FF::new_int(n),
+ c: FF::new_int(n),
+ }
+}
+
+pub fn new_public_key(m: usize) -> RsaPublicKey {
+ RsaPublicKey {
+ e: 0,
+ n: FF::new_int(m),
+ }
+}
+
+fn hashit(sha: usize, a: Option<&[u8]>, n: isize, w: &mut [u8]) {
+ if sha == SHA256 {
+ let mut h = HASH256::new();
+ if let Some(x) = a {
+ h.process_array(x);
+ }
+ if n >= 0 {
+ h.process_num(n as i32)
+ }
+ let hs = h.hash();
+ for i in 0..sha {
+ w[i] = hs[i]
+ }
+ }
+ if sha == SHA384 {
+ let mut h = HASH384::new();
+ if let Some(x) = a {
+ h.process_array(x);
+ }
+ if n >= 0 {
+ h.process_num(n as i32)
+ }
+ let hs = h.hash();
+ for i in 0..sha {
+ w[i] = hs[i]
+ }
+ }
+ if sha == SHA512 {
+ let mut h = HASH512::new();
+ if let Some(x) = a {
+ h.process_array(x);
+ }
+ if n >= 0 {
+ h.process_num(n as i32)
+ }
+ let hs = h.hash();
+ for i in 0..sha {
+ w[i] = hs[i]
+ }
+ }
+}
+
+pub fn key_pair(rng: &mut RAND, e: isize, prv: &mut RsaPrivateKey, pbc: &mut RsaPublicKey) {
+ /* IEEE1363 A16.11/A16.12 more or less */
+ let n = pbc.n.getlen() / 2;
+ let mut t = FF::new_int(n);
+ let mut p1 = FF::new_int(n);
+ let mut q1 = FF::new_int(n);
+
+ loop {
+ prv.p.random(rng);
+ while prv.p.lastbits(2) != 3 {
+ prv.p.inc(1)
+ }
+ while !FF::prime(&prv.p, rng) {
+ prv.p.inc(4);
+ }
+
+ p1.copy(&prv.p);
+ p1.dec(1);
+
+ if p1.cfactor(e) {
+ continue;
+ }
+ break;
+ }
+
+ loop {
+ prv.q.random(rng);
+ while prv.q.lastbits(2) != 3 {
+ prv.q.inc(1)
+ }
+ while !FF::prime(&prv.q, rng) {
+ prv.q.inc(4);
+ }
+
+ q1.copy(&prv.q);
+ q1.dec(1);
+
+ if q1.cfactor(e) {
+ continue;
+ }
+
+ break;
+ }
+
+ pbc.n = FF::mul(&prv.p, &prv.q);
+ pbc.e = e;
+
+ t.copy(&p1);
+ t.shr();
+ prv.dp.set(e);
+ prv.dp.invmodp(&t);
+ if prv.dp.parity() == 0 {
+ prv.dp.add(&t)
+ }
+ prv.dp.norm();
+
+ t.copy(&q1);
+ t.shr();
+ prv.dq.set(e);
+ prv.dq.invmodp(&t);
+ if prv.dq.parity() == 0 {
+ prv.dq.add(&t)
+ }
+ prv.dq.norm();
+
+ prv.c.copy(&prv.p);
+ prv.c.invmodp(&prv.q);
+}
+
+/* Mask Generation Function */
+
+pub fn mgf1(sha: usize, z: &[u8], olen: usize, k: &mut [u8]) {
+ let hlen = sha;
+
+ let mut j = 0;
+ for i in 0..k.len() {
+ k[i] = 0
+ }
+
+ let mut cthreshold = olen / hlen;
+ if olen % hlen != 0 {
+ cthreshold += 1
+ }
+ for counter in 0..cthreshold {
+ let mut b: [u8; 64] = [0; 64];
+ hashit(sha, Some(z), counter as isize, &mut b);
+
+ if j + hlen > olen {
+ for i in 0..(olen % hlen) {
+ k[j] = b[i];
+ j += 1
+ }
+ } else {
+ for i in 0..hlen {
+ k[j] = b[i];
+ j += 1
+ }
+ }
+ }
+}
+
+/* SHAXXX identifier strings */
+const SHA256ID: [u8; 19] = [
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20,
+];
+const SHA384ID: [u8; 19] = [
+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30,
+];
+const SHA512ID: [u8; 19] = [
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40,
+];
+
+pub fn pkcs15(sha: usize, m: &[u8], w: &mut [u8]) -> bool {
+ let olen = ff::FF_BITS / 8;
+ let hlen = sha;
+ let idlen = 19;
+ let mut b: [u8; 64] = [0; 64]; /* Not good */
+
+ if olen < idlen + hlen + 10 {
+ return false;
+ }
+ hashit(sha, Some(m), -1, &mut b);
+
+ for i in 0..w.len() {
+ w[i] = 0
+ }
+ let mut i = 0;
+ w[i] = 0;
+ i += 1;
+ w[i] = 1;
+ i += 1;
+ for _ in 0..olen - idlen - hlen - 3 {
+ w[i] = 0xff;
+ i += 1
+ }
+ w[i] = 0;
+ i += 1;
+
+ if hlen == SHA256 {
+ for j in 0..idlen {
+ w[i] = SHA256ID[j];
+ i += 1
+ }
+ }
+ if hlen == SHA384 {
+ for j in 0..idlen {
+ w[i] = SHA384ID[j];
+ i += 1
+ }
+ }
+ if hlen == SHA512 {
+ for j in 0..idlen {
+ w[i] = SHA512ID[j];
+ i += 1
+ }
+ }
+ for j in 0..hlen {
+ w[i] = b[j];
+ i += 1
+ }
+
+ return true;
+}
+
+/* OAEP Message Encoding for Encryption */
+pub fn oaep_encode(sha: usize, m: &[u8], rng: &mut RAND, p: Option<&[u8]>, f: &mut [u8]) -> bool {
+ let olen = RFS - 1;
+ let mlen = m.len();
+
+ let hlen = sha;
+
+ let mut seed: [u8; 64] = [0; 64];
+
+ let seedlen = hlen;
+ if mlen > olen - hlen - seedlen - 1 {
+ return false;
+ }
+
+ let mut dbmask: [u8; RFS] = [0; RFS];
+
+ hashit(sha, p, -1, f);
+ let slen = olen - mlen - hlen - seedlen - 1;
+
+ for i in 0..slen {
+ f[hlen + i] = 0
+ }
+ f[hlen + slen] = 1;
+ for i in 0..mlen {
+ f[hlen + slen + 1 + i] = m[i]
+ }
+
+ for i in 0..seedlen {
+ seed[i] = rng.getbyte()
+ }
+
+ mgf1(sha, &seed, olen - seedlen, &mut dbmask);
+
+ for i in 0..olen - seedlen {
+ dbmask[i] ^= f[i]
+ }
+
+ mgf1(sha, &dbmask[0..olen - seedlen], seedlen, f);
+
+ for i in 0..seedlen {
+ f[i] ^= seed[i]
+ }
+
+ for i in 0..olen - seedlen {
+ f[i + seedlen] = dbmask[i]
+ }
+
+ /* pad to length RFS */
+ let d = 1;
+ for i in (d..RFS).rev() {
+ f[i] = f[i - d];
+ }
+ for i in (0..d).rev() {
+ f[i] = 0;
+ }
+ return true;
+}
+
+/* OAEP Message Decoding for Decryption */
+pub fn oaep_decode(sha: usize, p: Option<&[u8]>, f: &mut [u8]) -> usize {
+ let olen = RFS - 1;
+
+ let hlen = sha;
+ let mut seed: [u8; 64] = [0; 64];
+ let seedlen = hlen;
+ let mut chash: [u8; 64] = [0; 64];
+
+ if olen < seedlen + hlen + 1 {
+ return 0;
+ }
+ let mut dbmask: [u8; RFS] = [0; RFS];
+ //for i in 0..olen-seedlen {dbmask[i]=0}
+
+ if f.len() < RFS {
+ let d = RFS - f.len();
+ for i in (d..RFS).rev() {
+ f[i] = f[i - d];
+ }
+ for i in (0..d).rev() {
+ f[i] = 0;
+ }
+ }
+
+ hashit(sha, p, -1, &mut chash);
+
+ let x = f[0];
+
+ for i in seedlen..olen {
+ dbmask[i - seedlen] = f[i + 1];
+ }
+
+ mgf1(sha, &dbmask[0..olen - seedlen], seedlen, &mut seed);
+ for i in 0..seedlen {
+ seed[i] ^= f[i + 1]
+ }
+ mgf1(sha, &seed, olen - seedlen, f);
+ for i in 0..olen - seedlen {
+ dbmask[i] ^= f[i]
+ }
+
+ let mut comp = true;
+ for i in 0..hlen {
+ if chash[i] != dbmask[i] {
+ comp = false
+ }
+ }
+
+ for i in 0..olen - seedlen - hlen {
+ dbmask[i] = dbmask[i + hlen]
+ }
+
+ for i in 0..hlen {
+ seed[i] = 0;
+ chash[i] = 0
+ }
+
+ let mut k = 0;
+ loop {
+ if k >= olen - seedlen - hlen {
+ return 0;
+ }
+ if dbmask[k] != 0 {
+ break;
+ }
+ k += 1;
+ }
+
+ let t = dbmask[k];
+ if !comp || x != 0 || t != 0x01 {
+ for i in 0..olen - seedlen {
+ dbmask[i] = 0
+ }
+ return 0;
+ }
+
+ for i in 0..olen - seedlen - hlen - k - 1 {
+ f[i] = dbmask[i + k + 1];
+ }
+
+ for i in 0..olen - seedlen {
+ dbmask[i] = 0
+ }
+
+ return olen - seedlen - hlen - k - 1;
+}
+
+/* destroy the Private Key structure */
+pub fn private_key_kill(prv: &mut RsaPrivateKey) {
+ prv.p.zero();
+ prv.q.zero();
+ prv.dp.zero();
+ prv.dq.zero();
+ prv.c.zero();
+}
+
+/* RSA encryption with the public key */
+pub fn encrypt(pbc: &RsaPublicKey, f: &[u8], g: &mut [u8]) {
+ let m = pbc.n.getlen();
+ let mut r = FF::new_int(m);
+
+ FF::frombytes(&mut r, f);
+ r.power(pbc.e, &pbc.n);
+ r.tobytes(g);
+}
+
+/* RSA decryption with the private key */
+pub fn decrypt(prv: &RsaPrivateKey, g: &[u8], f: &mut [u8]) {
+ let n = prv.p.getlen();
+ let mut r = FF::new_int(2 * n);
+
+ FF::frombytes(&mut r, g);
+ let mut jp = r.dmod(&prv.p);
+ let mut jq = r.dmod(&prv.q);
+
+ jp.skpow(&prv.dp, &prv.p);
+ jq.skpow(&prv.dq, &prv.q);
+
+ r.zero();
+ r.dscopy(&jp);
+ jp.rmod(&prv.q);
+ if FF::comp(&jp, &jq) > 0 {
+ jq.add(&prv.q)
+ }
+ jq.sub(&jp);
+ jq.norm();
+
+ let mut t = FF::mul(&prv.c, &jq);
+ jq = t.dmod(&prv.q);
+
+ t = FF::mul(&jq, &prv.p);
+ r.add(&t);
+ r.norm();
+
+ r.tobytes(f);
+}
diff --git a/src/sha3.rs b/src/sha3.rs
new file mode 100644
index 0000000..eeaf953
--- /dev/null
+++ b/src/sha3.rs
@@ -0,0 +1,270 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+pub const HASH224: usize = 28;
+pub const HASH256: usize = 32;
+pub const HASH384: usize = 48;
+pub const HASH512: usize = 64;
+pub const SHAKE128: usize = 16;
+pub const SHAKE256: usize = 32;
+
+const ROUNDS: usize = 24;
+
+const RC: [u64; 24] = [
+ 0x0000000000000001,
+ 0x0000000000008082,
+ 0x800000000000808A,
+ 0x8000000080008000,
+ 0x000000000000808B,
+ 0x0000000080000001,
+ 0x8000000080008081,
+ 0x8000000000008009,
+ 0x000000000000008A,
+ 0x0000000000000088,
+ 0x0000000080008009,
+ 0x000000008000000A,
+ 0x000000008000808B,
+ 0x800000000000008B,
+ 0x8000000000008089,
+ 0x8000000000008003,
+ 0x8000000000008002,
+ 0x8000000000000080,
+ 0x000000000000800A,
+ 0x800000008000000A,
+ 0x8000000080008081,
+ 0x8000000000008080,
+ 0x0000000080000001,
+ 0x8000000080008008,
+];
+
+pub struct SHA3 {
+ length: u64,
+ rate: usize,
+ len: usize,
+ s: [[u64; 5]; 5],
+}
+
+impl SHA3 {
+ fn rotl(x: u64, n: u64) -> u64 {
+ return ((x) << n) | ((x) >> (64 - n));
+ }
+
+ fn transform(&mut self) {
+ /* basic transformation step */
+ let mut c: [u64; 5] = [0; 5];
+ let mut d: [u64; 5] = [0; 5];
+ let mut b: [[u64; 5]; 5] = [[0; 5]; 5];
+
+ for k in 0..ROUNDS {
+ c[0] = self.s[0][0] ^ self.s[0][1] ^ self.s[0][2] ^ self.s[0][3] ^ self.s[0][4];
+ c[1] = self.s[1][0] ^ self.s[1][1] ^ self.s[1][2] ^ self.s[1][3] ^ self.s[1][4];
+ c[2] = self.s[2][0] ^ self.s[2][1] ^ self.s[2][2] ^ self.s[2][3] ^ self.s[2][4];
+ c[3] = self.s[3][0] ^ self.s[3][1] ^ self.s[3][2] ^ self.s[3][3] ^ self.s[3][4];
+ c[4] = self.s[4][0] ^ self.s[4][1] ^ self.s[4][2] ^ self.s[4][3] ^ self.s[4][4];
+
+ d[0] = c[4] ^ SHA3::rotl(c[1], 1);
+ d[1] = c[0] ^ SHA3::rotl(c[2], 1);
+ d[2] = c[1] ^ SHA3::rotl(c[3], 1);
+ d[3] = c[2] ^ SHA3::rotl(c[4], 1);
+ d[4] = c[3] ^ SHA3::rotl(c[0], 1);
+
+ for i in 0..5 {
+ for j in 0..5 {
+ self.s[i][j] ^= d[i];
+ }
+ }
+
+ b[0][0] = self.s[0][0];
+ b[1][3] = SHA3::rotl(self.s[0][1], 36);
+ b[2][1] = SHA3::rotl(self.s[0][2], 3);
+ b[3][4] = SHA3::rotl(self.s[0][3], 41);
+ b[4][2] = SHA3::rotl(self.s[0][4], 18);
+
+ b[0][2] = SHA3::rotl(self.s[1][0], 1);
+ b[1][0] = SHA3::rotl(self.s[1][1], 44);
+ b[2][3] = SHA3::rotl(self.s[1][2], 10);
+ b[3][1] = SHA3::rotl(self.s[1][3], 45);
+ b[4][4] = SHA3::rotl(self.s[1][4], 2);
+
+ b[0][4] = SHA3::rotl(self.s[2][0], 62);
+ b[1][2] = SHA3::rotl(self.s[2][1], 6);
+ b[2][0] = SHA3::rotl(self.s[2][2], 43);
+ b[3][3] = SHA3::rotl(self.s[2][3], 15);
+ b[4][1] = SHA3::rotl(self.s[2][4], 61);
+
+ b[0][1] = SHA3::rotl(self.s[3][0], 28);
+ b[1][4] = SHA3::rotl(self.s[3][1], 55);
+ b[2][2] = SHA3::rotl(self.s[3][2], 25);
+ b[3][0] = SHA3::rotl(self.s[3][3], 21);
+ b[4][3] = SHA3::rotl(self.s[3][4], 56);
+
+ b[0][3] = SHA3::rotl(self.s[4][0], 27);
+ b[1][1] = SHA3::rotl(self.s[4][1], 20);
+ b[2][4] = SHA3::rotl(self.s[4][2], 39);
+ b[3][2] = SHA3::rotl(self.s[4][3], 8);
+ b[4][0] = SHA3::rotl(self.s[4][4], 14);
+
+ for i in 0..5 {
+ for j in 0..5 {
+ self.s[i][j] = b[i][j] ^ (!b[(i + 1) % 5][j] & b[(i + 2) % 5][j]);
+ }
+ }
+
+ self.s[0][0] ^= RC[k];
+ }
+ }
+
+ /* Initialise Hash function */
+ pub fn init(&mut self, olen: usize) {
+ /* initialise */
+ for i in 0..5 {
+ for j in 0..5 {
+ self.s[i][j] = 0;
+ }
+ }
+ self.length = 0;
+ self.len = olen;
+ self.rate = 200 - 2 * olen;
+ }
+
+ pub fn new(olen: usize) -> SHA3 {
+ let mut nh = SHA3 {
+ length: 0,
+ rate: 0,
+ len: 0,
+ s: [[0; 5]; 5],
+ };
+ nh.init(olen);
+ return nh;
+ }
+
+ /* process a single byte */
+ pub fn process(&mut self, byt: u8) {
+ /* process the next message byte */
+ let cnt = (self.length % (self.rate as u64)) as usize;
+ let b = cnt % 8;
+ let ind = cnt / 8;
+ let i = ind % 5;
+ let j = ind / 5;
+ self.s[i][j] ^= ((byt & 0xff) as u64) << (8 * b);
+ self.length += 1;
+ if cnt + 1 == self.rate {
+ self.transform();
+ }
+ }
+
+ pub fn squeeze(&mut self, buff: &mut [u8], olen: usize) {
+ //let olen=buff.len();
+ let mut done = false;
+ let mut m = 0;
+ loop {
+ for j in 0..5 {
+ for i in 0..5 {
+ let mut el = self.s[i][j];
+ for _ in 0..8 {
+ buff[m] = (el & 0xff) as u8;
+ m += 1;
+ if m >= olen || (m % self.rate) == 0 {
+ done = true;
+ break;
+ }
+ el >>= 8;
+ }
+ if done {
+ break;
+ }
+ }
+ if done {
+ break;
+ }
+ }
+ if m >= olen {
+ break;
+ }
+ done = false;
+ self.transform();
+ }
+ }
+
+ /* Generate 32-byte Hash */
+ pub fn hash(&mut self, digest: &mut [u8]) {
+ /* pad message and finish - supply digest */
+ let q = self.rate - (self.length % (self.rate as u64)) as usize;
+ if q == 1 {
+ self.process(0x86);
+ } else {
+ self.process(0x06);
+ while (self.length % (self.rate as u64)) as usize != self.rate - 1 {
+ self.process(0x00)
+ }
+ self.process(0x80);
+ }
+ let hlen = self.len as usize;
+ self.squeeze(digest, hlen);
+ }
+
+ pub fn shake(&mut self, digest: &mut [u8], olen: usize) {
+ let q = self.rate - (self.length % (self.rate as u64)) as usize;
+ if q == 1 {
+ self.process(0x9f);
+ } else {
+ self.process(0x1f);
+ while (self.length % (self.rate as u64)) as usize != self.rate - 1 {
+ self.process(0x00)
+ }
+ self.process(0x80);
+ }
+ self.squeeze(digest, olen);
+ }
+}
+
+//916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18
+//afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185
+//98be04516c04cc73593fef3ed0352ea9f6443942d6950e29a372a681c3deaf4535423709b02843948684e029010badcc0acd8303fc85fdad3eabf4f78cae165635f57afd28810fc2
+/*
+fn main() {
+ let s = String::from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
+ let mut digest: [u8;100]=[0;100];
+ let test = s.into_bytes();
+
+ let mut sh=SHA3::new(HASH256);
+ for i in 0..test.len(){
+ sh.process(test[i]);
+ }
+ sh.hash(&mut digest);
+ for i in 0..32 {print!("{:02x}",digest[i])}
+ println!("");
+
+ sh=SHA3::new(HASH512);
+ for i in 0..test.len(){
+ sh.process(test[i]);
+ }
+ sh.hash(&mut digest);
+ for i in 0..64 {print!("{:02x}",digest[i])}
+ println!("");
+
+ sh=SHA3::new(SHAKE256);
+ for i in 0..test.len(){
+ sh.process(test[i]);
+ }
+ sh.shake(&mut digest,72);
+ for i in 0..72 {print!("{:02x}",digest[i])}
+ println!("");
+
+} */
diff --git a/src/types.rs b/src/types.rs
new file mode 100644
index 0000000..ea310d7
--- /dev/null
+++ b/src/types.rs
@@ -0,0 +1,45 @@
+#[derive(PartialEq)]
+pub enum ModType {
+ NOT_SPECIAL,
+ PSEUDO_MERSENNE,
+ MONTGOMERY_FRIENDLY,
+ GENERALISED_MERSENNE,
+}
+
+#[derive(PartialEq)]
+pub enum CurveType {
+ EDWARDS,
+ WEIERSTRASS,
+ MONTGOMERY,
+}
+
+#[derive(PartialEq)]
+pub enum CurvePairingType {
+ NOT,
+ BN,
+ BLS,
+}
+
+#[derive(PartialEq)]
+pub enum SexticTwist {
+ NOT,
+ D_TYPE,
+ M_TYPE,
+}
+impl Into<usize> for SexticTwist {
+ fn into(self) -> usize {
+ match self {
+ SexticTwist::NOT => 0,
+ SexticTwist::D_TYPE => 0,
+ SexticTwist::M_TYPE => 1,
+ }
+ }
+}
+
+#[derive(PartialEq)]
+pub enum SignOfX {
+ NOT,
+ POSITIVEX,
+ NEGATIVEX,
+}
+