Skip to content

Commit

Permalink
Suite::Hasher associated type (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
davxy authored Apr 15, 2024
1 parent db51c2c commit 7fa0c75
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 81 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ ark-serialize = { version = "0.4.2", default-features = false }
rand_core = { version = "0.6.4", default-features = false, optional = true }
rand_chacha = { version = "0.3.1", default-features = false }
zeroize = { version = "1.7.0", default-features = false }
hmac = {version = "0.12.1", default-features = false }
digest = { version = "0.10.7", default-features = false }
# Curves
ark-secp256r1 = { version = "0.4.0", default-features = false, optional = true }
ark-ed25519 = { version = "0.4.0", default-features = false, optional = true }
Expand All @@ -26,11 +28,9 @@ fflonk = { git = "https://github.com/w3f/fflonk", default-features = false, opti
ring-proof = { package = "ring", git = "https://github.com/w3f/ring-proof", default-features = false, optional = true }
merlin = { version = "3.0.0", default-features = false, optional = true }

hmac = "0.12.1"
hex = "0.4.3"

[dev-dependencies]
ark-ed25519 = "0.4.0"
hex = "0.4.3"

[features]
default = [ "std" ]
Expand Down
2 changes: 1 addition & 1 deletion src/ietf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl<S: IetfSuite + Sync> ark_serialize::Valid for Signature<S> {

impl<S: Suite> Signature<S> {
/// Proof to hash as defined by RFC9381 section 5.2
pub fn hash(&self) -> S::Hash {
pub fn hash(&self) -> HashOutput<S> {
self.gamma.hash()
}

Expand Down
29 changes: 12 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use ark_ff::PrimeField;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{vec, vec::Vec};

use core::ops::{Index, RangeFrom, RangeFull, RangeTo};
use digest::Digest;

pub mod ietf;
pub mod pedersen;
Expand All @@ -40,6 +40,8 @@ pub type ScalarField<S> = <<S as Suite>::Affine as AffineRepr>::ScalarField;
pub type BaseField<S> = <<S as Suite>::Affine as AffineRepr>::BaseField;
pub type AffinePoint<S> = <S as Suite>::Affine;

pub type HashOutput<S> = digest::Output<<S as Suite>::Hasher>;

/// Verification error(s)
pub enum Error {
VerificationFailure,
Expand All @@ -64,14 +66,8 @@ pub trait Suite: Copy + Clone {
/// by the `AffineRepr` bound.
type Affine: AffineRepr;

/// Hash output.
type Hash: Index<usize, Output = u8>
+ Index<RangeTo<usize>, Output = [u8]>
+ Index<RangeFrom<usize>, Output = [u8]>
+ Index<RangeFull, Output = [u8]>;

/// Hasher.
fn hash(data: &[u8]) -> Self::Hash;
/// Hasher output.
type Hasher: Digest;

/// Nonce generation as described by RFC-9381 section 5.4.2.
///
Expand Down Expand Up @@ -107,7 +103,7 @@ pub trait Suite: Copy + Clone {
});
buf.extend_from_slice(ad);
buf.push(DOM_SEP_END);
let hash = &Self::hash(&buf)[..Self::CHALLENGE_LEN];
let hash = &utils::hash::<Self::Hasher>(&buf)[..Self::CHALLENGE_LEN];
ScalarField::<Self>::from_be_bytes_mod_order(hash)
}

Expand All @@ -118,13 +114,13 @@ pub trait Suite: Copy + Clone {
utils::hash_to_curve_tai::<Self>(data, false)
}

fn point_to_hash(pt: &AffinePoint<Self>) -> Self::Hash {
fn point_to_hash(pt: &AffinePoint<Self>) -> HashOutput<Self> {
const DOM_SEP_START: u8 = 0x03;
const DOM_SEP_END: u8 = 0x00;
let mut buf = vec![Self::SUITE_ID, DOM_SEP_START];
Self::point_encode(pt, &mut buf);
buf.push(DOM_SEP_END);
Self::hash(&buf)
utils::hash::<Self::Hasher>(&buf)
}

#[inline(always)]
Expand Down Expand Up @@ -209,7 +205,7 @@ impl<S: Suite> Secret<S> {
///
/// The `seed` is hashed using the `Suite::hash` to construct the secret scalar.
pub fn from_seed(seed: &[u8]) -> Self {
let bytes = S::hash(seed);
let bytes = utils::hash::<S::Hasher>(seed);
let scalar = ScalarField::<S>::from_le_bytes_mod_order(&bytes[..]);
Self::from_scalar(scalar)
}
Expand Down Expand Up @@ -268,7 +264,7 @@ impl<S: Suite> Output<S> {
}

/// Hash using `[Suite::point_to_hash]`.
pub fn hash(&self) -> S::Hash {
pub fn hash(&self) -> HashOutput<S> {
S::point_to_hash(&self.0)
}
}
Expand Down Expand Up @@ -300,8 +296,7 @@ mod tests {
let input = Input::from(random_val(None));
let output = secret.output(input);

let hash = output.hash();
let expected = "f30ceafdbd80a9280547a9d44a88c188";
assert_eq!(expected, hex::encode(&hash[..16]));
let expected = "08ffdc9d48f6553c0352b92a233a8101a69ac9f4dcb7f9e2c9c43d46a441c331";
assert_eq!(expected, hex::encode(output.hash()));
}
}
6 changes: 1 addition & 5 deletions src/suites/bandersnatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ impl Suite for BandersnatchSha512 {
const CHALLENGE_LEN: usize = 32;

type Affine = ark_ed_on_bls12_381_bandersnatch::SWAffine;
type Hash = [u8; 64];

fn hash(data: &[u8]) -> Self::Hash {
utils::sha512(data)
}
type Hasher = sha2::Sha512;
}

impl PedersenSuite for BandersnatchSha512 {
Expand Down
6 changes: 1 addition & 5 deletions src/suites/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,5 @@ impl Suite for Ed25519Sha512 {
const CHALLENGE_LEN: usize = 16;

type Affine = ark_ed25519::EdwardsAffine;
type Hash = [u8; 64];

fn hash(data: &[u8]) -> Self::Hash {
utils::sha512(data)
}
type Hasher = sha2::Sha512;
}
6 changes: 1 addition & 5 deletions src/suites/secp256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ impl Suite for P256Sha256Tai {
const CHALLENGE_LEN: usize = 16;

type Affine = ark_secp256r1::Affine;
type Hash = [u8; 32];

fn hash(data: &[u8]) -> Self::Hash {
utils::sha256(data)
}
type Hasher = sha2::Sha256;

fn nonce(sk: &ScalarField, pt: Input) -> ScalarField {
utils::nonce_rfc_6979::<Self>(sk, &pt.0)
Expand Down
75 changes: 30 additions & 45 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{AffinePoint, ScalarField, Suite};
use ark_ff::PrimeField;
use digest::{core_api::BlockSizeUser, Digest};

#[cfg(not(feature = "std"))]
use ark_std::vec::Vec;
Expand All @@ -26,40 +27,22 @@ macro_rules! suite_types {
};
}

/// SHA-256 hasher
// Generic hash wrapper.
#[inline(always)]
pub fn sha256(input: &[u8]) -> [u8; 32] {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(input);
let result = hasher.finalize();
let mut h = [0u8; 32];
h.copy_from_slice(&result);
h
pub(crate) fn hash<H: Digest>(data: &[u8]) -> digest::Output<H> {
H::new().chain_update(data).finalize()
}

/// SHA-512 hasher
/// Generic HMAC wrapper.
#[inline(always)]
pub fn sha512(input: &[u8]) -> [u8; 64] {
use sha2::{Digest, Sha512};
let mut hasher = Sha512::new();
hasher.update(input);
let result = hasher.finalize();
let mut h = [0u8; 64];
h.copy_from_slice(&result);
h
}

/// HMAC
pub fn hmac(sk: &[u8], data: &[u8]) -> Vec<u8> {
use hmac::{Hmac, Mac};
use sha2::Sha256;
// Create alias for HMAC-SHA256
type HmacSha256 = Hmac<Sha256>;
let mut mac = HmacSha256::new_from_slice(sk).expect("HMAC can take key of any size");
mac.update(data);
let result = mac.finalize();
result.into_bytes().to_vec()
pub(crate) fn hmac<H: Digest + BlockSizeUser>(sk: &[u8], data: &[u8]) -> Vec<u8> {
use hmac::{Mac, SimpleHmac};
SimpleHmac::<H>::new_from_slice(sk)
.expect("HMAC can take key of any size")
.chain_update(data)
.finalize()
.into_bytes()
.to_vec()
}

/// Try-And-Increment (TAI) method as defined by RFC9381 section 5.4.1.1.
Expand All @@ -83,14 +66,17 @@ pub fn hash_to_curve_tai<S: Suite>(data: &[u8], point_be_encoding: bool) -> Opti
const DOM_SEP_BACK: u8 = 0x00;

let mod_size = <<<S::Affine as AffineRepr>::BaseField as Field>::BasePrimeField as PrimeField>::MODULUS_BIT_SIZE as usize / 8;
if S::Hasher::output_size() < mod_size {
return None;
}

let mut buf = [&[S::SUITE_ID, DOM_SEP_FRONT], data, &[0x00, DOM_SEP_BACK]].concat();
let ctr_pos = buf.len() - 2;

for ctr in 0..256 {
// Modify ctr value
buf[ctr_pos] = ctr as u8;
let hash = &S::hash(&buf)[..];
let hash = &hash::<S::Hasher>(&buf)[..];
if hash.len() < mod_size {
return None;
}
Expand Down Expand Up @@ -125,11 +111,11 @@ pub fn hash_to_curve_tai<S: Suite>(data: &[u8], point_be_encoding: bool) -> Opti
/// This function panics if `Hash` is less than 32 bytes.
pub fn nonce_rfc_8032<S: Suite>(sk: &ScalarField<S>, input: &AffinePoint<S>) -> ScalarField<S> {
let raw = encode_scalar::<S>(sk);
let sk_hash = &S::hash(&raw)[32..];
let sk_hash = &hash::<S::Hasher>(&raw)[32..];

let raw = encode_point::<S>(input);
let v = [sk_hash, &raw[..]].concat();
let h = &S::hash(&v)[..];
let h = &hash::<S::Hasher>(&v)[..];

S::scalar_decode(h)
}
Expand All @@ -142,30 +128,33 @@ pub fn nonce_rfc_8032<S: Suite>(sk: &ScalarField<S>, input: &AffinePoint<S>) ->
///
/// The algorithm generate the nonce value in a deterministic
/// pseudorandom fashion.
pub fn nonce_rfc_6979<S: Suite>(sk: &ScalarField<S>, input: &AffinePoint<S>) -> ScalarField<S> {
pub fn nonce_rfc_6979<S: Suite>(sk: &ScalarField<S>, input: &AffinePoint<S>) -> ScalarField<S>
where
S::Hasher: BlockSizeUser,
{
let raw = encode_point::<S>(input);
let h1 = S::hash(&raw);
let h1 = hash::<S::Hasher>(&raw);

let v = [1; 32];
let k = [0; 32];

// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
let x = encode_scalar::<S>(sk);
let raw = [&v[..], &[0x00], &x[..], &h1[..]].concat();
let k = hmac(&k, &raw);
let k = hmac::<S::Hasher>(&k, &raw);

// V = HMAC_K(V)
let v = hmac(&k, &v);
let v = hmac::<S::Hasher>(&k, &v);

// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
let raw = [&v[..], &[0x01], &x[..], &h1[..]].concat();
let k = hmac(&k, &raw);
let k = hmac::<S::Hasher>(&k, &raw);

// V = HMAC_K(V)
let v = hmac(&k, &v);
let v = hmac::<S::Hasher>(&k, &v);

// TODO: loop until 1 < k < q
let v = hmac(&k, &v);
let v = hmac::<S::Hasher>(&k, &v);

S::scalar_decode(&v)
}
Expand Down Expand Up @@ -198,11 +187,7 @@ pub(crate) mod testing {
const CHALLENGE_LEN: usize = 16;

type Affine = ark_ed25519::EdwardsAffine;
type Hash = [u8; 64];

fn hash(data: &[u8]) -> Self::Hash {
utils::sha512(data)
}
type Hasher = sha2::Sha256;
}

suite_types!(TestSuite);
Expand Down

0 comments on commit 7fa0c75

Please sign in to comment.