Browse Source

Bugfix: cpu: Corrections necessary to get 'c' and 'cryptopp' algorithms working on big endian

- Initialize const hash1 data from uint32_t array, to avoid unnecessary runtime hex2bin and make it native endian
- Iterate over nonces in native endian, and only convert from/to little endian as necessary
- fulltest function is no longer deprecated, and meant for checking a hash in native endian (rather than standard big endian)
Luke Dashjr 13 years ago
parent
commit
7709fc967f
5 changed files with 42 additions and 10 deletions
  1. 9 2
      driver-cpu.c
  2. 12 2
      miner.h
  3. 8 1
      sha256_cryptopp.c
  4. 10 3
      sha256_generic.c
  5. 3 2
      util.c

+ 9 - 2
driver-cpu.c

@@ -214,6 +214,13 @@ static int cpur_thr_id;
 static bool forced_n_threads;
 #endif
 
+static const uint32_t hash1_init[] = {
+	0,0,0,0,0,0,0,0,
+	0x80000000,
+	  0,0,0,0,0,0,
+	          0x100,
+};
+
 
 
 
@@ -241,7 +248,7 @@ double bench_algo_stage3(
 	uint32_t max_nonce = (1<<22);
 	uint32_t last_nonce = 0;
 
-	hex2bin(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000", 64);
+	memcpy(&hash1[0], &hash1_init[0], sizeof(hash1));
 
 	gettimeofday(&start, 0);
 			{
@@ -814,7 +821,7 @@ static int64_t cpu_scanhash(struct thr_info *thr, struct work *work, int64_t max
 	uint32_t last_nonce;
 	bool rc;
 
-	hex2bin(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000", 64);
+	memcpy(&hash1[0], &hash1_init[0], sizeof(hash1));
 CPUSearch:
 	last_nonce = first_nonce;
 	rc = false;

+ 12 - 2
miner.h

@@ -604,12 +604,22 @@ static inline void swap32yes(void*out, const void*in, size_t sz) {
 		(((uint32_t*)out)[swapcounter]) = swab32(((uint32_t*)in)[swapcounter]);
 }
 
+#define LOCAL_swap32(type, var, sz)  \
+	type __swapped_ ## var[sz * 4 / sizeof(type)];  \
+	swap32yes(__swapped_ ## var, var, sz);  \
+	var = __swapped_ ## var;  \
+// end
+
 #ifdef WORDS_BIGENDIAN
-#  define swap32tobe(out, in, sz)  (void)0
+#  define swap32tobe(out, in, sz)  ((out == in) ? (void)0 : memmove(out, in, sz))
+#  define LOCAL_swap32be(type, var, sz)  ;
 #  define swap32tole(out, in, sz)  swap32yes(out, in, sz)
+#  define LOCAL_swap32le(type, var, sz)  LOCAL_swap32(type, var, sz)
 #else
 #  define swap32tobe(out, in, sz)  swap32yes(out, in, sz)
-#  define swap32tole(out, in, sz)  (void)0
+#  define LOCAL_swap32be(type, var, sz)  LOCAL_swap32(type, var, sz)
+#  define swap32tole(out, in, sz)  ((out == in) ? (void)0 : memmove(out, in, sz))
+#  define LOCAL_swap32le(type, var, sz)  ;
 #endif
 
 static inline void swab256(void *dest_p, const void *src_p)

+ 8 - 1
sha256_cryptopp.c

@@ -105,18 +105,25 @@ bool scanhash_cryptopp(struct thr_info*thr, const unsigned char *midstate,
 
 	data += 64;
 
+	// Midstate and data are stored in little endian
+	LOCAL_swap32le(unsigned char, midstate, 32/4)
+	LOCAL_swap32le(unsigned char, data, 64/4)
+	uint32_t *nonce_w = (uint32_t *)(data + 12);
+
 	while (1) {
-		*nonce = n;
+		*nonce_w = n;
 
 		runhash(hash1, data, midstate);
 		runhash(hash, hash1, sha256_init_state);
 
 		if (unlikely((hash32[7] == 0) && fulltest(hash, target))) {
+			*nonce = htole32(n);
 			*last_nonce = n;
 			return true;
 		}
 
 		if ((n >= max_nonce) || thr->work_restart) {
+			*nonce = htole32(n);
 			*last_nonce = n;
 			return false;
 		}

+ 10 - 3
sha256_generic.c

@@ -51,8 +51,7 @@ static inline u32 Maj(u32 x, u32 y, u32 z)
 
 static inline void LOAD_OP(int I, u32 *W, const u8 *input)
 {
-	/* byteswap is commented out, because bitcoin input
-	 * is already big-endian
+	/* byteswap is handled once in scanhash_c
 	 */
 	W[I] = /* ntohl */ ( ((u32*)(input))[I] );
 }
@@ -251,20 +250,28 @@ bool scanhash_c(struct thr_info*thr, const unsigned char *midstate, unsigned cha
 
 	data += 64;
 
+	// Midstate and data are stored in little endian
+	LOCAL_swap32le(unsigned char, midstate, 32/4)
+	LOCAL_swap32le(unsigned char, data, 64/4)
+	uint32_t *nonce_w = (uint32_t *)(data + 12);
+
 	while (1) {
-		*nonce = n;
+		*nonce_w = n;
 
+		// runhash expects int32 data preprocessed into native endian
 		runhash(hash1, data, midstate);
 		runhash(hash, hash1, sha256_init_state);
 
 		stat_ctr++;
 
 		if (unlikely((hash32[7] == 0) && fulltest(hash, target))) {
+			*nonce = htole32(n);
 			*last_nonce = n;
 			return true;
 		}
 
 		if ((n >= max_nonce) || thr->work_restart) {
+			*nonce = htole32(n);
 			*last_nonce = n;
 			return false;
 		}

+ 3 - 2
util.c

@@ -752,11 +752,12 @@ bool hash_target_check_v(const unsigned char *hash, const unsigned char *target)
 	return rc;
 }
 
-// DEPRECATED: This uses an input hash that has every 4 bytes flipped
+// This operates on a native-endian SHA256 state
+// In other words, on little endian platforms, every 4 bytes are in reverse order
 bool fulltest(const unsigned char *hash, const unsigned char *target)
 {
 	unsigned char hash2[32];
-	swap32yes(hash2, hash, 32 / 4);
+	swap32tobe(hash2, hash, 32 / 4);
 	return hash_target_check_v(hash2, target);
 }