| @@ -61,6 +61,14 @@ void API_NS(private_to_public) ( | |||||
| memcpy(pub, priv->pub, sizeof(API_NS(public_key_t))); | memcpy(pub, priv->pub, sizeof(API_NS(public_key_t))); | ||||
| } | } | ||||
| /* Performance vs consttime tuning. | |||||
| * Specifying true here might give better DOS resistance in certain corner | |||||
| * cases. Specifying false gives a tighter result in test_ct. | |||||
| */ | |||||
| #ifndef DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||||
| #define DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT DECAF_FALSE | |||||
| #endif | |||||
| decaf_error_t | decaf_error_t | ||||
| API_NS(shared_secret) ( | API_NS(shared_secret) ( | ||||
| uint8_t *shared, | uint8_t *shared, | ||||
| @@ -82,7 +90,8 @@ API_NS(shared_secret) ( | |||||
| strobe_ad(strobe,my_privkey->pub,sizeof(API_NS(public_key_t))); | strobe_ad(strobe,my_privkey->pub,sizeof(API_NS(public_key_t))); | ||||
| } | } | ||||
| decaf_error_t ret = API_NS(direct_scalarmul)( | decaf_error_t ret = API_NS(direct_scalarmul)( | ||||
| ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE | |||||
| ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, | |||||
| DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||||
| ); | ); | ||||
| strobe_transact(strobe,NULL,ss_ser,sizeof(ss_ser),STROBE_CW_DH_KEY); | strobe_transact(strobe,NULL,ss_ser,sizeof(ss_ser),STROBE_CW_DH_KEY); | ||||
| @@ -161,6 +161,16 @@ public: | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| /** Derive a shared secret */ | |||||
| inline decaf_error_t __attribute__((warn_unused_result)) | |||||
| sharedSecretNoexcept( | |||||
| Buffer ret, | |||||
| const PublicKey<%(cxx_ns)s> &pub, | |||||
| bool me_first | |||||
| ) const NOEXCEPT { | |||||
| return %(c_ns)s_shared_secret(ret.data(),ret.size(),wrapped,pub.wrapped,me_first); | |||||
| } | |||||
| /** Sign a message. */ | /** Sign a message. */ | ||||
| inline SecureBuffer sign(const Block &message) const { | inline SecureBuffer sign(const Block &message) const { | ||||
| @@ -88,7 +88,7 @@ public: | |||||
| /** Construct from RNG */ | /** Construct from RNG */ | ||||
| inline explicit Scalar(Rng &rng) NOEXCEPT { | inline explicit Scalar(Rng &rng) NOEXCEPT { | ||||
| FixedArrayBuffer<SER_BYTES> sb(rng); | |||||
| FixedArrayBuffer<SER_BYTES + 16> sb(rng); | |||||
| *this = sb; | *this = sb; | ||||
| } | } | ||||
| @@ -445,9 +445,8 @@ public: | |||||
| if (buf.size() < HASH_BYTES) { | if (buf.size() < HASH_BYTES) { | ||||
| ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size()); | ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size()); | ||||
| } | } | ||||
| if (ret) { | |||||
| /* TODO: make this constant time?? */ | |||||
| memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES); | |||||
| for (size_t i=0; i<buf.size() && i<HASH_BYTES; i++) { | |||||
| buf[i] = (buf[i] & ~ret) | (buf2[i] &ret); | |||||
| } | } | ||||
| decaf_bzero(buf2,sizeof(buf2)); | decaf_bzero(buf2,sizeof(buf2)); | ||||
| return decaf_succeed_if(ret); | return decaf_succeed_if(ret); | ||||
| @@ -55,11 +55,13 @@ static void test_arithmetic() { | |||||
| static void test_elligator() { | static void test_elligator() { | ||||
| SpongeRng rng(Block("test_elligator")); | SpongeRng rng(Block("test_elligator")); | ||||
| rng.stir(undef_block); | rng.stir(undef_block); | ||||
| FixedArrayBuffer<Group::Point::HASH_BYTES> inv; | |||||
| for (int i=0; i<NTESTS; i++) { | for (int i=0; i<NTESTS; i++) { | ||||
| Point x(rng); | |||||
| (void)x; | |||||
| /* TODO: uniform, nonuniform... */ | |||||
| Point x(rng), y(rng,false); | |||||
| ignore((x+y).invert_elligator(inv,i)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -82,7 +84,7 @@ static void test_ec() { | |||||
| (void)(p.times_two()); | (void)(p.times_two()); | ||||
| (void)(p==q); | (void)(p==q); | ||||
| (void)(p.debugging_torque()); | (void)(p.debugging_torque()); | ||||
| //(void)(p.non_secret_combo_with_base(y,z)); // Should fail | |||||
| /* (void)(p.non_secret_combo_with_base(y,z)); */ /* Should fail */ | |||||
| (void)(Precomputed(p)*y); | (void)(Precomputed(p)*y); | ||||
| p.dual_scalarmul(q,r,y,z); | p.dual_scalarmul(q,r,y,z); | ||||
| Group::Point::double_scalarmul(p,y,q,z); | Group::Point::double_scalarmul(p,y,q,z); | ||||
| @@ -90,17 +92,32 @@ static void test_ec() { | |||||
| } | } | ||||
| } | } | ||||
| /* Specify the same value as you did when compiling decaf_crypto.c */ | |||||
| #ifndef DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||||
| #define DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT DECAF_FALSE | |||||
| #endif | |||||
| static void test_crypto() { | static void test_crypto() { | ||||
| SpongeRng rng(Block("test_crypto")); | SpongeRng rng(Block("test_crypto")); | ||||
| rng.stir(undef_block); | rng.stir(undef_block); | ||||
| #if DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||||
| SpongeRng defrng(Block("test_crypto_defined")); | |||||
| #endif | |||||
| FixedArrayBuffer<Group::Point::SER_BYTES> shared; | |||||
| for (int i=0; i<NTESTS; i++) { | for (int i=0; i<NTESTS; i++) { | ||||
| PrivateKey<Group> sk1(rng); | PrivateKey<Group> sk1(rng); | ||||
| PrivateKey<Group> sk2(rng); | |||||
| SecureBuffer sig = sk1.sign(undef_block); | SecureBuffer sig = sk1.sign(undef_block); | ||||
| //sk.pub().verify(undef_block,sig); would fail. FUTURE: ct version of this? | |||||
| /* TODO: shared_secret nothrow? have to test shared_secret... */ | |||||
| #if DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||||
| PrivateKey<Group> sk2(defrng); | |||||
| (void)sk1.sharedSecretNoexcept(shared,sk2.pub(),i&1); | |||||
| #else | |||||
| PrivateKey<Group> sk3(rng); | |||||
| (void)sk1.sharedSecretNoexcept(shared,sk3.pub(),i&1); | |||||
| #endif | |||||
| } | } | ||||
| } | } | ||||