diff --git a/src/arithmetic/hashtocurve.rs b/src/arithmetic/hashtocurve.rs index c4c31069..84320817 100644 --- a/src/arithmetic/hashtocurve.rs +++ b/src/arithmetic/hashtocurve.rs @@ -6,24 +6,26 @@ use core::fmt::Debug; use core::marker::PhantomData; use subtle::ConstantTimeEq; -use super::{Curve, CurveAffine, FieldExt}; +use super::{Curve, CurveAffine, Field, FieldExt}; /// A method of hashing to an elliptic curve. -/// (If no isogeny is required, then C and I should be the same.) /// /// This is intended to conform to the work-in-progress Internet Draft /// [IRTF-CFRG-Hash-to-Curve](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html). -pub trait HashToCurve, C: CurveAffine> { +pub trait HashToCurve { + /// Curve that may or may not be isogenous to the target curve C. + type IsogenousCurve: Curve; + /// The MAP_ID of this method as specified in /// . fn map_id(&self) -> &str; /// A non-uniform map from a field element to the isogenous curve. - fn map_to_curve(&self, u: &C::Base) -> I::Projective; + fn map_to_curve(&self, u: &C::Base) -> Self::IsogenousCurve; /// The isogeny map from curve I to curve C. /// (If no isogeny is required, this should be the identity function.) - fn iso_map(&self, p: &I::Projective) -> C::Projective; + fn iso_map(&self, p: &Self::IsogenousCurve) -> C::Projective; /// The random oracle map. fn field_elements_to_curve(&self, u0: &C::Base, u1: &C::Base) -> C::Projective; @@ -42,9 +44,9 @@ pub trait HashToCurve, C: CurveAffine + 'static, + hasher: impl MessageHasher, ) -> Box C::Projective + '_> { - let domain_separation_tag = format!( + let domain_separation_tag: String = format!( "{}-{}_{}_{}_RO_", domain_prefix, C::CURVE_ID, @@ -53,7 +55,8 @@ pub trait HashToCurve, C: CurveAffine, C: CurveAffine + 'static, + hasher: impl MessageHasher, ) -> Box C::Projective + '_> { - let domain_separation_tag = format!( + let domain_separation_tag: String = format!( "{}-{}_{}_{}_NU_", domain_prefix, C::CURVE_ID, @@ -82,7 +85,8 @@ pub trait HashToCurve, C: CurveAffine, C: CurveAffine { +pub trait MessageHasher: 'static { /// The HASH_NAME of this message hasher as specified in /// . fn hash_name(&self) -> &str; - /// Hash the given message and domain separation tag to give `count` - /// field elements. - fn hash_to_field(&self, message: &[u8], domain_separation_tag: &[u8], count: usize) -> Vec; + /// Hash the given message and domain separation tag to produce `buf.len()` + /// field elements, which are written to `buf`. + fn hash_to_field(&self, message: &[u8], domain_separation_tag: &[u8], buf: &mut [F]); } /// A MessageHasher for SHAKE128 @@ -113,7 +117,7 @@ impl MessageHasher for Shake128 { "XOF:SHAKE128" } - fn hash_to_field(&self, message: &[u8], domain_separation_tag: &[u8], count: usize) -> Vec { + fn hash_to_field(&self, message: &[u8], domain_separation_tag: &[u8], buf: &mut [F]) { use sha3::digest::{ExtendableOutput, Update}; assert!(domain_separation_tag.len() < 256); @@ -121,7 +125,7 @@ impl MessageHasher for Shake128 { // . const CHUNKLEN: usize = 64; - let outlen = count * CHUNKLEN; + let outlen = buf.len() * CHUNKLEN; let mut outlen_enc = vec![]; outlen_enc.write_u32::(outlen as u32).unwrap(); @@ -131,15 +135,16 @@ impl MessageHasher for Shake128 { xof.update([domain_separation_tag.len() as u8]); xof.update(domain_separation_tag); - xof.finalize_boxed(outlen) + for (big, buf) in xof + .finalize_boxed(outlen) .chunks(CHUNKLEN) - .map(|big| { - let mut little = [0u8; CHUNKLEN]; - little.copy_from_slice(big); - little.reverse(); - F::from_bytes_wide(&little) - }) - .collect() + .zip(buf.iter_mut()) + { + let mut little = [0u8; CHUNKLEN]; + little.copy_from_slice(big); + little.reverse(); + *buf = F::from_bytes_wide(&little); + } } } @@ -148,8 +153,8 @@ impl MessageHasher for Shake128 { #[derive(Debug)] pub struct SimplifiedSWUWithDegree3Isogeny< F: FieldExt, - I: CurveAffine, C: CurveAffine, + I: CurveAffine, > { /// `Z` parameter (ΞΎ in [WB2019](https://eprint.iacr.org/2019/403)). pub z: F, @@ -166,12 +171,12 @@ pub struct SimplifiedSWUWithDegree3Isogeny< /// Constants for the isogeny. pub isogeny_constants: [F; 13], - marker_curve: PhantomData, - marker_iso: PhantomData, + _marker_c: PhantomData, + _marker_i: PhantomData, } -impl, C: CurveAffine> - SimplifiedSWUWithDegree3Isogeny +impl, I: CurveAffine> + SimplifiedSWUWithDegree3Isogeny { /// Create a SimplifiedSWUWithDegree3Isogeny method for the given parameters. /// @@ -187,20 +192,22 @@ impl, C: CurveAffine> b_over_za: b * &((*z * a).invert().unwrap()), theta: (F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap(), isogeny_constants: *isogeny_constants, - marker_curve: PhantomData, - marker_iso: PhantomData, + _marker_c: PhantomData, + _marker_i: PhantomData, } } } -impl, C: CurveAffine> HashToCurve - for SimplifiedSWUWithDegree3Isogeny +impl, I: CurveAffine> HashToCurve + for SimplifiedSWUWithDegree3Isogeny { + type IsogenousCurve = I::Projective; + fn map_id(&self) -> &str { "SSWU" } - fn map_to_curve(&self, u: &F) -> I::Projective { + fn map_to_curve(&self, u: &F) -> Self::IsogenousCurve { // 1. tv1 = inv0(Z^2 * u^4 + Z * u^2) // 2. x1 = (-B / A) * (1 + tv1) // 3. If tv1 == 0, set x1 = B / (Z * A) diff --git a/src/pasta/pallas.rs b/src/pasta/pallas.rs index 0b7e2497..612280a7 100644 --- a/src/pasta/pallas.rs +++ b/src/pasta/pallas.rs @@ -25,7 +25,7 @@ pub type IsoAffine = IsoEpAffine; lazy_static! { /// The iso-Pallas -> Pallas degree 3 isogeny map. - pub static ref MAP: SimplifiedSWUWithDegree3Isogeny = { + pub static ref MAP: SimplifiedSWUWithDegree3Isogeny = { let isogeny_constants: [Base; 13] = [ Base::from_raw([ 0x775f6034aaaaaaab, diff --git a/src/pasta/vesta.rs b/src/pasta/vesta.rs index c867fee5..ec7a1110 100644 --- a/src/pasta/vesta.rs +++ b/src/pasta/vesta.rs @@ -25,7 +25,7 @@ pub type IsoAffine = IsoEqAffine; lazy_static! { /// The iso-Vesta -> Vesta degree 3 isogeny map. - pub static ref MAP: SimplifiedSWUWithDegree3Isogeny = { + pub static ref MAP: SimplifiedSWUWithDegree3Isogeny = { let isogeny_constants: [Base; 13] = [ Base::from_raw([ 0x43cd42c800000001,