You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by km...@apache.org on 2019/06/26 09:01:42 UTC
[incubator-milagro-crypto-rust] 01/01: initial commit
This is an automated email from the ASF dual-hosted git repository.
kmccusker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-crypto-rust.git
commit 3948f75f9adb2ff91578af3171b5909ae99a0e85
Author: Kealan McCusker <ke...@gmail.com>
AuthorDate: Wed Jun 26 10:01:25 2019 +0100
initial commit
---
BenchtestALL.rs | 957 ++++++++++++++++++++++++
Cargo.lock | 6 +
Cargo.toml | 46 ++
LICENSE | 202 ++++++
TestALL.rs | 1459 +++++++++++++++++++++++++++++++++++++
TestBLS.rs | 190 +++++
TestNHS.rs | 77 ++
deploy.token | 1 +
readme.md | 83 +++
src/aes.rs | 772 ++++++++++++++++++++
src/arch/arch32.rs | 22 +
src/arch/arch64.rs | 22 +
src/big.rs | 1070 +++++++++++++++++++++++++++
src/bls.rs | 96 +++
src/bls192.rs | 96 +++
src/bls256.rs | 96 +++
src/dbig.rs | 301 ++++++++
src/ecdh.rs | 744 +++++++++++++++++++
src/ecp.rs | 1261 ++++++++++++++++++++++++++++++++
src/ecp2.rs | 784 ++++++++++++++++++++
src/ecp4.rs | 866 ++++++++++++++++++++++
src/ecp8.rs | 1155 +++++++++++++++++++++++++++++
src/ff.rs | 1058 +++++++++++++++++++++++++++
src/fp.rs | 717 ++++++++++++++++++
src/fp12.rs | 1109 ++++++++++++++++++++++++++++
src/fp16.rs | 602 +++++++++++++++
src/fp2.rs | 407 +++++++++++
src/fp24.rs | 1268 ++++++++++++++++++++++++++++++++
src/fp4.rs | 697 ++++++++++++++++++
src/fp48.rs | 1610 +++++++++++++++++++++++++++++++++++++++++
src/fp8.rs | 701 ++++++++++++++++++
src/gcm.rs | 481 ++++++++++++
src/hash256.rs | 216 ++++++
src/hash384.rs | 288 ++++++++
src/hash512.rs | 288 ++++++++
src/lib.rs | 561 ++++++++++++++
src/mpin.rs | 945 ++++++++++++++++++++++++
src/mpin192.rs | 960 ++++++++++++++++++++++++
src/mpin256.rs | 993 +++++++++++++++++++++++++
src/nhs.rs | 705 ++++++++++++++++++
src/pair.rs | 755 +++++++++++++++++++
src/pair192.rs | 606 ++++++++++++++++
src/pair256.rs | 722 ++++++++++++++++++
src/rand.rs | 180 +++++
src/roms/rom_anssi_32.rs | 73 ++
src/roms/rom_anssi_64.rs | 91 +++
src/roms/rom_bls24_32.rs | 240 ++++++
src/roms/rom_bls24_64.rs | 288 ++++++++
src/roms/rom_bls381_32.rs | 209 ++++++
src/roms/rom_bls381_64.rs | 211 ++++++
src/roms/rom_bls383_32.rs | 207 ++++++
src/roms/rom_bls383_64.rs | 218 ++++++
src/roms/rom_bls461_32.rs | 209 ++++++
src/roms/rom_bls461_64.rs | 232 ++++++
src/roms/rom_bls48_32.rs | 309 ++++++++
src/roms/rom_bls48_64.rs | 401 ++++++++++
src/roms/rom_bn254CX_32.rs | 183 +++++
src/roms/rom_bn254CX_64.rs | 242 +++++++
src/roms/rom_bn254_32.rs | 171 +++++
src/roms/rom_bn254_64.rs | 208 ++++++
src/roms/rom_brainpool_32.rs | 74 ++
src/roms/rom_brainpool_64.rs | 92 +++
src/roms/rom_c25519_32.rs | 59 ++
src/roms/rom_c25519_64.rs | 61 ++
src/roms/rom_c41417_32.rs | 71 ++
src/roms/rom_c41417_64.rs | 78 ++
src/roms/rom_ed25519_32.rs | 68 ++
src/roms/rom_ed25519_64.rs | 79 ++
src/roms/rom_fp256bn_32.rs | 180 +++++
src/roms/rom_fp256bn_64.rs | 233 ++++++
src/roms/rom_fp512bn_32.rs | 249 +++++++
src/roms/rom_fp512bn_64.rs | 482 ++++++++++++
src/roms/rom_goldilocks_32.rs | 73 ++
src/roms/rom_goldilocks_64.rs | 99 +++
src/roms/rom_hifive_32.rs | 68 ++
src/roms/rom_hifive_64.rs | 77 ++
src/roms/rom_nist256_32.rs | 74 ++
src/roms/rom_nist256_64.rs | 86 +++
src/roms/rom_nist384_32.rs | 76 ++
src/roms/rom_nist384_64.rs | 104 +++
src/roms/rom_nist521_32.rs | 79 ++
src/roms/rom_nist521_64.rs | 104 +++
src/roms/rom_nums256e_32.rs | 71 ++
src/roms/rom_nums256e_64.rs | 80 ++
src/roms/rom_nums256w_32.rs | 66 ++
src/roms/rom_nums256w_64.rs | 78 ++
src/roms/rom_nums384e_32.rs | 74 ++
src/roms/rom_nums384e_64.rs | 95 +++
src/roms/rom_nums384w_32.rs | 74 ++
src/roms/rom_nums384w_64.rs | 94 +++
src/roms/rom_nums512e_32.rs | 79 ++
src/roms/rom_nums512e_64.rs | 104 +++
src/roms/rom_nums512w_32.rs | 77 ++
src/roms/rom_nums512w_64.rs | 94 +++
src/roms/rom_rsa2048_32.rs | 3 +
src/roms/rom_rsa2048_64.rs | 3 +
src/roms/rom_rsa3072_32.rs | 3 +
src/roms/rom_rsa3072_64.rs | 3 +
src/roms/rom_rsa4096_32.rs | 3 +
src/roms/rom_rsa4096_64.rs | 3 +
src/roms/rom_secp256k1_32.rs | 70 ++
src/roms/rom_secp256k1_64.rs | 81 +++
src/rsa.rs | 469 ++++++++++++
src/sha3.rs | 270 +++++++
src/types.rs | 45 ++
105 files changed, 34172 insertions(+)
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 <ni...@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/4Q4jUoy8CtrZu6BCxAK7muLLWaI91gWpducaJKZ6dVHZ5tBz7XHG7NFpqRssCUfIMhg [...]
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();
... 24926 lines suppressed ...