Fix order comparison.
[novacoin.git] / src / key.cpp
index 381d346..85391ed 100644 (file)
@@ -120,6 +120,51 @@ err:
     return ret;
 }
 
+int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
+    while (c1len > c2len) {
+        if (*c1)
+            return 1;
+        c1++;
+        c1len--;
+    }
+    while (c2len > c1len) {
+        if (*c2)
+            return -1;
+        c2++;
+        c2len--;
+    }
+    while (c1len > 0) {
+        if (*c1 > *c2)
+            return 1;
+        if (*c2 > *c1)
+            return -1;
+        c1++;
+        c2++;
+        c1len--;
+    }
+    return 0;
+}
+
+// Order of secp256k1's generator minus 1.
+const unsigned char vchMaxModOrder[32] = {
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+    0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
+    0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
+};
+
+// Half of the order of secp256k1's generator minus 1.
+const unsigned char vchMaxModHalfOrder[32] = {
+    0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D,
+    0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0
+};
+
+const unsigned char vchZero[0] = {};
+
+
+
 void CKey::SetCompressedPubKey()
 {
     EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
@@ -174,6 +219,11 @@ bool CKey::IsCompressed() const
     return fCompressedPubKey;
 }
 
+bool CKey::CheckSignatureElement(const unsigned char *vch, int len, bool half) {
+    return CompareBigEndian(vch, len, vchZero, 0) > 0 &&
+        CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0;
+}
+
 void CKey::MakeNewKey(bool fCompressed)
 {
     if (!EC_KEY_generate_key(pkey))
@@ -289,11 +339,12 @@ bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
     ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
     if (sig==NULL)
         return false;
-    // Force even S value in order to prevent signature modification issues.
-    if (BN_is_odd(sig->s)) {
-        const EC_GROUP *group = EC_KEY_get0_group(pkey);
-        CBigNum order;
-        EC_GROUP_get_order(group, &order, NULL);
+    const EC_GROUP *group = EC_KEY_get0_group(pkey);
+    CBigNum order, halforder;
+    EC_GROUP_get_order(group, &order, NULL);
+    BN_rshift1(&halforder, &order);
+    // enforce low S values, by negating the value (modulo the order) if above order/2.
+    if (BN_cmp(sig->s, &halforder) > 0) {
         BN_sub(sig->s, &order, sig->s);
     }
     unsigned int nSize = ECDSA_size(pkey);
@@ -320,11 +371,12 @@ bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
     ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
     if (sig==NULL)
         return false;
-    // Force even S value in order to prevent signature modification issues.
-    if (BN_is_odd(sig->s)) {
-        const EC_GROUP *group = EC_KEY_get0_group(pkey);
-        CBigNum order;
-        EC_GROUP_get_order(group, &order, NULL);
+    const EC_GROUP *group = EC_KEY_get0_group(pkey);
+    CBigNum order, halforder;
+    EC_GROUP_get_order(group, &order, NULL);
+    BN_rshift1(&halforder, &order);
+    // enforce low S values, by negating the value (modulo the order) if above order/2.
+    if (BN_cmp(sig->s, &halforder) > 0) {
         BN_sub(sig->s, &order, sig->s);
     }
     vchSig.clear();