diff --git a/mobile_wallet/Cargo.lock b/mobile_wallet/Cargo.lock index 264ad4226..2cb0c870f 100644 --- a/mobile_wallet/Cargo.lock +++ b/mobile_wallet/Cargo.lock @@ -273,7 +273,7 @@ version = "4.0.1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -321,7 +321,7 @@ version = "1.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -338,9 +338,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -476,7 +476,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -487,7 +487,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -833,9 +833,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "link-cplusplus" @@ -1072,9 +1072,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1101,9 +1101,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1344,7 +1344,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -1383,7 +1383,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -1457,9 +1457,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", diff --git a/rust-src/Cargo.lock b/rust-src/Cargo.lock index 5c5f874a4..f2e10f6e9 100644 --- a/rust-src/Cargo.lock +++ b/rust-src/Cargo.lock @@ -969,9 +969,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "log" diff --git a/rust-src/concordium_base/CHANGELOG.md b/rust-src/concordium_base/CHANGELOG.md index 4e7a061d1..e58078d26 100644 --- a/rust-src/concordium_base/CHANGELOG.md +++ b/rust-src/concordium_base/CHANGELOG.md @@ -1,6 +1,9 @@ ## Unreleased changes - Improve performance of `multiexp*` family of functions. +- Add traits `Field` and `PrimeField` with implementations for the underlying field of the `BLS12-381`` curve. +- Add `MultiExp` trait that allows to have different `multiexp` algorithm implementations for different curves. +- Add implementations of `Field`, `PrimeField` and `Curve` for the Ristretto representation of `curve25519`. - Support `P7` protocol version. - The `Debug` implementation for `ContractEvent` displays the value in `hex`. The alternate formatter (using `#`) displays it as a list of bytes. diff --git a/rust-src/concordium_base/benches/bulletproofs.rs b/rust-src/concordium_base/benches/bulletproofs.rs index 6716a8ff8..4c6b77839 100644 --- a/rust-src/concordium_base/benches/bulletproofs.rs +++ b/rust-src/concordium_base/benches/bulletproofs.rs @@ -11,16 +11,14 @@ use concordium_base::{ random_oracle::RandomOracle, }; use criterion::Criterion; -use ff::Field; -use pairing::bls12_381::{Fr, G1}; +use curve25519_dalek::ristretto::RistrettoPoint; +use pairing::bls12_381::G1; use rand::*; use std::time::Duration; -type SomeCurve = G1; -type SomeField = Fr; - -pub fn prove_verify_benchmarks(c: &mut Criterion) { - let mut group = c.benchmark_group("Range Proof"); +pub fn prove_verify_benchmarks(c: &mut Criterion) { + let bench_group_name = "Range Proof for ".to_owned() + std::any::type_name::(); + let mut group = c.benchmark_group(bench_group_name); let rng = &mut thread_rng(); let n: u8 = 32; @@ -118,8 +116,12 @@ pub fn prove_verify_benchmarks(c: &mut Criterion) { } #[allow(non_snake_case)] -fn compare_inner_product_proof(c: &mut Criterion) { - let mut group = c.benchmark_group("Inner-Product Proof"); +fn compare_inner_product_proof(c: &mut Criterion) { + let bench_group_name = format!( + "Inner-Product Proof for {}", + std::any::type_name::() + ); + let mut group = c.benchmark_group(bench_group_name); // Testing with n = 4 let rng = &mut thread_rng(); @@ -145,7 +147,7 @@ fn compare_inner_product_proof(c: &mut Criterion) { let H = H_vec.clone(); let mut H_prime: Vec = Vec::with_capacity(n); let y_inv = y.inverse().unwrap(); - let mut H_prime_scalars: Vec = Vec::with_capacity(n); + let mut H_prime_scalars: Vec<::Scalar> = Vec::with_capacity(n); let mut transcript = RandomOracle::empty(); let G_vec_p = G_vec.clone(); let H_vec_p = H_vec.clone(); @@ -153,7 +155,7 @@ fn compare_inner_product_proof(c: &mut Criterion) { let b_vec_p = b_vec.clone(); group.bench_function("Naive inner product proof", move |b| { b.iter(|| { - let mut y_inv_i = SomeField::one(); + let mut y_inv_i = ::Scalar::one(); for h in H.iter().take(n) { H_prime.push(h.mul_by_scalar(&y_inv_i)); y_inv_i.mul_assign(&y_inv); @@ -164,7 +166,7 @@ fn compare_inner_product_proof(c: &mut Criterion) { let mut transcript = RandomOracle::empty(); group.bench_function("Better inner product proof with scalars", move |b| { b.iter(|| { - let mut y_inv_i = SomeField::one(); + let mut y_inv_i = ::Scalar::one(); for _ in 0..n { H_prime_scalars.push(y_inv_i); y_inv_i.mul_assign(&y_inv); @@ -185,5 +187,5 @@ fn compare_inner_product_proof(c: &mut Criterion) { criterion_group!( name = benchmarks; config = Criterion::default().measurement_time(Duration::from_millis(1000)).sample_size(10); - targets = prove_verify_benchmarks, compare_inner_product_proof); + targets = prove_verify_benchmarks::, prove_verify_benchmarks::, compare_inner_product_proof::, compare_inner_product_proof::); criterion_main!(benchmarks); diff --git a/rust-src/concordium_base/benches/multiexp_bench.rs b/rust-src/concordium_base/benches/multiexp_bench.rs index 5b1ee39fb..018c4e1dc 100644 --- a/rust-src/concordium_base/benches/multiexp_bench.rs +++ b/rust-src/concordium_base/benches/multiexp_bench.rs @@ -3,10 +3,12 @@ extern crate criterion; use concordium_base::curve_arithmetic::*; use criterion::Criterion; +use curve25519_dalek::ristretto::RistrettoPoint; use pairing::bls12_381::G1; use rand::*; +use std::time::Duration; -pub fn bench_multiexp(c: &mut Criterion) { +pub fn bench_multiexp_bls(c: &mut Criterion) { let mut csprng = thread_rng(); let m = 3; let ns = (1..=m).map(|x| x * x); @@ -21,7 +23,7 @@ pub fn bench_multiexp(c: &mut Criterion) { let gsc = gs[..i].to_vec(); let esc = es[..i].to_vec(); let mut group = c.benchmark_group(format!("Group({})", i)); - group.bench_function(format!("{}: Baseline", module_path!()), move |b| { + group.bench_function(format!("{}: Baseline for BLS", module_path!()), move |b| { b.iter(|| { let mut a = G1::zero_point(); for (g, e) in gsc.iter().zip(esc.iter()) { @@ -33,13 +35,67 @@ pub fn bench_multiexp(c: &mut Criterion) { let gsc = gs[..i].to_vec(); let esc = es[..i].to_vec(); group.bench_function( - &format!("{}: Multiexp (window = {w})", module_path!()), - move |b| b.iter(|| multiexp_worker(&gsc, &esc, w)), + &format!("{}: Multiexp for BLS (window = {w})", module_path!()), + move |b| b.iter(|| GenericMultiExp::new(&gsc, w).multiexp(&esc)), ); } group.finish(); } } -criterion_group!(multiexp_benchmarks, bench_multiexp); +// Benchmarking multi-exponentiation over the Ristretto curve. Note that we have +// two multiexp algorithms in our library: one that is tailor-made for the +// Ristretto curve, and one generic algorithm for other curves (e.g., BLS). +// The purpose of this benchmark is to measure the running time of the multiexp +// algorithm for the Ristretto curve. +pub fn bench_multiexp_ristretto(c: &mut Criterion) { + let mut csprng = thread_rng(); + let m = 3; + let ns = (1..=m).map(|x| x * x); + let mut gs: Vec = Vec::with_capacity(m * m); + let mut es: Vec<::Scalar> = Vec::with_capacity(m * m); + for _ in 0..(m * m) { + gs.push(RistrettoPoint::generate(&mut csprng)); + es.push(RistrettoPoint::generate_scalar(&mut csprng)); + } + + for i in ns { + let gsc = gs[..i].to_vec(); + let esc = es[..i].to_vec(); + let mut group = c.benchmark_group(format!("Group({})", i)); + group.bench_function( + format!("{}: Baseline for Ristretto", module_path!()), + move |b| { + b.iter(|| { + let mut a = RistrettoPoint::zero_point(); + for (g, e) in gsc.iter().zip(esc.iter()) { + a = a.plus_point(&g.mul_by_scalar(e)) + } + }) + }, + ); + + let gsc = gs[..i].to_vec(); + let esc = es[..i].to_vec(); + group.bench_function( + format!("{}: Multiexp for Ristretto", module_path!()), + move |b| { + b.iter(|| { + // Create msm algorithm instance with a precomputed point table. + // For the Ristretto curve it will use the RistrettoMultiExpNoPrecompute and + // our generic implementation for the BLS curve. + let msm = RistrettoPoint::new_multiexp(&gsc); + msm.multiexp(&esc); + }) + }, + ); + + group.finish(); + } +} + +criterion_group!( + name = multiexp_benchmarks; + config = Criterion::default().measurement_time(Duration::from_millis(10000)).sample_size(100); + targets = bench_multiexp_bls, bench_multiexp_ristretto); criterion_main!(multiexp_benchmarks); diff --git a/rust-src/concordium_base/src/aggregate_sig/mod.rs b/rust-src/concordium_base/src/aggregate_sig/mod.rs index ab369bb6c..0b1566f32 100644 --- a/rust-src/concordium_base/src/aggregate_sig/mod.rs +++ b/rust-src/concordium_base/src/aggregate_sig/mod.rs @@ -4,11 +4,10 @@ mod ffi; use crate::{ common::{SerdeBase16Serialize, Serialize, *}, - curve_arithmetic::{Curve, Pairing, Value}, + curve_arithmetic::{Curve, Field, Pairing, Value}, random_oracle::RandomOracle, sigma_protocols::{common::*, dlog::*}, }; -use ff::Field; use rand::Rng; use rayon::iter::*; use sha2::{digest::Output, Digest, Sha512}; diff --git a/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs b/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs index f10145247..7addcb249 100644 --- a/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs @@ -2,10 +2,9 @@ //! this crate use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, random_oracle::RandomOracle, }; -use ff::Field; /// Inner product proof #[derive(Clone, Serialize, Debug)] diff --git a/rust-src/concordium_base/src/bulletproofs/range_proof.rs b/rust-src/concordium_base/src/bulletproofs/range_proof.rs index 206f42922..b45a3ebf0 100644 --- a/rust-src/concordium_base/src/bulletproofs/range_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/range_proof.rs @@ -2,12 +2,11 @@ use super::{inner_product_proof::*, utils::*}; use crate::{ common::*, - curve_arithmetic::{multiexp, multiexp_table, multiexp_worker_given_table, Curve, Value}, + curve_arithmetic::{multiexp, Curve, Field, MultiExp, PrimeField, Value}, id::id_proof_types::ProofVersion, pedersen_commitment::*, random_oracle::RandomOracle, }; -use ff::{Field, PrimeField}; use rand::*; use std::iter::once; @@ -92,7 +91,7 @@ pub fn prove_given_scalars( let mut v_integers = Vec::with_capacity(v_vec.len()); for &v in v_vec { let rep = v.into_repr(); - let r = rep.as_ref()[0]; + let r = rep[0]; v_integers.push(r); } @@ -226,10 +225,9 @@ pub fn prove( .chain(once(B_tilde)) .collect(); // compute A and S comittments using multi exponentiation - let window_size = 4; - let table = multiexp_table(&GH_B_tilde, window_size); - let A = multiexp_worker_given_table(&A_scalars, &table, window_size); - let S = multiexp_worker_given_table(&S_scalars, &table, window_size); + let multiexp_alg = C::new_multiexp(&GH_B_tilde); + let A = multiexp_alg.multiexp(&A_scalars); + let S = multiexp_alg.multiexp(&S_scalars); // append commitments A and S to transcript transcript.append_message(b"A", &A); transcript.append_message(b"S", &S); diff --git a/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs b/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs index 02c996714..8b32c184b 100644 --- a/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs @@ -2,12 +2,11 @@ use super::{inner_product_proof::*, utils::*}; use crate::{ common::*, - curve_arithmetic::{multiexp, multiexp_table, multiexp_worker_given_table, Curve}, + curve_arithmetic::{multiexp, Curve, Field, MultiExp}, id::id_proof_types::ProofVersion, pedersen_commitment::*, random_oracle::RandomOracle, }; -use ff::Field; use rand::*; use std::{convert::TryInto, iter::once}; @@ -169,10 +168,9 @@ pub fn prove( .chain(once(B_tilde)) .collect(); // compute A and S commitments using multi exponentiation - let window_size = 4; - let table = multiexp_table(&GH_B_tilde, window_size); - let A = multiexp_worker_given_table(&A_scalars, &table, window_size); - let S = multiexp_worker_given_table(&S_scalars, &table, window_size); + let mexp = C::new_multiexp(&GH_B_tilde); + let A = mexp.multiexp(&A_scalars); + let S = mexp.multiexp(&S_scalars); // append commitments A and S to transcript transcript.append_message(b"A", &A); transcript.append_message(b"S", &S); diff --git a/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs b/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs index 809047778..251f9f54e 100644 --- a/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs @@ -2,12 +2,11 @@ use super::{inner_product_proof::*, utils::*}; use crate::{ common::*, - curve_arithmetic::{multiexp, multiexp_table, multiexp_worker_given_table, Curve}, + curve_arithmetic::{multiexp, Curve, Field, MultiExp}, id::id_proof_types::ProofVersion, pedersen_commitment::*, random_oracle::RandomOracle, }; -use ff::Field; use rand::*; use std::iter::once; @@ -151,10 +150,9 @@ pub fn prove( let s_tilde = &S_scalars[2 * n]; // Compute A and S commitments using multi exponentiation - let window_size = 4; - let table = multiexp_table(&GH_B_tilde, window_size); - let A = multiexp_worker_given_table(&A_scalars, &table, window_size); - let S = multiexp_worker_given_table(&S_scalars, &table, window_size); + let mexp = C::new_multiexp(&GH_B_tilde); + let A = mexp.multiexp(&A_scalars); + let S = mexp.multiexp(&S_scalars); // append commitments A and S to transcript transcript.append_message(b"A", &A); transcript.append_message(b"S", &S); diff --git a/rust-src/concordium_base/src/bulletproofs/utils.rs b/rust-src/concordium_base/src/bulletproofs/utils.rs index cea1224fe..25d6125f2 100644 --- a/rust-src/concordium_base/src/bulletproofs/utils.rs +++ b/rust-src/concordium_base/src/bulletproofs/utils.rs @@ -1,6 +1,8 @@ //! Shared functions used by the proofs in this crate -use crate::{common::*, curve_arithmetic::Curve}; -use ff::Field; +use crate::{ + common::*, + curve_arithmetic::{Curve, Field}, +}; #[cfg(test)] use rand::Rng; /// Struct containing generators G and H needed for range proofs diff --git a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs index 321fcfa94..95d9d8ce4 100644 --- a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs +++ b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs @@ -1,11 +1,10 @@ use super::{bls12_381_g1hash::*, bls12_381_g2hash::*, *}; use byteorder::ReadBytesExt; -use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective, EncodedPoint}; use pairing::{ bls12_381::{ - Bls12, Fr, FrRepr, G1Affine, G1Compressed, G1Prepared, G2Affine, G2Compressed, G2Prepared, - G1, G2, + Bls12, Fq, FqRepr, Fr, FrRepr, G1Affine, G1Compressed, G1Prepared, G2Affine, G2Compressed, + G2Prepared, G1, G2, }, Engine, PairingCurveAffine, }; @@ -24,12 +23,75 @@ fn scalar_from_bytes_helper>(bytes: A) -> Fr { v[..chunk.len()].copy_from_slice(chunk); fr[i] = u64::from_le_bytes(v); } - // unset two topmost bits in the last read u64. + // unset two topmost bits in the last u64 limb. fr[3] &= !(1u64 << 63 | 1u64 << 62); - Fr::from_repr(FrRepr(fr)).expect("The scalar with top two bits erased should be valid.") + ::from_repr(FrRepr(fr)) + .expect("The scalar with top two bits erased should be valid.") +} + +impl Field for F { + fn random(rng: &mut R) -> Self { Self::random(rng) } + + fn zero() -> Self { Self::zero() } + + fn one() -> Self { Self::one() } + + fn is_zero(&self) -> bool { Self::is_zero(self) } + + fn square(&mut self) { self.square() } + + fn double(&mut self) { self.double() } + + fn negate(&mut self) { self.negate() } + + fn add_assign(&mut self, other: &Self) { self.add_assign(other) } + + fn sub_assign(&mut self, other: &Self) { self.sub_assign(other) } + + fn mul_assign(&mut self, other: &Self) { self.mul_assign(other) } + + fn inverse(&self) -> Option { self.inverse() } +} + +impl From for CurveDecodingError { + fn from(e: ff::PrimeFieldDecodingError) -> Self { + let ff::PrimeFieldDecodingError::NotInField(msg) = e; + CurveDecodingError::NotInField(msg) + } +} + +impl PrimeField for Fr { + const CAPACITY: u32 = ::CAPACITY; + const NUM_BITS: u32 = ::NUM_BITS; + + fn into_repr(self) -> Vec { ::into_repr(&self).0.to_vec() } + + fn from_repr(limbs: &[u64]) -> Result { + let l4: [u64; 4] = limbs + .try_into() + .map_err(|_| CurveDecodingError::NotInField(format!("{:?}", limbs)))?; + let res = ::from_repr(FrRepr(l4))?; + Ok(res) + } +} + +impl PrimeField for Fq { + const CAPACITY: u32 = ::CAPACITY; + const NUM_BITS: u32 = ::NUM_BITS; + + fn into_repr(self) -> Vec { ::into_repr(&self).0.to_vec() } + + fn from_repr(limbs: &[u64]) -> Result { + let l6: [u64; 6] = limbs + .try_into() + .map_err(|_| CurveDecodingError::NotInField(format!("{:?}", limbs)))?; + let res = ::from_repr(FqRepr(l6))?; + Ok(res) + } } impl Curve for G2 { + type MultiExpType = GenericMultiExp; type Scalar = Fr; const GROUP_ELEMENT_LENGTH: usize = 96; @@ -74,7 +136,7 @@ impl Curve for G2 { #[inline(always)] fn scalar_from_u64(n: u64) -> Self::Scalar { - Fr::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") + ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") } #[inline(always)] @@ -90,12 +152,13 @@ impl Curve for G2 { fn generate(csprng: &mut T) -> Self { G2::random(csprng) } - fn generate_scalar(csprng: &mut T) -> Self::Scalar { Fr::random(csprng) } + fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } fn hash_to_group(b: &[u8]) -> Self { hash_to_curve_g2(b, HASH_TO_GROUP_G2_DST) } } impl Curve for G1 { + type MultiExpType = GenericMultiExp; type Scalar = Fr; const GROUP_ELEMENT_LENGTH: usize = 48; @@ -140,7 +203,7 @@ impl Curve for G1 { #[inline(always)] fn scalar_from_u64(n: u64) -> Self::Scalar { - Fr::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") + ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") } #[inline(always)] @@ -156,12 +219,13 @@ impl Curve for G1 { fn generate(csprng: &mut T) -> Self { G1::random(csprng) } - fn generate_scalar(csprng: &mut T) -> Self::Scalar { Fr::random(csprng) } + fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } fn hash_to_group(bytes: &[u8]) -> Self { hash_to_curve(bytes, HASH_TO_GROUP_G1_DST) } } impl Curve for G1Affine { + type MultiExpType = GenericMultiExp; type Scalar = Fr; const GROUP_ELEMENT_LENGTH: usize = 48; @@ -203,7 +267,7 @@ impl Curve for G1Affine { } fn scalar_from_u64(n: u64) -> Self::Scalar { - Fr::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") + ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") } #[inline(always)] @@ -219,12 +283,13 @@ impl Curve for G1Affine { fn generate(csprng: &mut T) -> Self { G1::random(csprng).into_affine() } - fn generate_scalar(csprng: &mut T) -> Self::Scalar { Fr::random(csprng) } + fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } fn hash_to_group(b: &[u8]) -> Self { hash_to_curve(b, HASH_TO_GROUP_G1_DST).into_affine() } } impl Curve for G2Affine { + type MultiExpType = GenericMultiExp; type Scalar = Fr; const GROUP_ELEMENT_LENGTH: usize = 96; @@ -266,7 +331,7 @@ impl Curve for G2Affine { } fn scalar_from_u64(n: u64) -> Self::Scalar { - Fr::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") + ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") } #[inline(always)] @@ -282,13 +347,12 @@ impl Curve for G2Affine { fn generate(csprng: &mut T) -> Self { G2::random(csprng).into_affine() } - fn generate_scalar(csprng: &mut T) -> Self::Scalar { Fr::random(csprng) } + fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } fn hash_to_group(b: &[u8]) -> Self { hash_to_curve_g2(b, HASH_TO_GROUP_G2_DST).into_affine() } } impl Pairing for Bls12 { - type BaseField = ::Fq; type G1 = ::G1; type G1Prepared = G1Prepared; type G2 = ::G2; @@ -329,18 +393,20 @@ mod tests { fn scalar_from_bytes_small() { let mut rng = rand::thread_rng(); for _ in 0..1000 { - let n = Fr::random(&mut rng); + let n = ::random(&mut rng); let mut bytes = to_bytes(&n); bytes.reverse(); + println!("bytes: {:?}", bytes[31]); let m = scalar_from_bytes_helper(&bytes); - // make sure that n and m only differ in the topmost bit. - let n = n.into_repr().0; - let m = m.into_repr().0; + // Make sure that n and m only differ in the topmost bits; + // `scalar_from_bytes_helper` resets the topmost bits to zeros. + let n = n.into_repr(); + let m = m.into_repr(); let mask = !(1u64 << 63 | 1u64 << 62); assert_eq!(n[0], m[0], "First limb."); assert_eq!(n[1], m[1], "Second limb."); assert_eq!(n[2], m[2], "Third limb."); - assert_eq!(n[3] & mask, m[3] & mask, "Fourth limb with top bit masked."); + assert_eq!(n[3] & mask, m[3], "Fourth limb with top bit masked."); } } diff --git a/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs b/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs new file mode 100644 index 000000000..eeb16550d --- /dev/null +++ b/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs @@ -0,0 +1,378 @@ +use super::{Curve, Field, MultiExp, PrimeField}; +use crate::common::{Buffer, Deserial, Serial}; +use byteorder::{ByteOrder, LittleEndian}; +use curve25519_dalek::{ + constants::RISTRETTO_BASEPOINT_POINT, + ristretto::{CompressedRistretto, RistrettoPoint, VartimeRistrettoPrecomputation}, + scalar::Scalar, + traits::{Identity, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}, +}; +use std::{ + borrow::Borrow, + ops::{AddAssign, MulAssign, Neg, SubAssign}, +}; + +/// A wrapper to make it possible to implement external traits +/// and to avoid clashes with blacket implementations. +#[derive(Clone, Copy, Debug, PartialEq, Eq, derive_more::From)] +pub struct RistrettoScalar(Scalar); + +impl Serial for RistrettoScalar { + fn serial(&self, out: &mut B) { + let res: &[u8; 32] = self.0.as_bytes(); + out.write_all(res) + .expect("Writing to a buffer should not fail."); + } +} + +impl Deserial for RistrettoScalar { + fn deserial(source: &mut R) -> crate::common::ParseResult { + let mut buf: [u8; 32] = [0; 32]; + source.read_exact(&mut buf)?; + let res = Scalar::from_canonical_bytes(buf).ok_or(anyhow::anyhow!( + "Deserialization failed! Not a field value!" + ))?; + Ok(res.into()) + } +} + +impl Field for RistrettoScalar { + fn random(rng: &mut R) -> Self { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Scalar::from_bytes_mod_order_wide(&scalar_bytes).into() + } + + fn zero() -> Self { Scalar::zero().into() } + + fn one() -> Self { Scalar::one().into() } + + fn is_zero(&self) -> bool { self.0 == Self::zero().0 } + + fn square(&mut self) { self.0.mul_assign(self.0) } + + fn double(&mut self) { self.0.add_assign(self.0) } + + fn negate(&mut self) { + let v = self.0.neg(); + self.0 = v; + } + + fn add_assign(&mut self, other: &Self) { self.0.add_assign(other.0) } + + fn sub_assign(&mut self, other: &Self) { self.0.sub_assign(other.0) } + + fn mul_assign(&mut self, other: &Self) { self.0.mul_assign(other.0) } + + fn inverse(&self) -> Option { + if self.is_zero() { + None + } else { + Some(self.0.invert().into()) + } + } +} + +impl PrimeField for RistrettoScalar { + // Taken from `curve25519-dalek` v.4.1.1 that implements `ff::PrimeField` + const CAPACITY: u32 = 252; + // Taken from `curve25519-dalek` v.4.1.1 that implements `ff::PrimeField`` + const NUM_BITS: u32 = 253; + + fn into_repr(self) -> Vec { + let mut vec: Vec = Vec::new(); + let bytes: [u8; 32] = self.0.to_bytes(); + for chunk in bytes.chunks_exact(8) { + // The chunk size is always 8 and there is no remainder after chunking, since + // the representation is a 32-byte array. That is why it is safe to + // unwrap here. + let x: [u8; 8] = chunk.try_into().unwrap(); + let x_64 = u64::from_le_bytes(x); + vec.push(x_64); + } + vec + } + + fn from_repr(r: &[u64]) -> Result { + let tmp: [u64; 4] = r + .try_into() + .map_err(|_| super::CurveDecodingError::NotInField(format!("{:?}", r)))?; + let mut s_bytes = [0u8; 32]; + let mut offset = 0; + for x in tmp { + let max = offset + 8; + LittleEndian::write_u64(&mut s_bytes[offset..max], x); + offset = max; + } + let res = Scalar::from_canonical_bytes(s_bytes).ok_or( + super::CurveDecodingError::NotInField(format!("{:?}", s_bytes)), + )?; + Ok(res.into()) + } +} + +impl Serial for RistrettoPoint { + fn serial(&self, out: &mut B) { + let compressed_point = self.compress(); + let res: &[u8; 32] = compressed_point.as_bytes(); + out.write_all(res) + .expect("Writing to a buffer should not fail."); + } +} + +impl Deserial for RistrettoPoint { + fn deserial(source: &mut R) -> crate::common::ParseResult { + let mut buf: [u8; 32] = [0; 32]; + source.read_exact(&mut buf)?; + let res = CompressedRistretto::from_slice(&buf) + .decompress() + .ok_or(anyhow::anyhow!("Failed!"))?; + Ok(res) + } +} + +impl Curve for RistrettoPoint { + type MultiExpType = RistrettoMultiExpNoPrecompute; + type Scalar = RistrettoScalar; + + const GROUP_ELEMENT_LENGTH: usize = 32; + const SCALAR_LENGTH: usize = 32; + + fn zero_point() -> Self { Self::identity() } + + fn one_point() -> Self { RISTRETTO_BASEPOINT_POINT } + + fn is_zero_point(&self) -> bool { self == &Self::zero_point() } + + fn inverse_point(&self) -> Self { -self } + + // A doubling operation on the Ristretto representation is not available + // directly. Moreover, v4.1.1 of `curve25519-dalek` implements `double()` + // using addition. + // https://docs.rs/curve25519-dalek/4.1.1/src/curve25519_dalek/ristretto.rs.html#1203-1205 + fn double_point(&self) -> Self { self + self } + + fn plus_point(&self, other: &Self) -> Self { self + other } + + fn minus_point(&self, other: &Self) -> Self { self - other } + + fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { self * scalar.0 } + + fn bytes_to_curve_unchecked( + source: &mut R, + ) -> anyhow::Result { + let mut buf: [u8; 32] = [0; 32]; + source.read_exact(&mut buf)?; + let res = CompressedRistretto::from_slice(&buf) + .decompress() + .ok_or(anyhow::anyhow!("Failed!"))?; + Ok(res) + } + + fn generate(rng: &mut R) -> Self { + let mut uniform_bytes = [0u8; 64]; + rng.fill_bytes(&mut uniform_bytes); + + RistrettoPoint::from_uniform_bytes(&uniform_bytes) + } + + fn generate_scalar(rng: &mut R) -> Self::Scalar { Self::Scalar::random(rng) } + + fn scalar_from_u64(n: u64) -> Self::Scalar { Scalar::from(n).into() } + + fn scalar_from_bytes>(bs: A) -> Self::Scalar { + // Traverse at most 4 8-byte chunks, for a total of 256 bits. + // The top-most four bits in the last chunk are set to 0. + let mut fr = [0u64; 4]; + for (i, chunk) in bs.as_ref().chunks(8).take(4).enumerate() { + let mut v = [0u8; 8]; + v[..chunk.len()].copy_from_slice(chunk); + fr[i] = u64::from_le_bytes(v); + } + // unset four topmost bits in the last u64 limb. + fr[3] &= !(1u64 << 63 | 1u64 << 62 | 1u64 << 61 | 1u64 << 60); + ::from_repr(&fr) + .expect("The scalar with top two bits erased should be valid.") + } + + fn hash_to_group(m: &[u8]) -> Self { + RistrettoPoint::hash_from_bytes::(m) + } +} + +/// An instance of multiexp algorithm from the Dalek library that uses +/// precomputed table of points. Precomputing is slow, so it makes sense to use +/// this implementation when one wants to share the precomputed table with many +/// subsequent computations. For our current use cases it seems not relevant. +impl MultiExp for VartimeRistrettoPrecomputation { + type CurvePoint = RistrettoPoint; + + fn new>(gs: &[X]) -> Self { + ::new(gs.iter().map(|p| p.borrow())) + } + + fn multiexp::Scalar>>( + &self, + exps: &[X], + ) -> Self::CurvePoint { + self.vartime_multiscalar_mul(exps.iter().map(|p| p.borrow().0)) + } +} + +/// An instance of multiexp algorithm from the Dalek library. +/// It is instantiated with points, but no precomputations is done. +/// This way, it follows the same interface as our generic multiexp. +pub struct RistrettoMultiExpNoPrecompute { + points: Vec, +} + +impl MultiExp for RistrettoMultiExpNoPrecompute { + type CurvePoint = RistrettoPoint; + + fn new>(gs: &[X]) -> Self { + Self { + points: gs.iter().map(|x| *x.borrow()).collect(), + } + } + + fn multiexp::Scalar>>( + &self, + exps: &[X], + ) -> Self::CurvePoint { + Self::CurvePoint::vartime_multiscalar_mul(exps.iter().map(|p| p.borrow().0), &self.points) + } +} + +/// In the tests we focus on the functionality related to conversion form/to +/// bytes or other representations. We do not test field/group operations here +/// since we delegate this functionality to the `curve25519-dalek` +/// implementation, which features its own test suite. +#[cfg(test)] +pub(crate) mod tests { + use super::{RistrettoScalar, *}; + use crate::common::*; + use curve25519_dalek::ristretto::RistrettoPoint; + use rand::Rng; + use rand_core::RngCore; + use std::io::Cursor; + + /// Test serialization for scalars + #[test] + fn test_scalar_serialization() { + let mut csprng = rand::thread_rng(); + for _ in 0..1000 { + let mut out = Vec::::new(); + let scalar = RistrettoScalar::random(&mut csprng); + scalar.serial(&mut out); + let scalar_res = RistrettoScalar::deserial(&mut Cursor::new(out)); + assert!(scalar_res.is_ok()); + assert_eq!(scalar, scalar_res.unwrap()); + } + } + + /// Test serialization for curve points + #[test] + fn test_point_serialization() { + let mut csprng = rand::thread_rng(); + for _ in 0..1000 { + let mut out = Vec::::new(); + let point = RistrettoPoint::generate(&mut csprng); + point.serial(&mut out); + let point_res = RistrettoPoint::deserial(&mut Cursor::new(out)); + assert!(point_res.is_ok()); + assert_eq!(point, point_res.unwrap()); + } + } + + /// Turn scalar elements into representations and back again, and compare. + #[test] + fn test_into_from_rep() { + let mut csprng = rand::thread_rng(); + for _ in 0..1000 { + let scalar = RistrettoScalar::random(&mut csprng); + let scalar_vec64 = scalar.into_repr(); + let scalar_res = RistrettoScalar::from_repr(&scalar_vec64); + assert!(scalar_res.is_ok()); + assert_eq!(scalar, scalar_res.unwrap()); + } + } + + /// Turn curve points into representations and back again, and compare. + #[test] + fn test_point_byte_conversion_unchecked() { + let mut csprng = rand::thread_rng(); + for _ in 0..1000 { + let point = RistrettoPoint::generate(&mut csprng); + let bytes = to_bytes(&point); + let point_res = RistrettoPoint::bytes_to_curve_unchecked(&mut Cursor::new(&bytes)); + assert!(point_res.is_ok()); + assert_eq!(point, point_res.unwrap()); + } + } + + /// Test that `into_repr()` correclty converts a scalar constructed from a + /// byte array to an array of limbs with least significant digits first. + #[test] + fn test_into() { + let s: RistrettoScalar = Scalar::from_canonical_bytes([ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, + 0, 0, 0, 0, 0, 0, 0, 0, + ]) + .expect("Expected a valid scalar") + .into(); + assert_eq!(s.into_repr(), [1u64, 0u64, u64::MAX - 1, 0u64]); + } + + // Check that scalar_from_bytes for ed25519 works on small values. + #[test] + fn test_scalar_from_bytes_small() { + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + let n = ::random(&mut rng); + let bytes = to_bytes(&n); + let m = ::scalar_from_bytes(&bytes); + // Make sure that n and m only differ in the topmost bits; + // `scalar_from_bytes_helper` resets the topmost bits to zeros. + let n = n.into_repr(); + let m = m.into_repr(); + let mask = !(1u64 << 63 | 1u64 << 62 | 1u64 << 61 | 1u64 << 60); + assert_eq!(n[0], m[0], "First limb."); + assert_eq!(n[1], m[1], "Second limb."); + assert_eq!(n[2], m[2], "Third limb."); + // It is unlikely that the limbs will differ even without masking, because the + // difference between the max number for `RistrettoScalar::CAPACITY` and the + // curve order is quite small. We, however, keep the mask here, + // because we're interesed in lower bytes in this test. + assert_eq!(n[3] & mask, m[3], "Fourth limb with top bit masked."); + } + } + + /// Test that everything that exeeds `RistrettoScalar::CAPACITY` is ignored + /// by `Curve::scalar_from_bytes()` + #[test] + fn test_scalar_from_bytes_big() { + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + // First, we generate 31 random bytes. + let mut lower_bytes: [u8; 31] = [0u8; 31]; + rng.fill_bytes(&mut lower_bytes); + let mut fits_capacity_bytes = [0u8; 32]; + // Next, we create a byte array that is filled with random lower bytes, the last + // byte is in [0; 15], that is, of the form 0b0000XXXX (big-endian). + fits_capacity_bytes[0..31].copy_from_slice(&lower_bytes); + let n = rng.gen_range(0, 16); + fits_capacity_bytes[31] = n; + let fits_capacity = ::scalar_from_bytes(fits_capacity_bytes); + let i = rng.gen_range(1, 16); + // Now, we create a byte array from lower bytes with the last byte being number + // that is guaranteed to exceed `RistrettoScalar::CAPACITY`. + let mut bytes: [u8; 32] = [0u8; 32]; + bytes[0..31].copy_from_slice(&lower_bytes); + // Add 0bXXXX0000 that leaves the first four bits untouched. + bytes[31] = n + (i << 4); + let over_capacity = ::scalar_from_bytes(bytes); + // Check that four topmost bits are ignored. + assert_eq!(fits_capacity, over_capacity); + } + } +} diff --git a/rust-src/concordium_base/src/curve_arithmetic/mod.rs b/rust-src/concordium_base/src/curve_arithmetic/mod.rs index 4a566a145..d70dd52d8 100644 --- a/rust-src/concordium_base/src/curve_arithmetic/mod.rs +++ b/rust-src/concordium_base/src/curve_arithmetic/mod.rs @@ -3,21 +3,100 @@ mod bls12_381_g1hash; mod bls12_381_g2hash; mod bls12_381_instance; +mod ed25519_instance; pub mod secret_value; pub use secret_value::{Secret, Value}; use crate::common::{Serial, Serialize}; use byteorder::ReadBytesExt; -use ff::{Field, PrimeField}; use rand::*; -use std::{borrow::Borrow, fmt::Debug}; +use std::{borrow::Borrow, fmt, fmt::Debug}; use thiserror::Error; #[derive(Error, Debug)] pub enum CurveDecodingError { #[error("Not a point on the curve.")] NotOnCurve, + #[error("{0} is not a field element.")] + NotInField(String), +} + +/// This trait represents an element of a field. +/// The trait essentially copies `ff::Field` from `v0.5`. +pub trait Field: Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug { + /// Returns an element chosen uniformly at random using a user-provided RNG. + fn random(rng: &mut R) -> Self; + + /// Returns the zero element of the field, the additive identity. + fn zero() -> Self; + + /// Returns the one element of the field, the multiplicative identity. + fn one() -> Self; + + /// Returns true iff this element is zero. + fn is_zero(&self) -> bool; + + /// Squares this element. + fn square(&mut self); + + /// Doubles this element. + fn double(&mut self); + + /// Negates this element. + fn negate(&mut self); + + /// Adds another element to this element. + fn add_assign(&mut self, other: &Self); + + /// Subtracts another element from this element. + fn sub_assign(&mut self, other: &Self); + + /// Multiplies another element by this element. + fn mul_assign(&mut self, other: &Self); + + /// Computes the multiplicative inverse of this element, if nonzero. + fn inverse(&self) -> Option; + + /// Exponentiates this element by a number represented with `u64` limbs, + /// least significant digit first. This operation is variable time with + /// respect to `self`, for all exponent. + fn pow>(&self, exp: S) -> Self { + // Note: this implementations is + // copied from the `ff` crate's trait method `ff::Field::pow_vartime()`. + // https://docs.rs/ff/0.13.0/src/ff/lib.rs.html#178-191 + let mut res = Self::one(); + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + res.square(); + + if ((*e >> i) & 1) == 1 { + res.mul_assign(self); + } + } + } + + res + } +} + +/// This is an extension of the `Field` trait that adds some constants decribing +/// the element size and operations for converting to/from big integer +/// representation (an array of `u64` limbs.) +pub trait PrimeField: Field { + /// How many bits are needed to represent an element of this field. + const NUM_BITS: u32; + + /// How many bits of information can be reliably stored in the field + /// element. + const CAPACITY: u32; + + /// Get a big integer representation with least significant digit first. + fn into_repr(self) -> Vec; + + /// Get a prime field element from its big integer representaion (least + /// significant digit first). + fn from_repr(_: &[u64]) -> Result; } /// A relatively large trait that covers what is needed to perform constructions @@ -27,11 +106,14 @@ pub enum CurveDecodingError { pub trait Curve: Serialize + Copy + Clone + Sized + Send + Sync + Debug + PartialEq + Eq + 'static { /// The prime field of the group order size. - type Scalar: PrimeField + Field + Serialize; + type Scalar: PrimeField + Serialize; + type MultiExpType: MultiExp; /// Size in bytes of elements of the [Curve::Scalar] field. const SCALAR_LENGTH: usize; /// Size in bytes of group elements when serialized. const GROUP_ELEMENT_LENGTH: usize; + /// Create new instance of multiexp algorithm given some initial points. + fn new_multiexp>(gs: &[X]) -> Self::MultiExpType { Self::MultiExpType::new(gs) } /// Unit for the group operation. fn zero_point() -> Self; /// Chosen generator of the group. @@ -82,6 +164,158 @@ pub trait Curve: fn hash_to_group(m: &[u8]) -> Self; } +/// An abstraction over a multiexp algorithm. +pub trait MultiExp { + type CurvePoint: Curve; + + /// Create new algorithm instance by providing initial points. + /// Can be used to precompute a lookup table. + // NOTE: this method does not take `window_size` as a parameter. + // Some libraries do not expose `window_size`, so it is left to a + // concrete implementation to take additional configuration parameters. + fn new>(gs: &[X]) -> Self; + + /// Multiexp algorithm that uses points provided at the instantiation step + /// and scalars provided as a parameter. + fn multiexp::Scalar>>( + &self, + exps: &[X], + ) -> Self::CurvePoint; +} + +pub struct GenericMultiExp { + table: Vec>, + window_size: usize, +} + +impl GenericMultiExp { + // This number is based on the benchmark in benches/multiexp_bench.rs + const DEFAULT_WINDOW_SIZE: usize = 4; + + /// Compute the table of powers that can be used `multiexp`. + pub fn new>(gs: &[X], window_size: usize) -> Self { + let k = gs.len(); + let mut table = Vec::with_capacity(k); + for g in gs.iter() { + let sq = g.borrow().plus_point(g.borrow()); + let mut tmp = *g.borrow(); + // All of the odd exponents, between 1 and 2^w. + let num_exponents = 1 << (window_size - 1); + let mut exps = Vec::with_capacity(num_exponents); + exps.push(tmp); + for _ in 1..num_exponents { + tmp = tmp.plus_point(&sq); + exps.push(tmp); + } + table.push(exps); + } + Self { table, window_size } + } +} + +impl MultiExp for GenericMultiExp { + type CurvePoint = C; + + /// Construct new instance of a lookup table with the default window size. + // fn new, I: IntoIterator>(gs: I) -> Self { + fn new>(gs: &[X]) -> Self { Self::new(gs, Self::DEFAULT_WINDOW_SIZE) } + + /// This implements the WNAF method from + /// + /// + /// Assumes: + /// - the length of input is the same as the table length + /// - window size at least 1 + /// - window size < 62 + fn multiexp::Scalar>>( + &self, + exps: &[X], + ) -> Self::CurvePoint { + // Compute the wnaf + let window_size_plus1 = self.window_size + 1; + let k = exps.len(); + assert!(window_size_plus1 >= 2); + assert!(window_size_plus1 < 63); + + let mut wnaf = Vec::with_capacity(k); + + // The computation of the wnaf table here is a modification of the + // implementation in + // Compared to the high-level algorithm described in https://link.springer.com/content/pdf/10.1007%2F3-540-45537-X_13.pdf + // this avoids any field arithmetic and operates directly on the bit + // representation of the scalars, leading to a substantial performance + // improvement. + let width = 1u64 << window_size_plus1; + let window_mask = width - 1; + + for c in exps.iter() { + let mut pos = 0; + let mut carry = 0; + let repr_limbs = c.borrow().into_repr(); + let mut v = Vec::new(); + let num_bits = repr_limbs.len() * 64; + while pos < num_bits { + // Construct a buffer of bits of the scalar, starting at bit `pos` + let u64_idx = pos / 64; + let bit_idx = pos % 64; + let cur_u64 = repr_limbs[u64_idx]; + let bit_buf = if bit_idx + window_size_plus1 < 64 { + // This window's bits are contained in a single u64 + cur_u64 >> bit_idx + } else { + let next_u64 = repr_limbs.get(u64_idx + 1).copied().unwrap_or(0); + // Combine the current u64's bits with the bits from the next u64 + (cur_u64 >> bit_idx) | (next_u64 << (64 - bit_idx)) + }; + + // Add the carry into the current window + let window_val = carry + (bit_buf & window_mask); + + if window_val & 1 == 0 { + // If the window value is even, preserve the carry and emit 0. + // Why is the carry preserved? + // If carry == 0 and window_val & 1 == 0, then the next carry should be 0 + // If carry == 1 and window_val & 1 == 0, then bit_buf & 1 == 1 so the next + // carry should be 1 + v.push(0); + pos += 1; + } else { + v.push( + if window_val < width / 2 { + carry = 0; + window_val as i64 + } else { + carry = 1; + (window_val as i64).wrapping_sub(width as i64) + }, + ); + v.extend(std::iter::repeat(0).take(window_size_plus1 - 1)); + pos += window_size_plus1; + } + } + wnaf.push(v); + } + + // evaluate using the precomputed table + let mut a = C::zero_point(); + for j in (0..=C::Scalar::NUM_BITS as usize).rev() { + a = a.double_point(); + for (wnaf_i, table_i) in wnaf.iter().zip(self.table.iter()) { + match wnaf_i.get(j) { + Some(&ge) if ge > 0 => { + a = a.plus_point(&table_i[(ge / 2) as usize]); + } + Some(&ge) if ge < 0 => { + a = a.minus_point(&table_i[((-ge) / 2) as usize]); + } + _ => (), + } + } + } + a + } +} + /// A pairing friendly curve is a collection of two groups and a pairing /// function. The groups must be of prime order. pub trait Pairing: Sized + 'static + Clone { @@ -95,8 +329,6 @@ pub trait Pairing: Sized + 'static + Clone { type G1Prepared; /// An auxiliary type that is used as an input to the pairing function. type G2Prepared; - /// Field of the size of G1 and G2. - type BaseField: PrimeField; /// The target of the pairing function. The pairing function actually maps /// to a subgroup of the same order as G1 and G2, but this subgroup is /// not exposed here and is generally not useful. It is subgroup of the @@ -171,152 +403,15 @@ pub trait Pairing: Sized + 'static + Clone { } } -/// Like 'multiexp_worker', but computes a reasonable window size automatically. +/// Calls a multiexp algorithm for a curve. +/// The function combines instantiation of an algorithm implementation and +/// computation. #[inline(always)] -pub fn multiexp>(gs: &[X], exps: &[C::Scalar]) -> C { - // This number is based on the benchmark in benches/multiexp_bench.rs - let window_size = 4; - multiexp_worker(gs, exps, window_size) -} - -/// This implements the WNAF method from -/// -/// -/// Assumes: -/// - the lengths of inputs are the same -/// - window size at least 1 -/// - window_size < 62 -pub fn multiexp_worker>( - gs: &[X], - exps: &[C::Scalar], - window_size: usize, -) -> C { - // Compute the wnaf - - let k = exps.len(); - assert_eq!(gs.len(), k); - assert!(window_size >= 1); - assert!(window_size < 62); - - let table = multiexp_table(gs, window_size); - - multiexp_worker_given_table(exps, &table, window_size) -} - -/// This function assumes the same properties about the inputs as -/// `multiexp_worker`, as well as the fact that the table corresponds to the -/// window-size and the given inputs. -/// -/// See for what it means -/// for the table to be computed correctly. -pub fn multiexp_worker_given_table( - exps: &[C::Scalar], - table: &[Vec], - window: usize, -) -> C { - // Compute the wnaf - let window_plus1 = window + 1; - let k = exps.len(); - assert!(window_plus1 >= 2); - assert!(window_plus1 < 63); - - let mut wnaf = Vec::with_capacity(k); - - // The computation of the wnaf table here is a modification of the - // implementation in - // Compared to the high-level algorithm described in https://link.springer.com/content/pdf/10.1007%2F3-540-45537-X_13.pdf - // this avoids any field arithmetic and operates directly on the bit - // representation of the scalars, leading to a substantial performance - // improvement. - let width = 1u64 << window_plus1; - let window_mask = width - 1; - - for c in exps.iter() { - let mut pos = 0; - let mut carry = 0; - let repr = c.into_repr(); - let repr_limbs = repr.as_ref(); - let mut v = Vec::new(); - let num_bits = repr_limbs.len() * 64; - while pos < num_bits { - // Construct a buffer of bits of the scalar, starting at bit `pos` - let u64_idx = pos / 64; - let bit_idx = pos % 64; - let cur_u64 = repr_limbs[u64_idx]; - let bit_buf = if bit_idx + window_plus1 < 64 { - // This window's bits are contained in a single u64 - cur_u64 >> bit_idx - } else { - let next_u64 = repr_limbs.get(u64_idx + 1).copied().unwrap_or(0); - // Combine the current u64's bits with the bits from the next u64 - (cur_u64 >> bit_idx) | (next_u64 << (64 - bit_idx)) - }; - - // Add the carry into the current window - let window_val = carry + (bit_buf & window_mask); - - if window_val & 1 == 0 { - // If the window value is even, preserve the carry and emit 0. - // Why is the carry preserved? - // If carry == 0 and window_val & 1 == 0, then the next carry should be 0 - // If carry == 1 and window_val & 1 == 0, then bit_buf & 1 == 1 so the next - // carry should be 1 - v.push(0); - pos += 1; - } else { - v.push( - if window_val < width / 2 { - carry = 0; - window_val as i64 - } else { - carry = 1; - (window_val as i64).wrapping_sub(width as i64) - }, - ); - v.extend(std::iter::repeat(0).take(window_plus1 - 1)); - pos += window_plus1; - } - } - wnaf.push(v); - } - - // evaluate using the precomputed table - let mut a = C::zero_point(); - for j in (0..=C::Scalar::NUM_BITS as usize).rev() { - a = a.double_point(); - for (wnaf_i, table_i) in wnaf.iter().zip(table.iter()) { - match wnaf_i.get(j) { - Some(&ge) if ge > 0 => { - a = a.plus_point(&table_i[(ge / 2) as usize]); - } - Some(&ge) if ge < 0 => { - a = a.minus_point(&table_i[((-ge) / 2) as usize]); - } - _ => (), - } - } - } - a -} - -/// Compute the table of powers that can be used `multiexp_worker_given_table`. -pub fn multiexp_table>(gs: &[X], window_size: usize) -> Vec> { - let k = gs.len(); - let mut table = Vec::with_capacity(k); - for g in gs.iter() { - let sq = g.borrow().plus_point(g.borrow()); - let mut tmp = *g.borrow(); - // All of the odd exponents, between 1 and 2^w. - let num_exponents = 1 << (window_size - 1); - let mut exps = Vec::with_capacity(num_exponents); - exps.push(tmp); - for _ in 1..num_exponents { - tmp = tmp.plus_point(&sq); - exps.push(tmp); - } - table.push(exps); - } - table +pub fn multiexp(gs: &[X], exps: &[C::Scalar]) -> C +where + C: Curve, + X: Borrow, { + C::new_multiexp(gs).multiexp(exps) } #[cfg(test)] diff --git a/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs b/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs index 2c6b44226..60d38b1f5 100644 --- a/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs +++ b/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs @@ -3,7 +3,6 @@ //! A thin wrapper around a scalar to indicate that it is a secret value. use crate::{common::*, curve_arithmetic::*}; -use ff::Field; use rand::*; use std::{ ops::{Deref, Drop}, @@ -15,7 +14,7 @@ use std::{ /// A generic wrapper for a secret that implements a zeroize on drop. /// Other types are expected to wrap this in more convenient interfaces. /// Ideally the constraint would be Default, but fields we have do not implement -/// it, so we cannot use it at the moment. Hence the temporary hack of 'F: +/// it, so we cannot use it at the moment. Hence the temporary hack of 'T: /// Field'. #[repr(transparent)] #[derive(Debug, PartialEq, Eq, Serialize)] diff --git a/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs b/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs index 888c1a779..ed51efe9d 100644 --- a/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs +++ b/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs @@ -3,9 +3,8 @@ use super::errors::{InternalError::DivisionByZero, *}; use crate::{ common::*, - curve_arithmetic::{Curve, Secret, Value}, + curve_arithmetic::{Curve, Field, Secret, Value}, }; -use ff::Field; use rand::*; use std::rc::Rc; diff --git a/rust-src/concordium_base/src/elgamal/mod.rs b/rust-src/concordium_base/src/elgamal/mod.rs index 111b8a638..965943f04 100644 --- a/rust-src/concordium_base/src/elgamal/mod.rs +++ b/rust-src/concordium_base/src/elgamal/mod.rs @@ -8,8 +8,7 @@ mod secret; pub use self::{cipher::*, message::*, public::*, secret::*}; -use crate::curve_arithmetic::{Curve, Value}; -use ff::{Field, PrimeField}; +use crate::curve_arithmetic::{Curve, Field, PrimeField, Value}; use rand::*; /// Possible chunk sizes in bits. @@ -93,9 +92,8 @@ pub fn value_to_chunks(val: &C::Scalar, chunk_size: ChunkSize) -> Vec< let size = usize::from(u8::from(chunk_size)); let n = C::SCALAR_LENGTH / size; let mut out = Vec::with_capacity(n); - let repr = val.into_repr(); - let u64_chunks = repr.as_ref(); - for &chunk in u64_chunks { + let u64_chunks = val.into_repr(); + for chunk in u64_chunks { out.extend( chunk_size .u64_to_chunks(chunk) @@ -123,7 +121,7 @@ pub fn chunks_to_value(chunks: &[Value], chunk_size: ChunkSize) -> // get the u64 encoded in this chunk section let v = chunk_size.chunks_to_u64(chunk_section.iter().map(|chunk| { let repr = chunk.into_repr(); - repr.as_ref()[0] + repr[0] })); let mut val = C::scalar_from_u64(v); val.mul_assign(&factor); @@ -210,7 +208,6 @@ pub fn decrypt_from_chunks_given_table( #[cfg(test)] mod tests { use super::*; - use ff::Field; use pairing::bls12_381::{G1, G2}; use rand::{rngs::ThreadRng, Rng}; diff --git a/rust-src/concordium_base/src/elgamal/secret.rs b/rust-src/concordium_base/src/elgamal/secret.rs index 492e0c0fa..edb1c2ad2 100644 --- a/rust-src/concordium_base/src/elgamal/secret.rs +++ b/rust-src/concordium_base/src/elgamal/secret.rs @@ -4,10 +4,9 @@ use super::{cipher::*, message::*}; use crate::{ common::*, - curve_arithmetic::{Curve, Value}, + curve_arithmetic::{Curve, Field, Value}, }; use anyhow::{bail, Result}; -use ff::Field; use rand::*; use std::collections::HashMap; @@ -127,9 +126,9 @@ impl SecretKey { pub fn decrypt_exponent_slow(&self, c: &Cipher) -> Value { let m = self.decrypt(c).value; - let mut a = ::zero(); + let mut a = C::Scalar::zero(); let mut i = C::zero_point(); - let field_one = ::one(); + let field_one = C::Scalar::one(); while m != i { i = i.plus_point(&self.generator); a.add_assign(&field_one); diff --git a/rust-src/concordium_base/src/id/account_holder.rs b/rust-src/concordium_base/src/id/account_holder.rs index 77d4746eb..358a8d48d 100644 --- a/rust-src/concordium_base/src/id/account_holder.rs +++ b/rust-src/concordium_base/src/id/account_holder.rs @@ -7,7 +7,7 @@ use crate::{ range_proof::{prove_given_scalars as bulletprove, prove_less_than_or_equal, RangeProof}, }, common::types::TransactionTime, - curve_arithmetic::{Curve, Pairing}, + curve_arithmetic::{Curve, Field, Pairing}, dodis_yampolskiy_prf as prf, elgamal::{multicombine, Cipher}, pedersen_commitment::{ @@ -19,7 +19,6 @@ use crate::{ }, }; use anyhow::{bail, ensure}; -use ff::Field; use itertools::izip; use rand::*; use std::collections::{btree_map::BTreeMap, hash_map::HashMap, BTreeSet}; @@ -400,7 +399,8 @@ fn generate_pio_common<'a, P: Pairing, C: Curve, R: ran let u8_chunk_size = u8::from(CHUNK_SIZE); let two_chunksize = C::scalar_from_u64(1 << u8_chunk_size); let mut power_of_two = C::Scalar::one(); - let mut scalars = Vec::with_capacity(item.encrypted_share.len()); + let mut scalars: Vec<

::ScalarField> = + Vec::with_capacity(item.encrypted_share.len()); for _ in 0..item.encrypted_share.len() { scalars.push(power_of_two); power_of_two.mul_assign(&two_chunksize); diff --git a/rust-src/concordium_base/src/id/id_verifier.rs b/rust-src/concordium_base/src/id/id_verifier.rs index d1dce9095..9114a9e86 100644 --- a/rust-src/concordium_base/src/id/id_verifier.rs +++ b/rust-src/concordium_base/src/id/id_verifier.rs @@ -13,14 +13,13 @@ use crate::bulletproofs::{ use super::id_proof_types::*; use crate::{ - curve_arithmetic::Curve, + curve_arithmetic::{Curve, Field}, pedersen_commitment::{ Commitment, CommitmentKey as PedersenKey, Randomness as PedersenRandomness, Value, }, random_oracle::RandomOracle, sigma_protocols::{common::verify as sigma_verify, dlog::Dlog}, }; -use ff::Field; use sha2::{Digest, Sha256}; /// Function for opening an attribute inside a commitment. The arguments are diff --git a/rust-src/concordium_base/src/id/identity_provider.rs b/rust-src/concordium_base/src/id/identity_provider.rs index fa63f74be..e0b7fdfa8 100644 --- a/rust-src/concordium_base/src/id/identity_provider.rs +++ b/rust-src/concordium_base/src/id/identity_provider.rs @@ -4,13 +4,12 @@ use super::{id_proof_types::ProofVersion, secret_sharing::Threshold, types::*, u use crate::{ bulletproofs::range_proof::verify_efficient, common::{to_bytes, types::TransactionTime}, - curve_arithmetic::{multiexp, Curve, Pairing}, + curve_arithmetic::{multiexp, Curve, Field, Pairing}, elgamal::multicombine, pedersen_commitment::{Commitment, CommitmentKey}, random_oracle::RandomOracle, sigma_protocols::{com_enc_eq, com_eq, com_eq_different_groups, common::*, dlog}, }; -use ff::Field; use rand::*; use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, BTreeSet}; diff --git a/rust-src/concordium_base/src/id/secret_sharing.rs b/rust-src/concordium_base/src/id/secret_sharing.rs index 6af02d569..6188a5ca1 100644 --- a/rust-src/concordium_base/src/id/secret_sharing.rs +++ b/rust-src/concordium_base/src/id/secret_sharing.rs @@ -1,7 +1,10 @@ //! Implementation of Shamir secret sharing. -use crate::{common::*, curve_arithmetic::*, pedersen_commitment::Value as PedersenValue}; +use crate::{ + common::*, + curve_arithmetic::{Curve, Field}, + pedersen_commitment::Value as PedersenValue, +}; use anyhow::bail; -use ff::Field; use rand::*; use serde_json::{json, Value}; use std::convert::TryFrom; diff --git a/rust-src/concordium_base/src/id/types.rs b/rust-src/concordium_base/src/id/types.rs index dd2169bc9..55bf2ecf7 100644 --- a/rust-src/concordium_base/src/id/types.rs +++ b/rust-src/concordium_base/src/id/types.rs @@ -33,7 +33,6 @@ use derive_more::*; use ed25519_dalek as ed25519; use ed25519_dalek::Verifier; use either::Either; -use ff::Field; use hex::{decode, encode}; use serde::{ de, de::Visitor, ser::SerializeMap, Deserialize as SerdeDeserialize, Deserializer, diff --git a/rust-src/concordium_base/src/id/utils.rs b/rust-src/concordium_base/src/id/utils.rs index 1d7e0f6ba..a541f219c 100644 --- a/rust-src/concordium_base/src/id/utils.rs +++ b/rust-src/concordium_base/src/id/utils.rs @@ -7,14 +7,13 @@ use crate::{ types::{KeyIndex, TransactionTime}, ParseResult, }, - curve_arithmetic::{multiexp, Curve, Pairing, Value}, + curve_arithmetic::{multiexp, Curve, Field, Pairing, PrimeField, Value}, elgamal::*, pedersen_commitment::Commitment, }; use anyhow::bail; use ed25519_dalek::Verifier; use either::Either; -use ff::{Field, PrimeField}; use rand::*; use sha2::{Digest, Sha256}; use std::collections::{btree_map::BTreeMap, BTreeSet}; @@ -128,8 +127,8 @@ pub fn encode_tags<'a, F: PrimeField, I: std::iter::IntoIterator(ars: &BTreeSet) -> Option> { } else { u64::from(ar_id) << 32 }; - f.as_mut()[i / 2] |= x; + f[i / 2] |= x; } - let mut scalar = F::from_repr(f).ok()?; + let mut scalar = F::from_repr(f.as_slice()).ok()?; // shift one bit left. scalar.mul_assign(&two); scalars.push(scalar) @@ -213,10 +212,10 @@ pub fn encode_public_credential_values( let ca: u32 = created_at.into(); let vt: u32 = valid_to.into(); let s = u64::from(vt) << 32 | u64::from(ca); - f.as_mut()[0] = s; // limbs in as_mut are little endian. + f[0] = s; // limbs are little endian. let threshold: u8 = threshold.into(); - f.as_mut()[1] = u64::from(threshold); - Ok(F::from_repr(f)?) + f[1] = u64::from(threshold); + Ok(F::from_repr(f.as_slice())?) } /// This function verifies that the signature inside diff --git a/rust-src/concordium_base/src/pedersen_commitment/randomness.rs b/rust-src/concordium_base/src/pedersen_commitment/randomness.rs index 7f72e13b5..dae67094e 100644 --- a/rust-src/concordium_base/src/pedersen_commitment/randomness.rs +++ b/rust-src/concordium_base/src/pedersen_commitment/randomness.rs @@ -5,8 +5,6 @@ use crate::{common::*, curve_arithmetic::*}; -use ff::Field; - use rand::*; use std::ops::Deref; diff --git a/rust-src/concordium_base/src/ps_sig/secret.rs b/rust-src/concordium_base/src/ps_sig/secret.rs index acd2cad08..17a07d9a5 100644 --- a/rust-src/concordium_base/src/ps_sig/secret.rs +++ b/rust-src/concordium_base/src/ps_sig/secret.rs @@ -10,8 +10,6 @@ use super::{ }; use crate::{common::*, curve_arithmetic::*}; -use ff::Field; - use rand::*; /// A secret key diff --git a/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs b/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs index 2190c81fd..6890df4ed 100644 --- a/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs +++ b/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs @@ -7,10 +7,9 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, random_oracle::{Challenge, RandomOracle}, }; -use ff::Field; use itertools::izip; use std::rc::Rc; diff --git a/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs b/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs index 378561d67..920c42d46 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs @@ -7,14 +7,13 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, elgamal::{ Cipher as ElGamalCipher, PublicKey as ElGamalPublicKey, Randomness as ElgamalRandomness, }, pedersen_commitment::{Commitment, CommitmentKey, Randomness as PedersenRandomness, Value}, random_oracle::RandomOracle, }; -use ff::Field; use rand::*; #[derive(Debug)] diff --git a/rust-src/concordium_base/src/sigma_protocols/com_eq.rs b/rust-src/concordium_base/src/sigma_protocols/com_eq.rs index 22c4b069e..95c9b82e6 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_eq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_eq.rs @@ -11,11 +11,10 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value}, random_oracle::RandomOracle, }; -use ff::Field; #[derive(Clone, Debug, Eq, PartialEq, Serialize, SerdeBase16Serialize)] pub struct Response { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs b/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs index c3706740f..960a40bfd 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs @@ -6,11 +6,10 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value}, random_oracle::RandomOracle, }; -use ff::Field; use rand::*; #[derive(Debug)] diff --git a/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs b/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs index 744826f12..ddd414619 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs @@ -15,7 +15,6 @@ use crate::{ ps_sig::{BlindedSignature, BlindingRandomness, PublicKey as PsSigPublicKey}, random_oracle::RandomOracle, }; -use ff::Field; use itertools::izip; use rand::*; diff --git a/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs b/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs index 2f0fe3fdb..12a92895c 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs @@ -16,11 +16,10 @@ use super::{ }; use crate::{ common::*, - curve_arithmetic::Curve, + curve_arithmetic::{Curve, Field}, pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value}, random_oracle::RandomOracle, }; -use ff::Field; #[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct Response { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_lin.rs b/rust-src/concordium_base/src/sigma_protocols/com_lin.rs index 89d5dc866..217d2f5bc 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_lin.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_lin.rs @@ -7,11 +7,10 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value}, random_oracle::{Challenge, RandomOracle}, }; -use ff::Field; use itertools::izip; pub struct ComLinSecret { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_mult.rs b/rust-src/concordium_base/src/sigma_protocols/com_mult.rs index 5f784c345..538a6c4e8 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_mult.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_mult.rs @@ -6,11 +6,10 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value}, random_oracle::{Challenge, RandomOracle}, }; -use ff::Field; use itertools::izip; pub struct ComMultSecret { diff --git a/rust-src/concordium_base/src/sigma_protocols/dlog.rs b/rust-src/concordium_base/src/sigma_protocols/dlog.rs index 0ed2070f1..5d8949bc9 100644 --- a/rust-src/concordium_base/src/sigma_protocols/dlog.rs +++ b/rust-src/concordium_base/src/sigma_protocols/dlog.rs @@ -5,10 +5,9 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{Curve, Value}, + curve_arithmetic::{Curve, Field, Value}, random_oracle::{Challenge, RandomOracle}, }; -use ff::Field; pub struct Dlog { /// Evaluated point. diff --git a/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs b/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs index 21aed59eb..ede9fc3d0 100644 --- a/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs +++ b/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs @@ -8,11 +8,10 @@ use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, random_oracle::{Challenge, RandomOracle}, sigma_protocols::{aggregate_dlog::*, common::*, dlog::*}, }; -use ff::Field; use itertools::izip; use std::rc::Rc; diff --git a/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs b/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs index 9f702492b..5efc601e7 100644 --- a/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs +++ b/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs @@ -54,13 +54,12 @@ use super::{ }; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, elgamal::ChunkSize, encrypted_transfers::types::CHUNK_SIZE, pedersen_commitment::{Randomness as PedersenRandomness, Value}, random_oracle::{Challenge, RandomOracle}, }; -use ff::Field; use itertools::izip; use std::rc::Rc; diff --git a/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs b/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs index 2bf219327..6198c8640 100644 --- a/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs @@ -6,11 +6,10 @@ use super::common::*; use crate::{ common::*, - curve_arithmetic::{multiexp, Curve}, + curve_arithmetic::{multiexp, Curve, Field}, pedersen_commitment::{Commitment, Value}, random_oracle::{Challenge, RandomOracle}, }; -use ff::Field; use itertools::izip; use std::collections::BTreeMap;