refactor hash implementations with hash_to_array/scalar functions

This commit is contained in:
Conrado Gouvea 2022-12-08 14:52:20 -03:00 committed by Deirdre Connolly
parent 8a391caab8
commit 2967cae5e4
4 changed files with 84 additions and 149 deletions

View File

@ -9,7 +9,7 @@ use curve25519_dalek::{
traits::Identity,
};
use rand_core::{CryptoRng, RngCore};
use sha2::{digest::Update, Digest, Sha512};
use sha2::{Digest, Sha512};
use frost_core::{frost, Ciphersuite, Field, Group, GroupError};
@ -65,6 +65,21 @@ impl Group for Ed25519Group {
}
}
fn hash_to_array(inputs: &[&[u8]]) -> [u8; 64] {
let mut h = Sha512::new();
for i in inputs {
h.update(i);
}
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
output
}
fn hash_to_scalar(inputs: &[&[u8]]) -> Scalar {
let output = hash_to_array(inputs);
Scalar::from_bytes_mod_order_wide(&output)
}
/// Context string 'FROST-RISTRETTO255-SHA512-v5' from the ciphersuite in the [spec]
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-1
@ -85,79 +100,40 @@ impl Ciphersuite for Ed25519Sha512 {
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-2.2.2.1
fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("rho")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"rho", m])
}
/// H2 for FROST(Ed25519, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-2.2.2.2
fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new().chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
hash_to_scalar(&[m])
}
/// H3 for FROST(Ed25519, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-2.2.2.3
fn H3(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("nonce")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"nonce", m])
}
/// H4 for FROST(Ed25519, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-2.2.2.4
fn H4(m: &[u8]) -> Self::HashOutput {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("msg")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"msg", m])
}
/// H5 for FROST(Ed25519, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-2.2.2.5
fn H5(m: &[u8]) -> Self::HashOutput {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("com")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"com", m])
}
/// HDKG for FROST(Ed25519, SHA-512)
fn HDKG(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("dkg")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
Some(<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output))
Some(hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"dkg", m]))
}
}

View File

@ -12,7 +12,7 @@ use p256::{
AffinePoint, ProjectivePoint, Scalar,
};
use rand_core::{CryptoRng, RngCore};
use sha2::{digest::Update, Digest, Sha256};
use sha2::{Digest, Sha256};
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
@ -140,6 +140,23 @@ impl Group for P256Group {
}
}
fn hash_to_array(inputs: &[&[u8]]) -> [u8; 32] {
let mut h = Sha256::new();
for i in inputs {
h.update(i);
}
let mut output = [0u8; 32];
output.copy_from_slice(h.finalize().as_slice());
output
}
fn hash_to_scalar(domain: &[u8], msg: &[u8]) -> Scalar {
let mut u = [P256ScalarField::zero()];
hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&[msg], domain, &mut u)
.expect("should never return error according to error cases described in ExpandMsgXmd");
u[0]
}
/// Context string from the ciphersuite in the [spec]
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-1
@ -160,70 +177,43 @@ impl Ciphersuite for P256Sha256 {
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-2.2.2.1
fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "rho";
hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&[m], dst.as_bytes(), &mut u)
.expect("should never return error according to error cases described in ExpandMsgXmd");
u[0]
hash_to_scalar((CONTEXT_STRING.to_owned() + "rho").as_bytes(), m)
}
/// H2 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-2.2.2.2
fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "chal";
hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&[m], dst.as_bytes(), &mut u)
.expect("should never return error according to error cases described in ExpandMsgXmd");
u[0]
hash_to_scalar((CONTEXT_STRING.to_owned() + "chal").as_bytes(), m)
}
/// H3 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-2.2.2.3
fn H3(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "nonce";
hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&[m], dst.as_bytes(), &mut u)
.expect("should never return error according to error cases described in ExpandMsgXmd");
u[0]
hash_to_scalar((CONTEXT_STRING.to_owned() + "nonce").as_bytes(), m)
}
/// H4 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-2.2.2.4
fn H4(m: &[u8]) -> Self::HashOutput {
let h = Sha256::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("msg")
.chain(m);
let mut output = [0u8; 32];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"msg", m])
}
/// H5 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-2.2.2.5
fn H5(m: &[u8]) -> Self::HashOutput {
let h = Sha256::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("com")
.chain(m);
let mut output = [0u8; 32];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"com", m])
}
/// HDKG for FROST(P-256, SHA-256)
fn HDKG(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "dkg";
hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&[m], dst.as_bytes(), &mut u)
.expect("should never return error according to error cases described in ExpandMsgXmd");
Some(u[0])
Some(hash_to_scalar(
(CONTEXT_STRING.to_owned() + "dkg").as_bytes(),
m,
))
}
}

View File

@ -9,7 +9,7 @@ use curve25519_dalek::{
traits::Identity,
};
use rand_core::{CryptoRng, RngCore};
use sha2::{digest::Update, Digest, Sha512};
use sha2::{Digest, Sha512};
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
@ -107,6 +107,21 @@ impl Group for RistrettoGroup {
}
}
fn hash_to_array(inputs: &[&[u8]]) -> [u8; 64] {
let mut h = Sha512::new();
for i in inputs {
h.update(i);
}
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
output
}
fn hash_to_scalar(inputs: &[&[u8]]) -> Scalar {
let output = hash_to_array(inputs);
Scalar::from_bytes_mod_order_wide(&output)
}
/// Context string from the ciphersuite in the [spec].
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-1
@ -127,82 +142,40 @@ impl Ciphersuite for Ristretto255Sha512 {
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-2.2.2.1
fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("rho")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"rho", m])
}
/// H2 for FROST(ristretto255, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-2.2.2.2
fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("chal")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"chal", m])
}
/// H3 for FROST(ristretto255, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-2.2.2.3
fn H3(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("nonce")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"nonce", m])
}
/// H4 for FROST(ristretto255, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-2.2.2.4
fn H4(m: &[u8]) -> Self::HashOutput {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("msg")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"msg", m])
}
/// H5 for FROST(ristretto255, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-2.2.2.5
fn H5(m: &[u8]) -> Self::HashOutput {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("com")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"com", m])
}
/// HDKG for FROST(ristretto255, SHA-512)
fn HDKG(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("dkg")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
Some(<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output))
Some(hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"dkg", m]))
}
}

View File

@ -14,7 +14,7 @@ use k256::{
AffinePoint, ProjectivePoint, Scalar,
};
use rand_core::{CryptoRng, RngCore};
use sha2::{digest::Update, Digest, Sha256};
use sha2::{Digest, Sha256};
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
@ -142,6 +142,16 @@ impl Group for Secp256K1Group {
}
}
fn hash_to_array(inputs: &[&[u8]]) -> [u8; 32] {
let mut h = Sha256::new();
for i in inputs {
h.update(i);
}
let mut output = [0u8; 32];
output.copy_from_slice(h.finalize().as_slice());
output
}
/// hash2field implementation from <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3>
///
/// From <https://github.com/serai-dex/serai/blob/5df74ac9e28f9299e674e98d08e64c99c34e579c/crypto/ciphersuite/src/kp256.rs#L45-L62>
@ -212,28 +222,14 @@ impl Ciphersuite for Secp256K1Sha256 {
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.5-2.2.2.4
fn H4(m: &[u8]) -> Self::HashOutput {
let h = Sha256::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("msg")
.chain(m);
let mut output = [0u8; 32];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"msg", m])
}
/// H5 for FROST(secp256k1, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.5-2.2.2.5
fn H5(m: &[u8]) -> Self::HashOutput {
let h = Sha256::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("com")
.chain(m);
let mut output = [0u8; 32];
output.copy_from_slice(h.finalize().as_slice());
output
hash_to_array(&[CONTEXT_STRING.as_bytes(), b"com", m])
}
/// HDKG for FROST(secp256k1, SHA-256)