public unsafe void Compress33Test() { int dataLen = 33; byte[] data = GetRandomBytes(dataLen); byte[] expected = ComputeSingleSha(data); using Sha256Fo sha = new Sha256Fo(); fixed(uint *hPt = &sha.hashState[0], wPt = &sha.w[0]) { int dIndex = 0; for (int i = 0; i < 8; i++, dIndex += 4) { wPt[i] = (uint)((data[dIndex] << 24) | (data[dIndex + 1] << 16) | (data[dIndex + 2] << 8) | data[dIndex + 3]); } wPt[8] = (uint)data[32] << 24 | 0b00000000_10000000_00000000_00000000U; wPt[15] = (uint)dataLen * 8; sha.Init(hPt); sha.Compress33(hPt, wPt); byte[] actual = sha.GetBytes(hPt); Assert.Equal(expected, actual); } }
public unsafe byte[] Compress33(byte[] data) { fixed(byte *dPt = data) fixed(uint *rip_blkPt = &rip.block[0], rip_hPt = &rip.hashState[0], sh_wPt = &sha.w[0]) { // Step 1: compute SHA256 of data then copy result of hash (HashState) into RIPEMD160 block // so we just pass RIPEMD160 block as HashState of SHA256 sha.Init(rip_blkPt); int dIndex = 0; for (int i = 0; i < 8; i++, dIndex += 4) { sh_wPt[i] = (uint)((dPt[dIndex] << 24) | (dPt[dIndex + 1] << 16) | (dPt[dIndex + 2] << 8) | dPt[dIndex + 3]); } sh_wPt[8] = (uint)((dPt[dIndex] << 24) | 0b00000000_10000000_00000000_00000000U); sh_wPt[9] = 0; sh_wPt[10] = 0; sh_wPt[11] = 0; sh_wPt[12] = 0; sh_wPt[13] = 0; sh_wPt[14] = 0; // Message length for pad2, 33 byte or 264 bits sh_wPt[15] = 264; sha.Compress33(rip_blkPt, sh_wPt); // SHA256 compression is over and the result is already inside RIPEMD160 Block // But SHA256 endianness is reverse of RIPEMD160, so we have to do an endian swap // 32 byte or 8 uint items coming from SHA256 for (int i = 0; i < 8; i++) { // RIPEMD160 uses little-endian while SHA256 uses big-endian rip_blkPt[i] = (rip_blkPt[i] >> 24) | (rip_blkPt[i] << 24) | // Swap byte 1 and 4 ((rip_blkPt[i] >> 8) & 0xff00) | ((rip_blkPt[i] << 8) & 0xff0000); // Swap byte 2 and 3 } rip_blkPt[8] = 0b00000000_00000000_00000000_10000000U; rip_blkPt[14] = 256; // rip_blkPt[15] = 0; // There is no need to set other items in block (like 13, 12,...) // because they are not changed and they are always zero rip.Init(rip_hPt); rip.CompressBlock(rip_blkPt, rip_hPt); return(rip.GetBytes(rip_hPt)); } }
public static unsafe byte[] Compress33(Span <byte> data) { uint *pt = stackalloc uint[Sha256Fo.UBufferSize]; fixed(byte *dPt = data) { pt[8] = (uint)((dPt[0] << 24) | (dPt[1] << 16) | (dPt[2] << 8) | dPt[3]); pt[9] = (uint)((dPt[4] << 24) | (dPt[5] << 16) | (dPt[6] << 8) | dPt[7]); pt[10] = (uint)((dPt[8] << 24) | (dPt[9] << 16) | (dPt[10] << 8) | dPt[11]); pt[11] = (uint)((dPt[12] << 24) | (dPt[13] << 16) | (dPt[14] << 8) | dPt[15]); pt[12] = (uint)((dPt[16] << 24) | (dPt[17] << 16) | (dPt[18] << 8) | dPt[19]); pt[13] = (uint)((dPt[20] << 24) | (dPt[21] << 16) | (dPt[22] << 8) | dPt[23]); pt[14] = (uint)((dPt[24] << 24) | (dPt[25] << 16) | (dPt[26] << 8) | dPt[27]); pt[15] = (uint)((dPt[28] << 24) | (dPt[29] << 16) | (dPt[30] << 8) | dPt[31]); pt[16] = (uint)((dPt[32] << 24) | 0b00000000_10000000_00000000_00000000U); pt[23] = 264; Sha256Fo.Init(pt); Sha256Fo.Compress33(pt); // Compute RIPEMD160 pt[12] = (pt[7] >> 24) | (pt[7] << 24) | ((pt[7] >> 8) & 0xff00) | ((pt[7] << 8) & 0xff0000); pt[11] = (pt[6] >> 24) | (pt[6] << 24) | ((pt[6] >> 8) & 0xff00) | ((pt[6] << 8) & 0xff0000); pt[10] = (pt[5] >> 24) | (pt[5] << 24) | ((pt[5] >> 8) & 0xff00) | ((pt[5] << 8) & 0xff0000); pt[9] = (pt[4] >> 24) | (pt[4] << 24) | ((pt[4] >> 8) & 0xff00) | ((pt[4] << 8) & 0xff0000); pt[8] = (pt[3] >> 24) | (pt[3] << 24) | ((pt[3] >> 8) & 0xff00) | ((pt[3] << 8) & 0xff0000); pt[7] = (pt[2] >> 24) | (pt[2] << 24) | ((pt[2] >> 8) & 0xff00) | ((pt[2] << 8) & 0xff0000); pt[6] = (pt[1] >> 24) | (pt[1] << 24) | ((pt[1] >> 8) & 0xff00) | ((pt[1] << 8) & 0xff0000); pt[5] = (pt[0] >> 24) | (pt[0] << 24) | // Swap byte 1 and 4 ((pt[0] >> 8) & 0xff00) | ((pt[0] << 8) & 0xff0000); // Swap byte 2 and 3 pt[13] = 0b00000000_00000000_00000000_10000000U; pt[14] = 0; pt[15] = 0; pt[16] = 0; pt[19] = 256; Ripemd160Fo.Init(pt); Ripemd160Fo.CompressBlock(pt); return(Ripemd160Fo.GetBytes(pt)); } }
/// <summary> /// Returns HASH160(OP_0 | Push(HASH160(33_bytes))) /// </summary> public unsafe byte[] Compress33_P2sh(Span <byte> data) { fixed(byte *dPt = data) fixed(uint *rip_blkPt = &rip.block[0], rip_hPt = &rip.hashState[0], sh_wPt = &sha.w[0]) { sh_wPt[0] = (uint)((dPt[0] << 24) | (dPt[1] << 16) | (dPt[2] << 8) | dPt[3]); sh_wPt[1] = (uint)((dPt[4] << 24) | (dPt[5] << 16) | (dPt[6] << 8) | dPt[7]); sh_wPt[2] = (uint)((dPt[8] << 24) | (dPt[9] << 16) | (dPt[10] << 8) | dPt[11]); sh_wPt[3] = (uint)((dPt[12] << 24) | (dPt[13] << 16) | (dPt[14] << 8) | dPt[15]); sh_wPt[4] = (uint)((dPt[16] << 24) | (dPt[17] << 16) | (dPt[18] << 8) | dPt[19]); sh_wPt[5] = (uint)((dPt[20] << 24) | (dPt[21] << 16) | (dPt[22] << 8) | dPt[23]); sh_wPt[6] = (uint)((dPt[24] << 24) | (dPt[25] << 16) | (dPt[26] << 8) | dPt[27]); sh_wPt[7] = (uint)((dPt[28] << 24) | (dPt[29] << 16) | (dPt[30] << 8) | dPt[31]); sh_wPt[8] = (uint)((dPt[32] << 24) | 0b00000000_10000000_00000000_00000000U); sh_wPt[9] = 0; sh_wPt[10] = 0; sh_wPt[11] = 0; sh_wPt[12] = 0; sh_wPt[13] = 0; sh_wPt[14] = 0; sh_wPt[15] = 264; sha.Init(rip_blkPt); sha.Compress33(rip_blkPt, sh_wPt); for (int i = 0; i < 8; i++) { // RIPEMD160 uses little-endian while SHA256 uses big-endian rip_blkPt[i] = (rip_blkPt[i] >> 24) | (rip_blkPt[i] << 24) | // Swap byte 1 and 4 ((rip_blkPt[i] >> 8) & 0xff00) | ((rip_blkPt[i] << 8) & 0xff0000); // Swap byte 2 and 3 } rip_blkPt[8] = 0b00000000_00000000_00000000_10000000U; rip_blkPt[14] = 256; rip.Init(rip_hPt); rip.CompressBlock(rip_blkPt, rip_hPt); // Compute second HASH160 sh_wPt[0] = 0x00140000U | ((rip_hPt[0] << 8) & 0xff00) | ((rip_hPt[0] >> 8) & 0xff); sh_wPt[1] = ((rip_hPt[0] << 8) & 0xff000000) | ((rip_hPt[0] >> 8) & 0x00ff0000) | ((rip_hPt[1] << 8) & 0x0000ff00) | ((rip_hPt[1] >> 8) & 0x000000ff); sh_wPt[2] = ((rip_hPt[1] << 8) & 0xff000000) | ((rip_hPt[1] >> 8) & 0x00ff0000) | ((rip_hPt[2] << 8) & 0x0000ff00) | ((rip_hPt[2] >> 8) & 0x000000ff); sh_wPt[3] = ((rip_hPt[2] << 8) & 0xff000000) | ((rip_hPt[2] >> 8) & 0x00ff0000) | ((rip_hPt[3] << 8) & 0x0000ff00) | ((rip_hPt[3] >> 8) & 0x000000ff); sh_wPt[4] = ((rip_hPt[3] << 8) & 0xff000000) | ((rip_hPt[3] >> 8) & 0x00ff0000) | ((rip_hPt[4] << 8) & 0x0000ff00) | ((rip_hPt[4] >> 8) & 0x000000ff); sh_wPt[5] = ((rip_hPt[4] << 8) & 0xff000000) | ((rip_hPt[4] >> 8) & 0x00ff0000) | 0b00000000_00000000_10000000_00000000U; sh_wPt[6] = 0; sh_wPt[7] = 0; sh_wPt[8] = 0; // 9 to 14 are already 0 sh_wPt[15] = 176; // 22*8 sha.Init(rip_blkPt); sha.Compress22(rip_blkPt, sh_wPt); for (int i = 0; i < 8; i++) { // RIPEMD160 uses little-endian while SHA256 uses big-endian rip_blkPt[i] = (rip_blkPt[i] >> 24) | (rip_blkPt[i] << 24) | // Swap byte 1 and 4 ((rip_blkPt[i] >> 8) & 0xff00) | ((rip_blkPt[i] << 8) & 0xff0000); // Swap byte 2 and 3 } rip_blkPt[8] = 0b00000000_00000000_00000000_10000000U; rip_blkPt[14] = 256; rip.Init(rip_hPt); rip.CompressBlock(rip_blkPt, rip_hPt); return(rip.GetBytes(rip_hPt)); } }