Skip to content

Commit 8a28739

Browse files
j-bermanjeffro256kayabaNerve
committed
crypto: derive key image generator & separate {un}biased hash to ec
monero-project/research-lab#142 Co-authored-by: Jeffro <jeffro256@tutanota.com> Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
1 parent 4efde0f commit 8a28739

File tree

6 files changed

+321
-266
lines changed

6 files changed

+321
-266
lines changed

src/crypto/crypto.cpp

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "warnings.h"
4343
#include "crypto.h"
4444
#include "hash.h"
45+
#include "blake2b.h"
4546

4647
#include "cryptonote_config.h"
4748

@@ -608,7 +609,7 @@ namespace crypto {
608609
return sc_isnonzero(&c2) == 0;
609610
}
610611

611-
static void hash_to_ec(const public_key &key, ge_p3 &res) {
612+
static void biased_hash_to_ec(const public_key &key, ge_p3 &res) {
612613
hash h;
613614
ge_p2 point;
614615
ge_p1p1 point2;
@@ -618,11 +619,57 @@ namespace crypto {
618619
ge_p1p1_to_p3(&res, &point2);
619620
}
620621

622+
void crypto_ops::unbiased_hash_to_ec(const unsigned char *preimage, const std::size_t length, ec_point &res) {
623+
uint8_t hash[64];
624+
blake2b(std::addressof(hash), 64, preimage, length, NULL, 0);
625+
626+
ge_p2 first;
627+
ge_fromfe_frombytes_vartime(&first, reinterpret_cast<const unsigned char *>(&hash));
628+
ge_p1p1 first_p1p1;
629+
ge_mul8(&first_p1p1, &first);
630+
ge_p3 first_p3;
631+
ge_p1p1_to_p3(&first_p3, &first_p1p1);
632+
633+
ge_p2 second;
634+
ge_fromfe_frombytes_vartime(&second, reinterpret_cast<const unsigned char *>(&hash) + 32);
635+
ge_p1p1 second_p1p1;
636+
ge_mul8(&second_p1p1, &second);
637+
ge_p3 second_p3;
638+
ge_p1p1_to_p3(&second_p3, &second_p1p1);
639+
ge_cached second_cached;
640+
ge_p3_to_cached(&second_cached, &second_p3);
641+
642+
ge_p1p1 point;
643+
ge_add(&point, &first_p3, &second_cached);
644+
645+
ge_p3 res_ge_p3;
646+
ge_p1p1_to_p3(&res_ge_p3, &point);
647+
ge_p3_tobytes(&res, &res_ge_p3);
648+
}
649+
650+
static void biased_derive_key_image_generator(const public_key &pub, ec_point &ki_gen) {
651+
ge_p3 point;
652+
biased_hash_to_ec(pub, point);
653+
ge_p3_tobytes(&ki_gen, &point);
654+
}
655+
656+
static void unbiased_derive_key_image_generator(const public_key &pub, ec_point &ki_gen) {
657+
unbiased_hash_to_ec(&pub, sizeof(public_key), ki_gen);
658+
}
659+
660+
void crypto_ops::derive_key_image_generator(const public_key &pub, const bool biased, ec_point &ki_gen) {
661+
if (biased)
662+
biased_derive_key_image_generator(pub, ki_gen);
663+
else
664+
unbiased_derive_key_image_generator(pub, ki_gen);
665+
}
666+
667+
// key image derivation used before FCMP++/Carrot
621668
void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
622669
ge_p3 point;
623670
ge_p2 point2;
624671
assert(sc_check(&sec) == 0);
625-
hash_to_ec(pub, point);
672+
biased_hash_to_ec(pub, point);
626673
ge_scalarmult(&point2, &unwrap(sec), &point);
627674
ge_tobytes(&image, &point2);
628675
}
@@ -683,7 +730,7 @@ POP_WARNINGS
683730
random_scalar(k);
684731
ge_scalarmult_base(&tmp3, &k);
685732
ge_p3_tobytes(&buf->ab[i].a, &tmp3);
686-
hash_to_ec(*pubs[i], tmp3);
733+
biased_hash_to_ec(*pubs[i], tmp3);
687734
ge_scalarmult(&tmp2, &k, &tmp3);
688735
ge_tobytes(&buf->ab[i].b, &tmp2);
689736
} else {
@@ -695,7 +742,7 @@ POP_WARNINGS
695742
}
696743
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
697744
ge_tobytes(&buf->ab[i].a, &tmp2);
698-
hash_to_ec(*pubs[i], tmp3);
745+
biased_hash_to_ec(*pubs[i], tmp3);
699746
ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
700747
ge_tobytes(&buf->ab[i].b, &tmp2);
701748
sc_add(&sum, &sum, &sig[i].c);
@@ -740,7 +787,7 @@ POP_WARNINGS
740787
}
741788
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
742789
ge_tobytes(&buf->ab[i].a, &tmp2);
743-
hash_to_ec(*pubs[i], tmp3);
790+
biased_hash_to_ec(*pubs[i], tmp3);
744791
ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
745792
ge_tobytes(&buf->ab[i].b, &tmp2);
746793
sc_add(&sum, &sum, &sig[i].c);

src/crypto/crypto.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ namespace crypto {
129129
friend void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
130130
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
131131
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
132+
static void unbiased_hash_to_ec(const unsigned char *, const std::size_t, ec_point &);
133+
friend void unbiased_hash_to_ec(const unsigned char *, const std::size_t, ec_point &);
134+
static void derive_key_image_generator(const public_key &, const bool biased, ec_point &);
135+
friend void derive_key_image_generator(const public_key &, const bool biased, ec_point &);
132136
static void generate_key_image(const public_key &, const secret_key &, key_image &);
133137
friend void generate_key_image(const public_key &, const secret_key &, key_image &);
134138
static void generate_ring_signature(const hash &, const key_image &,
@@ -297,6 +301,10 @@ namespace crypto {
297301
crypto_ops::derive_view_tag(derivation, output_index, vt);
298302
}
299303

304+
inline void unbiased_hash_to_ec(const unsigned char *preimage, const std::size_t length, ec_point &res) {
305+
crypto_ops::unbiased_hash_to_ec(preimage, length, res);
306+
}
307+
300308
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
301309
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
302310
}

tests/crypto/crypto-tests.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ bool check_scalar(const crypto::ec_scalar &scalar);
4545
void random_scalar(crypto::ec_scalar &res);
4646
void hash_to_scalar(const void *data, std::size_t length, crypto::ec_scalar &res);
4747
void hash_to_point(const crypto::hash &h, crypto::ec_point &res);
48-
void hash_to_ec(const crypto::public_key &key, crypto::ec_point &res);
48+
void biased_hash_to_ec(const crypto::public_key &key, crypto::ec_point &res);
4949
bool check_ge_p3_identity_failure(const crypto::public_key &point);
5050
bool check_ge_p3_identity_success(const crypto::public_key &point);
5151
#endif

tests/crypto/crypto.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ void hash_to_point(const crypto::hash &h, crypto::ec_point &res) {
8080
crypto::ge_tobytes(crypto::operator &(res), &point);
8181
}
8282

83-
void hash_to_ec(const crypto::public_key &key, crypto::ec_point &res) {
83+
void biased_hash_to_ec(const crypto::public_key &key, crypto::ec_point &res) {
8484
crypto::ge_p3 tmp;
85-
crypto::hash_to_ec(key, tmp);
85+
crypto::biased_hash_to_ec(key, tmp);
8686
crypto::ge_p3_tobytes(crypto::operator &(res), &tmp);
8787
}
8888

tests/crypto/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ int main(int argc, char *argv[]) {
194194
if (expected != actual) {
195195
goto error;
196196
}
197-
} else if (cmd == "hash_to_ec") {
197+
} else if (cmd == "biased_hash_to_ec") {
198198
public_key key;
199199
ec_point expected, actual;
200200
get(input, key, expected);
201-
hash_to_ec(key, actual);
201+
biased_hash_to_ec(key, actual);
202202
if (expected != actual) {
203203
goto error;
204204
}

0 commit comments

Comments
 (0)