Skip to content

Commit

Permalink
tmp: use sha256 as hasher with smaller k and reduce the hash dige…
Browse files Browse the repository at this point in the history
…st directly
  • Loading branch information
han0110 committed Jun 11, 2023
1 parent 3ba1790 commit 17b45df
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 45 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ paste = "1.0.11"
serde = { version = "1.0", default-features = false, optional = true }
serde_arrays = { version = "0.1.0", optional = true }
blake2b_simd = "1"
sha2 = "0.10.6"

[features]
default = ["reexport", "bits"]
Expand Down
43 changes: 40 additions & 3 deletions src/bn256/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ new_curve_impl!(
Fr,
(G1_GENERATOR_X,G1_GENERATOR_Y),
G1_B,
"bn256_g1",
"BN254G1",
|curve_id, domain_prefix| svdw_map_to_curve(curve_id, domain_prefix, Fq::ONE),
);

Expand Down Expand Up @@ -209,18 +209,55 @@ impl CofactorGroup for G2 {

#[cfg(test)]
mod tests {

use crate::arithmetic::CurveEndo;
use crate::bn256::{Fr, G1, G2};
use crate::bn256::{Fr, G1Affine, G1, G2};
use crate::tests::from_hex;
use crate::CurveExt;
use ff::Field;
use ff::PrimeField;
use ff::WithSmallOrderMulGroup;
use group::Curve;
use pasta_curves::arithmetic::CurveAffine;
use rand_core::OsRng;

#[test]
fn test_hash_to_curve() {
crate::tests::curve::hash_to_curve_test::<G1>();

// Test vector taken from https://github.com/ConsenSys/gnark-crypto/blob/441dc0ffe639294b8d09e394f24ba7575577229c/ecc/bn254/hash_vectors_test.go#L29
let domain_prefix = "QUUX-V01-CS02-with";
let hasher = G1::hash_to_curve(domain_prefix);
for (message, x, y) in [
(
"",
"0xa976ab906170db1f9638d376514dbf8c42aef256a54bbd48521f20749e59e86",
"0x2925ead66b9e68bfc309b014398640ab55f6619ab59bc1fab2210ad4c4d53d5",
),
(
"abc",
"0x23f717bee89b1003957139f193e6be7da1df5f1374b26a4643b0378b5baf53d1",
"0x4142f826b71ee574452dbc47e05bc3e1a647478403a7ba38b7b93948f4e151d",
),
(
"abcdef0123456789",
"0x187dbf1c3c89aceceef254d6548d7163fdfa43084145f92c4c91c85c21442d4a",
"0xabd99d5b0000910b56058f9cc3b0ab0a22d47cf27615f588924fac1e5c63b4d",
),
(
"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
"0xfe2b0743575324fc452d590d217390ad48e5a16cf051bee5c40a2eba233f5c",
"0x794211e0cc72d3cbbdf8e4e5cd6e7d7e78d101ff94862caae8acbe63e9fdc78",
),
(
"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0x1b05dc540bd79fd0fea4fbb07de08e94fc2e7bd171fe025c479dc212a2173ce",
"0x1bf028afc00c0f843d113758968f580640541728cfc6d32ced9779aa613cd9b0",
),
] {
let output = G1Affine::from_xy(from_hex(x), from_hex(y)).unwrap();
let a = hasher(message.as_bytes()).to_affine();
assert_eq!(a, output)
}
}

#[test]
Expand Down
108 changes: 66 additions & 42 deletions src/hash_to_curve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use ff::{Field, FromUniformBytes, PrimeField};
use num_bigint::BigUint;
use num_traits::Num;
use pasta_curves::arithmetic::CurveExt;
use sha2::{Digest, Sha256};
use static_assertions::const_assert;
use std::iter;
use subtle::{ConditionallySelectable, ConstantTimeEq};

/// Hashes over a message and writes the output to all of `buf`.
Expand All @@ -15,69 +19,89 @@ fn hash_to_field<F: FromUniformBytes<64>>(
assert!(domain_prefix.len() < 256);
assert!((18 + method.len() + 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 128, where k is defined in
// <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 = 48;
const_assert!(CHUNKLEN * 2 < 256);

// Input block size of BLAKE2b.
const R_IN_BYTES: usize = 128;
// Input block size of SHA-256.
const R_IN_BYTES: usize = 64;

let personal = [0u8; 16];
let empty_hasher = blake2b_simd::Params::new()
.hash_length(CHUNKLEN)
.personal(&personal)
.to_state();
let empty_hasher = Sha256::new();

let b_0 = empty_hasher
.clone()
.update(&[0; R_IN_BYTES])
.update(message)
.update(&[0, (CHUNKLEN * 2) as u8, 0])
.update(domain_prefix.as_bytes())
.update(b"-")
.update(curve_id.as_bytes())
.update(b"_XMD:BLAKE2b_")
.update(method.as_bytes())
.update(b"_RO_")
.update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.chain_update(&[0; R_IN_BYTES])
.chain_update(message)
.chain_update(&[0, (CHUNKLEN * 2) as u8, 0])
.chain_update(domain_prefix.as_bytes())
.chain_update(b"-")
.chain_update(curve_id.as_bytes())
.chain_update(b"_XMD:SHA-256_")
.chain_update(method.as_bytes())
.chain_update(b"_RO_")
.chain_update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.finalize();

let b_1 = empty_hasher
.clone()
.update(b_0.as_array())
.update(&[1])
.update(domain_prefix.as_bytes())
.update(b"-")
.update(curve_id.as_bytes())
.update(b"_XMD:BLAKE2b_")
.update(method.as_bytes())
.update(b"_RO_")
.update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.chain_update(b_0.as_slice())
.chain_update(&[1])
.chain_update(domain_prefix.as_bytes())
.chain_update(b"-")
.chain_update(curve_id.as_bytes())
.chain_update(b"_XMD:SHA-256_")
.chain_update(method.as_bytes())
.chain_update(b"_RO_")
.chain_update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.finalize();

let b_2 = {
let mut empty_hasher = empty_hasher.clone();
for (l, r) in b_0.as_slice().iter().zip(b_1.as_slice().iter()) {
empty_hasher.update(&[*l ^ *r]);
}
empty_hasher
.chain_update(&[2])
.chain_update(domain_prefix.as_bytes())
.chain_update(b"-")
.chain_update(curve_id.as_bytes())
.chain_update(b"_XMD:SHA-256_")
.chain_update(method.as_bytes())
.chain_update(b"_RO_")
.chain_update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.finalize()
};

let b_3 = {
let mut empty_hasher = empty_hasher;
for (l, r) in b_0.as_array().iter().zip(b_1.as_array().iter()) {
for (l, r) in b_0.as_slice().iter().zip(b_2.as_slice().iter()) {
empty_hasher.update(&[*l ^ *r]);
}
empty_hasher
.update(&[2])
.update(domain_prefix.as_bytes())
.update(b"-")
.update(curve_id.as_bytes())
.update(b"_XMD:BLAKE2b_")
.update(method.as_bytes())
.update(b"_RO_")
.update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.chain_update(&[3])
.chain_update(domain_prefix.as_bytes())
.chain_update(b"-")
.chain_update(curve_id.as_bytes())
.chain_update(b"_XMD:SHA-256_")
.chain_update(method.as_bytes())
.chain_update(b"_RO_")
.chain_update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8])
.finalize()
};

for (big, buf) in [b_1, b_2].iter().zip(buf.iter_mut()) {
let mut little = [0u8; CHUNKLEN];
little.copy_from_slice(big.as_array());
little.reverse();
*buf = F::from_uniform_bytes(&little);
let bytes = iter::empty()
.chain(b_1)
.chain(b_2)
.chain(b_3)
.collect::<Vec<_>>();

let modulus = &BigUint::from_str_radix(&F::MODULUS[2..], 16).unwrap();
for (bytes, buf) in bytes.chunks(CHUNKLEN).zip(buf.iter_mut()) {
let reduced_bytes_le = (BigUint::from_bytes_be(bytes) % modulus).to_bytes_le();
let mut repr = F::Repr::default();
repr.as_mut()[..reduced_bytes_le.len()].copy_from_slice(&reduced_bytes_le);
*buf = F::from_repr(repr).unwrap();
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,15 @@
use ff::PrimeField;
use num_bigint::BigUint;
use num_traits::Num;

pub mod curve;
pub mod field;

pub(crate) fn from_hex<F: PrimeField>(hex: impl AsRef<str>) -> F {
let hex = hex
.as_ref()
.strip_prefix("0x")
.unwrap_or_else(|| hex.as_ref());
let oct = BigUint::from_str_radix(hex, 16).unwrap().to_string();
F::from_str_vartime(oct.as_str()).unwrap()
}

0 comments on commit 17b45df

Please sign in to comment.