Skip to content

Commit

Permalink
hash to curve suite (#146)
Browse files Browse the repository at this point in the history
* add hash to curve suite

* Update comment

Co-authored-by: David Nevado <davidnevadoc@users.noreply.github.com>

* remove lefovers

* update references of test vectors

* Fix domain name

Co-authored-by: David Nevado <davidnevadoc@users.noreply.github.com>

* rollback nonsense pluto from_u512 change

* add bn256 g1 hash to curve test vectors

* add bn256 g2 hash to curve test vectors

* tidy

* reuse `FromUniformBytes<64>` when possible

* remove old blake2 dep

---------

Co-authored-by: David Nevado <davidnevadoc@users.noreply.github.com>
  • Loading branch information
kilic and davidnevadoc committed May 24, 2024
1 parent 1aa447e commit f7c6b4c
Show file tree
Hide file tree
Showing 25 changed files with 927 additions and 820 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ paste = "1.0.11"
serde = { version = "1.0", default-features = false, optional = true }
serde_arrays = { version = "0.1.0", optional = true }
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] }
blake2b_simd = "1"
rayon = "1.8"
unroll = "0.1.5"
blake2 = "0.10.6"
sha2 = "0.10.8"
digest = "0.10.7"

[features]
default = ["bits"]
Expand Down
272 changes: 200 additions & 72 deletions src/bn256/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::ff::WithSmallOrderMulGroup;
use crate::ff::{Field, PrimeField};
use crate::group::Curve;
use crate::group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group, GroupEncoding};
use crate::hash_to_curve::svdw_hash_to_curve;
use crate::{
impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
Expand Down Expand Up @@ -39,7 +38,7 @@ new_curve_impl!(
G1_A,
G1_B,
"bn256_g1",
|curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z),
|domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, G1::default_hash_to_curve_suite()),
);

new_curve_impl!(
Expand All @@ -52,9 +51,18 @@ new_curve_impl!(
G2_A,
G2_B,
"bn256_g2",
|_, _| unimplemented!(),
|domain_prefix| hash_to_curve_g2(domain_prefix),
);

#[allow(clippy::type_complexity)]
pub(crate) fn hash_to_curve_g2<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> G2 + 'a> {
let suite = G2::default_hash_to_curve_suite();
Box::new(move |message| {
let r0 = suite.hash_to_curve(domain_prefix, message);
r0.clear_cofactor()
})
}

const G1_GENERATOR_X: Fq = Fq::one();
const G1_GENERATOR_Y: Fq = Fq::from_raw([2, 0, 0, 0]);
const G1_A: Fq = Fq::from_raw([0, 0, 0, 0]);
Expand Down Expand Up @@ -146,24 +154,65 @@ impl CofactorGroup for G2 {
type Subgroup = G2;

fn clear_cofactor(&self) -> Self {
// "0x30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d"
let e: [u8; 32] = [
0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81,
0x58, 0x5e, 0x06, 0xce, 0xec, 0xda, 0x57, 0x2a, 0x24, 0x89, 0x34, 0x5f, 0x22, 0x99,
0xc0, 0xf9, 0xfa, 0x8d,
];
fn exp_by_x(g2: &G2) -> G2 {
let x = super::BN_X;
let mut res = G2::identity();
for i in (0..64).rev() {
res = res.double();
if ((x >> i) & 1) == 1 {
res += g2;
}
}
res
}

// self * COFACTOR_G2
let mut acc = G2::identity();
for bit in e
.iter()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = G2::conditional_select(&acc, &(acc + self), bit);
fn psi(mut g2: G2) -> G2 {
const U0: Fq = Fq::from_raw([
0x99e39557176f553d,
0xb78cc310c2c3330c,
0x4c0bec3cf559b143,
0x2fb347984f7911f7,
]);

const U1: Fq = Fq::from_raw([
0x1665d51c640fcba2,
0x32ae2a1d0b7c9dce,
0x4ba4cc8bd75a0794,
0x16c9e55061ebae20,
]);
let u = Fq2::new(U0, U1);

const V0: Fq = Fq::from_raw([
0xdc54014671a0135a,
0xdbaae0eda9c95998,
0xdc5ec698b6e2f9b9,
0x063cf305489af5dc,
]);

const V1: Fq = Fq::from_raw([
0x82d37f632623b0e3,
0x21807dc98fa25bd2,
0x0704b5a7ec796f2b,
0x07c03cbcac41049a,
]);
let v = Fq2::new(V0, V1);

g2.x.conjugate();
g2.y.conjugate();
g2.z.conjugate();

g2.x *= u;
g2.y *= v;

g2
}
acc

let u0 = exp_by_x(self);
let u1 = psi(u0.double() + u0);
let u2 = psi(psi(u0));
let u3 = psi(psi(psi(*self)));

u0 + u1 + u2 + u3
}

fn into_subgroup(self) -> CtOption<Self::Subgroup> {
Expand All @@ -179,7 +228,6 @@ impl CofactorGroup for G2 {
];

// self * GROUP_ORDER;

let mut acc = G2::identity();
for bit in e
.iter()
Expand All @@ -195,16 +243,37 @@ impl CofactorGroup for G2 {

impl G1 {
const SVDW_Z: Fq = Fq::ONE;

fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite<Self, sha2::Sha256, 48> {
crate::hash_to_curve::Suite::<G1, sha2::Sha256, 48>::new(
b"BN254G1_XMD:SHA-256_SVDW_RO_",
Self::SVDW_Z,
crate::hash_to_curve::Method::SVDW,
)
}
}

impl G2 {
const SVDW_Z: Fq2 = Fq2::ONE;

fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite<Self, sha2::Sha256, 96> {
crate::hash_to_curve::Suite::<G2, sha2::Sha256, 96>::new(
b"BN254G2_XMD:SHA-256_SVDW_RO_",
Self::SVDW_Z,
crate::hash_to_curve::Method::SVDW,
)
}
}

#[cfg(test)]
mod test {
use crate::tests::curve::TestH2C;

use super::*;
use group::UncompressedEncoding;

crate::curve_testing_suite!(G2, "clear_cofactor");
crate::curve_testing_suite!(G1, G2);
crate::curve_testing_suite!(G1, "hash_to_curve");
crate::curve_testing_suite!(G1, "endo_consistency");
crate::curve_testing_suite!(
G1,
Expand All @@ -218,57 +287,7 @@ mod test {
0x00,
]
);
crate::curve_testing_suite!(
G1,
"svdw_map_to_curve",
(
// Precomputed constants taken from https://github.com/ConsenSys/gnark-crypto/blob/441dc0ffe639294b8d09e394f24ba7575577229c/internal/generator/config/bn254.go#L26-L32.
[
"4",
"10944121435919637611123202872628637544348155578648911831344518947322613104291",
"8815841940592487685674414971303048083897117035520822607866",
"7296080957279758407415468581752425029565437052432607887563012631548408736189",
],
// List of (u, (Q.x, Q.y)) taken from https://github.com/ConsenSys/gnark-crypto/blob/441dc0ffe639294b8d09e394f24ba7575577229c/ecc/bn254/hash_vectors_test.go#L4-L28
[
(
"0xcb81538a98a2e3580076eed495256611813f6dae9e16d3d4f8de7af0e9833e1",
(
"0x1bb8810e2ceaf04786d4efd216fc2820ddd9363712efc736ada11049d8af5925",
"0x1efbf8d54c60d865cce08437668ea30f5bf90d287dbd9b5af31da852915e8f11",
),
),
(
"0xba35e127276e9000b33011860904ddee28f1d48ddd3577e2a797ef4a5e62319",
(
"0xda4a96147df1f35b0f820bd35c6fac3b80e8e320de7c536b1e054667b22c332",
"0x189bd3fbffe4c8740d6543754d95c790e44cd2d162858e3b733d2b8387983bb7",
),
),
(
"0x11852286660cd970e9d7f46f99c7cca2b75554245e91b9b19d537aa6147c28fc",
(
"0x2ff727cfaaadb3acab713fa22d91f5fddab3ed77948f3ef6233d7ea9b03f4da1",
"0x304080768fd2f87a852155b727f97db84b191e41970506f0326ed4046d1141aa",
),
),
(
"0x174d1c85d8a690a876cc1deba0166d30569fafdb49cb3ed28405bd1c5357a1cc",
(
"0x11a2eaa8e3e89de056d1b3a288a7f733c8a1282efa41d28e71af065ab245df9b",
"0x60f37c447ac29fd97b9bb83be98ddccf15e34831a9cdf5493b7fede0777ae06",
),
),
(
"0x73b81432b4cf3a8a9076201500d1b94159539f052a6e0928db7f2df74bff672",
(
"0x27409dccc6ee4ce90e24744fda8d72c0bc64e79766f778da0c1c0ef1c186ea84",
"0x1ac201a542feca15e77f30370da183514dc99d8a0b2c136d64ede35cd0b51dc0",
),
),
]
)
);

crate::curve_testing_suite!(
G1,
"constants",
Expand All @@ -279,6 +298,7 @@ mod test {
G1_GENERATOR_Y,
Fr::MODULUS
);

crate::curve_testing_suite!(
G2,
"constants",
Expand All @@ -289,4 +309,112 @@ mod test {
G2_GENERATOR_Y,
Fr::MODULUS
);

#[test]
fn test_hash_to_curve_g1() {
// Test vectors are taken from gnark-crypto/ecc/bn254/hash_vectors_test.go
[
TestH2C::<G1Affine>::new(
b"",
crate::tests::point_from_hex(
"0a976ab906170db1f9638d376514dbf8c42aef256a54bbd48521f20749e59e86",
"02925ead66b9e68bfc309b014398640ab55f6619ab59bc1fab2210ad4c4d53d5",
),
),
TestH2C::<G1Affine>::new(
b"abc",
crate::tests::point_from_hex(
"23f717bee89b1003957139f193e6be7da1df5f1374b26a4643b0378b5baf53d1",
"04142f826b71ee574452dbc47e05bc3e1a647478403a7ba38b7b93948f4e151d",
),
),
TestH2C::<G1Affine>::new(
b"abcdef0123456789",
crate::tests::point_from_hex(
"187dbf1c3c89aceceef254d6548d7163fdfa43084145f92c4c91c85c21442d4a",
"0abd99d5b0000910b56058f9cc3b0ab0a22d47cf27615f588924fac1e5c63b4d",
),
),
TestH2C::<G1Affine>::new(
b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
crate::tests::point_from_hex(
"00fe2b0743575324fc452d590d217390ad48e5a16cf051bee5c40a2eba233f5c",
"0794211e0cc72d3cbbdf8e4e5cd6e7d7e78d101ff94862caae8acbe63e9fdc78",
),
),
TestH2C::<G1Affine>::new(
b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
crate::tests::point_from_hex(
"01b05dc540bd79fd0fea4fbb07de08e94fc2e7bd171fe025c479dc212a2173ce",
"1bf028afc00c0f843d113758968f580640541728cfc6d32ced9779aa613cd9b0",
),
),
].iter().for_each(|test| {
test.run("QUUX-V01-CS02-with-");
});
}

#[test]
fn test_hash_to_curve_g2() {
pub(crate) fn point_from_hex(x0: &str, x1: &str, y0: &str, y1: &str) -> G2Affine {
let x0: Fq = crate::tests::hex_to_field(x0);
let x1: Fq = crate::tests::hex_to_field(x1);
let x = Fq2 { c0: x0, c1: x1 };
let y0: Fq = crate::tests::hex_to_field(y0);
let y1: Fq = crate::tests::hex_to_field(y1);
let y = Fq2 { c0: y0, c1: y1 };
G2Affine::from_xy(x, y).unwrap()
}

// Test vectors are taken from gnark-crypto/ecc/bn254/hash_vectors_test.go
[
TestH2C::<G2Affine>::new(
b"",
point_from_hex(
"1192005a0f121921a6d5629946199e4b27ff8ee4d6dd4f9581dc550ade851300",
"1747d950a6f23c16156e2171bce95d1189b04148ad12628869ed21c96a8c9335",
"0498f6bb5ac309a07d9a8b88e6ff4b8de0d5f27a075830e1eb0e68ea318201d8",
"2c9755350ca363ef2cf541005437221c5740086c2e909b71d075152484e845f4",
),
),
TestH2C::<G2Affine>::new(
b"abc",
point_from_hex(
"16c88b54eec9af86a41569608cd0f60aab43464e52ce7e6e298bf584b94fccd2",
"0b5db3ca7e8ef5edf3a33dfc3242357fbccead98099c3eb564b3d9d13cba4efd",
"1c42ba524cb74db8e2c680449746c028f7bea923f245e69f89256af2d6c5f3ac",
"22d02d2da7f288545ff8789e789902245ab08c6b1d253561eec789ec2c1bd630",
),
),
TestH2C::<G2Affine>::new(
b"abcdef0123456789",
point_from_hex(
"1435fd84aa43c699230e371f6fea3545ce7e053cbbb06a320296a2b81efddc70",
"2a8a360585b6b05996ef69c3c09b2c6fb17afe2b1e944f07559c53178eabf171",
"2820188dcdc13ffdca31694942418afa1d6dfaaf259d012fab4da52b0f592e38",
"142f08e2441ec431defc24621b73cfe0252d19b243cb55b84bdeb85de039207a",
),
),
TestH2C::<G2Affine>::new(
b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
point_from_hex(
"2cffc213fb63d00d923cb22cda5a2904837bb93a2fe6e875c532c51744388341",
"2718ef38d1bc4347f0266c774c8ef4ee5fa7056cc27a4bd7ecf7a888efb95b26",
"232553f728341afa64ce66d00535764557a052e38657594e10074ad28728c584",
"2206ec0a9288f31ed78531c37295df3b56c42a1284443ee9893adb1521779001",
),
),
TestH2C::<G2Affine>::new(
b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
point_from_hex(
"242a0a159f36f87065e7c5170426012087023165ce47a486e53d6e2845ca625a",
"17f9f6292998cf18ccc155903c1fe6b6465d40c794a3e1ed644a4182ad639f4a",
"2dc5b7b65c9c79e6ef4afab8fbe3083c66d4ce31c78f6621ece17ecc892cf4b3",
"18ef4886c818f01fdf309bc9a46dd904273917f85e74ecd0de62460a68122037",
),
),
].iter().for_each(|test| {
test.run("QUUX-V01-CS02-with-");
});
}
}
Loading

0 comments on commit f7c6b4c

Please sign in to comment.