Skip to content

Commit 6f8bd43

Browse files
committed
Optional cofactor clearing
1 parent 2c9c56e commit 6f8bd43

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

src/lib.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use zeroize::Zeroize;
2020

2121
use ark_ec::{AffineRepr, CurveGroup};
22-
use ark_ff::PrimeField;
22+
use ark_ff::{One, PrimeField, Zero};
2323
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
2424
use ark_std::vec::Vec;
2525

@@ -58,7 +58,7 @@ pub use codec::Codec;
5858

5959
#[derive(Debug)]
6060
pub enum Error {
61-
/// Verification error(s)
61+
/// Verification error
6262
VerificationFailure,
6363
/// Bad input data
6464
InvalidData,
@@ -135,9 +135,9 @@ pub trait Suite: Copy {
135135

136136
/// Hash data to a curve point.
137137
///
138-
/// By default uses "try and increment" method described by RFC 9381.
138+
/// By default uses "try and increment" method described by RFC-9381.
139139
///
140-
/// The input `data` is assumed to be `[salt||]alpha` according to the RFC 9381.
140+
/// The input `data` is assumed to be `[salt||]alpha` according to the RFC-9381.
141141
/// In other words, salt is not applied by this function.
142142
#[inline(always)]
143143
fn data_to_point(data: &[u8]) -> Option<AffinePoint<Self>> {
@@ -146,10 +146,10 @@ pub trait Suite: Copy {
146146

147147
/// Map the point to a hash value using `Self::Hasher`.
148148
///
149-
/// By default uses the algorithm described by RFC 9381.
149+
/// By default uses the algorithm described by RFC-9381 without cofactor clearing.
150150
#[inline(always)]
151151
fn point_to_hash(pt: &AffinePoint<Self>) -> HashOutput<Self> {
152-
utils::point_to_hash_rfc_9381::<Self>(pt)
152+
utils::point_to_hash_rfc_9381::<Self>(pt, false)
153153
}
154154

155155
/// Generator used through all the suite.
@@ -221,7 +221,10 @@ impl<S: Suite> Secret<S> {
221221
/// The `seed` is hashed using the `Suite::hash` to construct the secret scalar.
222222
pub fn from_seed(seed: &[u8]) -> Self {
223223
let bytes = utils::hash::<S::Hasher>(seed);
224-
let scalar = ScalarField::<S>::from_le_bytes_mod_order(&bytes[..]);
224+
let mut scalar = ScalarField::<S>::from_le_bytes_mod_order(&bytes[..]);
225+
if scalar.is_zero() {
226+
scalar.set_one();
227+
}
225228
Self::from_scalar(scalar)
226229
}
227230

src/utils/common.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,35 @@ pub fn challenge_rfc_9381<S: Suite>(pts: &[&AffinePoint<S>], ad: &[u8]) -> Scala
129129
}
130130

131131
/// Point to a hash according to RFC-9381 section 5.2.
132-
pub fn point_to_hash_rfc_9381<S: Suite>(pt: &AffinePoint<S>) -> HashOutput<S> {
132+
///
133+
/// According to the RFC, the input point `pt` should be multiplied by the cofactor
134+
/// before being hashed. However, in typical usage, the hashed point is the result
135+
/// of a scalar multiplication on a point produced by the `Suite::data_to_point`
136+
/// (also referred to as the _hash-to-curve_ or _h2c_) algorithm, which is expected
137+
/// to yield a point that already belongs to the prime order subgroup of the curve.
138+
///
139+
/// Therefore, assuming the `data_to_point` function is implemented correctly, the
140+
/// input point `pt` will inherently reside in the prime order subgroup, making the
141+
/// cofactor multiplication unnecessary and redundant in terms of security. The primary
142+
/// purpose of multiplying by the cofactor is as a safeguard against potential issues
143+
/// with an incorrect implementation of `data_to_point`.
144+
///
145+
/// Since multiplying by the cofactor changes the point being hashed, this step is
146+
/// made optional to accommodate scenarios where strict compliance with the RFC's
147+
/// prescribed procedure is not required.
148+
pub fn point_to_hash_rfc_9381<S: Suite>(
149+
pt: &AffinePoint<S>,
150+
mul_by_cofactor: bool,
151+
) -> HashOutput<S> {
152+
use ark_std::borrow::Cow::*;
133153
const DOM_SEP_START: u8 = 0x03;
134154
const DOM_SEP_END: u8 = 0x00;
135155
let mut buf = [S::SUITE_ID, &[DOM_SEP_START]].concat();
136-
S::Codec::point_encode_into(pt, &mut buf);
156+
let pt = match mul_by_cofactor {
157+
false => Borrowed(pt),
158+
true => Owned(pt.mul_by_cofactor()),
159+
};
160+
S::Codec::point_encode_into(&pt, &mut buf);
137161
buf.push(DOM_SEP_END);
138162
hash::<S::Hasher>(&buf)
139163
}

0 commit comments

Comments
 (0)