mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-06 20:20:34 +00:00
Avoid heap allocations within hash_to_curve.
This commit is contained in:
parent
16e5f96f3f
commit
e93de2c285
3 changed files with 48 additions and 51 deletions
|
|
@ -95,7 +95,7 @@ pub trait Curve:
|
||||||
/// (g * x + &(h * r)).to_affine()
|
/// (g * x + &(h * r)).to_affine()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn hash_to_curve(domain_prefix: &str) -> Box<dyn Fn(&[u8]) -> Self + 'static>;
|
fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a>;
|
||||||
|
|
||||||
/// Returns whether or not this element is on the curve; should
|
/// Returns whether or not this element is on the curve; should
|
||||||
/// always be true unless an "unchecked" API was used.
|
/// always be true unless an "unchecked" API was used.
|
||||||
|
|
|
||||||
|
|
@ -677,20 +677,12 @@ macro_rules! new_curve_impl {
|
||||||
|
|
||||||
macro_rules! impl_projective_curve_specific {
|
macro_rules! impl_projective_curve_specific {
|
||||||
($name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, special_a0_b5) => {
|
($name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, special_a0_b5) => {
|
||||||
fn hash_to_curve(domain_prefix: &str) -> Box<dyn Fn(&[u8]) -> Self + 'static> {
|
fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
|
||||||
use super::hashtocurve;
|
use super::hashtocurve;
|
||||||
|
|
||||||
let domain_separation_tag: String = format!(
|
|
||||||
"{}-{}_{}_{}_RO_",
|
|
||||||
domain_prefix,
|
|
||||||
$name_affine::CURVE_ID,
|
|
||||||
"XMD:BLAKE2b",
|
|
||||||
"SSWU"
|
|
||||||
);
|
|
||||||
|
|
||||||
Box::new(move |message| {
|
Box::new(move |message| {
|
||||||
let mut us = [Field::zero(); 2];
|
let mut us = [Field::zero(); 2];
|
||||||
hashtocurve::hash_to_field(message, domain_separation_tag.as_bytes(), &mut us);
|
hashtocurve::hash_to_field($name_affine::CURVE_ID, domain_prefix, message, &mut us);
|
||||||
let q0 = hashtocurve::map_to_curve_simple_swu::<$base, $name_affine, $iso_affine>(
|
let q0 = hashtocurve::map_to_curve_simple_swu::<$base, $name_affine, $iso_affine>(
|
||||||
&us[0],
|
&us[0],
|
||||||
$name::THETA,
|
$name::THETA,
|
||||||
|
|
@ -702,7 +694,7 @@ macro_rules! impl_projective_curve_specific {
|
||||||
$name::Z,
|
$name::Z,
|
||||||
);
|
);
|
||||||
let r = q0 + &q1;
|
let r = q0 + &q1;
|
||||||
assert!(bool::from(r.is_on_curve()));
|
debug_assert!(bool::from(r.is_on_curve()));
|
||||||
hashtocurve::iso_map::<$base, $name_affine, $iso_affine>(
|
hashtocurve::iso_map::<$base, $name_affine, $iso_affine>(
|
||||||
&r,
|
&r,
|
||||||
&$name::ISOGENY_CONSTANTS,
|
&$name::ISOGENY_CONSTANTS,
|
||||||
|
|
@ -766,7 +758,7 @@ macro_rules! impl_projective_curve_specific {
|
||||||
};
|
};
|
||||||
($name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, general) => {
|
($name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, general) => {
|
||||||
/// Unimplemented: hashing to this curve is not supported
|
/// Unimplemented: hashing to this curve is not supported
|
||||||
fn hash_to_curve(_domain_prefix: &str) -> Box<dyn Fn(&[u8]) -> Self + 'static> {
|
fn hash_to_curve<'a>(_domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,71 @@
|
||||||
//! This module implements "simplified SWU" hashing to short Weierstrass curves
|
//! This module implements "simplified SWU" hashing to short Weierstrass curves
|
||||||
//! with a = 0.
|
//! with a = 0.
|
||||||
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
use crate::arithmetic::{Curve, CurveAffine, FieldExt};
|
use crate::arithmetic::{Curve, CurveAffine, FieldExt};
|
||||||
|
|
||||||
/// Hashes over a message and writes the output to all of `buf`.
|
/// Hashes over a message and writes the output to all of `buf`.
|
||||||
pub fn hash_to_field<F: FieldExt>(message: &[u8], domain_separation_tag: &[u8], buf: &mut [F; 2]) {
|
pub fn hash_to_field<F: FieldExt>(
|
||||||
use blake2b_simd::{Params as Blake2bParams, State as Blake2bState};
|
curve_id: &str,
|
||||||
assert!(domain_separation_tag.len() < 256);
|
domain_prefix: &str,
|
||||||
|
message: &[u8],
|
||||||
|
buf: &mut [F; 2],
|
||||||
|
) {
|
||||||
|
assert!(domain_prefix.len() < 256);
|
||||||
|
assert!((22 + curve_id.len() + domain_prefix.len()) < 256);
|
||||||
|
|
||||||
// Assume that the field size is 32 bytes and k is 256, where k is defined in
|
// Assume that the field size is 32 bytes and k is 256, where k is defined in
|
||||||
// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#name-security-considerations-3>.
|
// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#name-security-considerations-3>.
|
||||||
const CHUNKLEN: usize = 64;
|
const CHUNKLEN: usize = 64;
|
||||||
|
|
||||||
let mut dst_prime: Vec<u8> = domain_separation_tag.into();
|
|
||||||
dst_prime.extend_from_slice(&[domain_separation_tag.len() as u8]);
|
|
||||||
|
|
||||||
let personal = [0u8; 16];
|
let personal = [0u8; 16];
|
||||||
let empty_hasher = Blake2bParams::new()
|
let empty_hasher = blake2b_simd::Params::new()
|
||||||
.hash_length(CHUNKLEN)
|
.hash_length(CHUNKLEN)
|
||||||
.personal(&personal)
|
.personal(&personal)
|
||||||
.to_state();
|
.to_state();
|
||||||
|
|
||||||
let xor = |left: &[u8; CHUNKLEN], right: &[u8; CHUNKLEN]| -> Vec<u8> {
|
let b_0 = empty_hasher
|
||||||
left.iter()
|
.clone()
|
||||||
.zip(right.iter())
|
.update(&[0; CHUNKLEN])
|
||||||
.map(|(&l, &r)| l ^ r)
|
.update(message)
|
||||||
.collect()
|
.update(&[0, 128, 0])
|
||||||
};
|
.update(domain_prefix.as_bytes())
|
||||||
|
.update(b"-")
|
||||||
|
.update(curve_id.as_bytes())
|
||||||
|
.update(b"_XMD:BLAKE2b_SSWU_RO_")
|
||||||
|
.update(&[(22 + curve_id.len() + domain_prefix.len()) as u8])
|
||||||
|
.finalize();
|
||||||
|
|
||||||
let finalize = |hasher: &Blake2bState| -> [u8; CHUNKLEN] {
|
let b_1 = empty_hasher
|
||||||
hasher.finalize().as_bytes().try_into().unwrap()
|
.clone()
|
||||||
};
|
.update(b_0.as_array())
|
||||||
|
.update(&[1])
|
||||||
|
.update(domain_prefix.as_bytes())
|
||||||
|
.update(b"-")
|
||||||
|
.update(curve_id.as_bytes())
|
||||||
|
.update(b"_XMD:BLAKE2b_SSWU_RO_")
|
||||||
|
.update(&[(22 + curve_id.len() + domain_prefix.len()) as u8])
|
||||||
|
.finalize();
|
||||||
|
|
||||||
let b_0 = finalize(
|
let b_2 = {
|
||||||
|
let mut empty_hasher = empty_hasher;
|
||||||
|
for (l, r) in b_0.as_array().iter().zip(b_1.as_array().iter()) {
|
||||||
|
empty_hasher.update(&[*l ^ *r]);
|
||||||
|
}
|
||||||
empty_hasher
|
empty_hasher
|
||||||
.clone()
|
|
||||||
.update(&[0; CHUNKLEN])
|
|
||||||
.update(message)
|
|
||||||
.update(&[0, 128, 0])
|
|
||||||
.update(&dst_prime),
|
|
||||||
);
|
|
||||||
let b_1 = finalize(
|
|
||||||
empty_hasher
|
|
||||||
.clone()
|
|
||||||
.update(&b_0)
|
|
||||||
.update(&[1])
|
|
||||||
.update(&dst_prime),
|
|
||||||
);
|
|
||||||
let mut empty_hasher = empty_hasher;
|
|
||||||
let b_2 = finalize(
|
|
||||||
empty_hasher
|
|
||||||
.update(&xor(&b_0, &b_1))
|
|
||||||
.update(&[2])
|
.update(&[2])
|
||||||
.update(&dst_prime),
|
.update(domain_prefix.as_bytes())
|
||||||
);
|
.update(b"-")
|
||||||
|
.update(curve_id.as_bytes())
|
||||||
|
.update(b"_XMD:BLAKE2b_SSWU_RO_")
|
||||||
|
.update(&[(22 + curve_id.len() + domain_prefix.len()) as u8])
|
||||||
|
.finalize()
|
||||||
|
};
|
||||||
|
|
||||||
for (big, buf) in [b_1, b_2].iter().zip(buf.iter_mut()) {
|
for (big, buf) in [b_1, b_2].iter().zip(buf.iter_mut()) {
|
||||||
let mut little = [0u8; CHUNKLEN];
|
let mut little = [0u8; CHUNKLEN];
|
||||||
little.copy_from_slice(big);
|
little.copy_from_slice(big.as_array());
|
||||||
little.reverse();
|
little.reverse();
|
||||||
*buf = F::from_bytes_wide(&little);
|
*buf = F::from_bytes_wide(&little);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue