Parcourir la source

Add public domain ripemd160 implementation

Copied from pycrypto:

	https://github.com/pycrypto/pycrypto/blob/master/src/RIPEMD160.c

Signed-off-by: Sean Young <sean@mess.org>
Sean Young il y a 5 ans
Parent
commit
397685cdaa
8 fichiers modifiés avec 322 ajouts et 5 suppressions
  1. 1 1
      .github/workflows/test.yml
  2. 1 1
      Dockerfile
  3. 8 0
      src/emit/mod.rs
  4. BIN
      stdlib/ripemd160.bc
  5. 301 0
      stdlib/ripemd160.c
  6. BIN
      stdlib/stdlib.bc
  7. 7 2
      stdlib/stdlib.c
  8. 4 1
      stdlib/stdlib.h

+ 1 - 1
.github/workflows/test.yml

@@ -42,7 +42,7 @@ jobs:
         toolchain: stable
         override: true
     - name: Compile stdlib
-      run: clang-8 --target=wasm32 -c -emit-llvm -O3 -ffreestanding -fno-builtin -Wall stdlib.c sha3.c substrate.c
+      run: clang-8 --target=wasm32 -c -emit-llvm -O3 -ffreestanding -fno-builtin -Wall stdlib.c sha3.c substrate.c ripemd160.c
       working-directory:  ./stdlib
     - name: Build
       run: cargo build --verbose

+ 1 - 1
Dockerfile

@@ -17,7 +17,7 @@ COPY src src/src/
 COPY stdlib src/stdlib/
 COPY build.rs Cargo.toml src/
 WORKDIR /src/stdlib/
-RUN clang-8 --target=wasm32 -c -emit-llvm -O3 -ffreestanding -fno-builtin -Wall stdlib.c sha3.c substrate.c
+RUN clang-8 --target=wasm32 -c -emit-llvm -O3 -ffreestanding -fno-builtin -Wall stdlib.c sha3.c substrate.c ripemd160.c
 
 WORKDIR /src/
 RUN cargo build --release

+ 8 - 0
src/emit/mod.rs

@@ -4106,6 +4106,7 @@ impl<'a> Contract<'a> {
 
 static STDLIB_IR: &[u8] = include_bytes!("../../stdlib/stdlib.bc");
 static SHA3_IR: &[u8] = include_bytes!("../../stdlib/sha3.bc");
+static RIPEMD160_IR: &[u8] = include_bytes!("../../stdlib/ripemd160.bc");
 static SUBSTRATE_IR: &[u8] = include_bytes!("../../stdlib/substrate.bc");
 
 /// Return the stdlib as parsed llvm module. The solidity standard library is hardcoded into
@@ -4118,6 +4119,13 @@ fn load_stdlib<'a>(context: &'a Context, target: &crate::Target) -> Module<'a> {
     if let super::Target::Substrate = target {
         let memory = MemoryBuffer::create_from_memory_range(SUBSTRATE_IR, "substrate");
 
+        module
+            .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
+            .unwrap();
+
+        // substrate does not provide ripemd160
+        let memory = MemoryBuffer::create_from_memory_range(RIPEMD160_IR, "ripemd160");
+
         module
             .link_in_module(Module::parse_bitcode_from_buffer(&memory, context).unwrap())
             .unwrap();

BIN
stdlib/ripemd160.bc


+ 301 - 0
stdlib/ripemd160.c

@@ -0,0 +1,301 @@
+/*
+ * Source:
+ * https://github.com/pycrypto/pycrypto/blob/master/src/RIPEMD160.c
+ *
+ *  RIPEMD160.c : RIPEMD-160 implementation
+ *
+ * Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+ *
+ * ===================================================================
+ * The contents of this file are dedicated to the public domain.  To
+ * the extent that dedication to the public domain is not available,
+ * everyone is granted a worldwide, perpetual, royalty-free,
+ * non-exclusive license to exercise all rights associated with the
+ * contents of this file for any purpose whatsoever.
+ * No rights are reserved.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * ===================================================================
+ *
+ * Country of origin: Canada
+ *
+ * This implementation (written in C) is based on an implementation the author
+ * wrote in Python.
+ *
+ * This implementation was written with reference to the RIPEMD-160
+ * specification, which is available at:
+ * http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/
+ *
+ * It is also documented in the _Handbook of Applied Cryptography_, as
+ * Algorithm 9.55.  It's on page 30 of the following PDF file:
+ * http://www.cacr.math.uwaterloo.ca/hac/about/chap9.pdf
+ *
+ * The RIPEMD-160 specification doesn't really tell us how to do padding, but
+ * since RIPEMD-160 is inspired by MD4, you can use the padding algorithm from
+ * RFC 1320.
+ *
+ * According to http://www.users.zetnet.co.uk/hopwood/crypto/scan/md.html:
+ *   "RIPEMD-160 is big-bit-endian, little-byte-endian, and left-justified."
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "stdlib.h"
+
+#define RIPEMD160_DIGEST_SIZE 20
+#define BLOCK_SIZE 64
+
+typedef struct {
+    uint32_t h[5];      /* The current hash state */
+    uint64_t length;    /* Total number of _bits_ (not bytes) added to the
+                           hash.  This includes bits that have been buffered
+                           but not not fed through the compression function yet. */
+    union {
+        uint32_t w[16];
+        uint8_t b[64];
+    } buf;
+    uint8_t bufpos;     /* number of bytes currently in the buffer */
+} ripemd160_state;
+
+
+/* cyclic left-shift the 32-bit word n left by s bits */
+#define ROL(s, n) (((n) << (s)) | ((n) >> (32-(s))))
+
+/* Initial values for the chaining variables.
+ * This is just 0123456789ABCDEFFEDCBA9876543210F0E1D2C3 in little-endian. */
+static const uint32_t initial_h[5] = { 0x67452301u, 0xEFCDAB89u, 0x98BADCFEu, 0x10325476u, 0xC3D2E1F0u };
+
+/* Ordering of message words.  Based on the permutations rho(i) and pi(i), defined as follows:
+ *
+ *  rho(i) := { 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 }[i]  0 <= i <= 15
+ *
+ *  pi(i) := 9*i + 5 (mod 16)
+ *
+ *  Line  |  Round 1  |  Round 2  |  Round 3  |  Round 4  |  Round 5
+ * -------+-----------+-----------+-----------+-----------+-----------
+ *  left  |    id     |    rho    |   rho^2   |   rho^3   |   rho^4
+ *  right |    pi     |   rho pi  |  rho^2 pi |  rho^3 pi |  rho^4 pi
+ */
+
+/* Left line */
+static const uint8_t RL[5][16] = {
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },   /* Round 1: id */
+    { 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 },   /* Round 2: rho */
+    { 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12 },   /* Round 3: rho^2 */
+    { 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 },   /* Round 4: rho^3 */
+    { 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 }    /* Round 5: rho^4 */
+};
+
+/* Right line */
+static const uint8_t RR[5][16] = {
+    { 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12 },   /* Round 1: pi */
+    { 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2 },   /* Round 2: rho pi */
+    { 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13 },   /* Round 3: rho^2 pi */
+    { 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 },   /* Round 4: rho^3 pi */
+    { 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 }    /* Round 5: rho^4 pi */
+};
+
+/*
+ * Shifts - Since we don't actually re-order the message words according to
+ * the permutations above (we could, but it would be slower), these tables
+ * come with the permutations pre-applied.
+ */
+
+/* Shifts, left line */
+static const uint8_t SL[5][16] = {
+    { 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8 }, /* Round 1 */
+    { 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12 }, /* Round 2 */
+    { 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5 }, /* Round 3 */
+    { 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12 }, /* Round 4 */
+    { 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 }  /* Round 5 */
+};
+
+/* Shifts, right line */
+static const uint8_t SR[5][16] = {
+    { 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6 }, /* Round 1 */
+    { 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11 }, /* Round 2 */
+    { 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5 }, /* Round 3 */
+    { 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8 }, /* Round 4 */
+    { 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 }  /* Round 5 */
+};
+
+/* Boolean functions */
+
+#define F1(x, y, z) ((x) ^ (y) ^ (z))
+#define F2(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define F3(x, y, z) (((x) | ~(y)) ^ (z))
+#define F4(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define F5(x, y, z) ((x) ^ ((y) | ~(z)))
+
+/* Round constants, left line */
+static const uint32_t KL[5] = {
+    0x00000000u,    /* Round 1: 0 */
+    0x5A827999u,    /* Round 2: floor(2**30 * sqrt(2)) */
+    0x6ED9EBA1u,    /* Round 3: floor(2**30 * sqrt(3)) */
+    0x8F1BBCDCu,    /* Round 4: floor(2**30 * sqrt(5)) */
+    0xA953FD4Eu     /* Round 5: floor(2**30 * sqrt(7)) */
+};
+
+/* Round constants, right line */
+static const uint32_t KR[5] = {
+    0x50A28BE6u,    /* Round 1: floor(2**30 * cubert(2)) */
+    0x5C4DD124u,    /* Round 2: floor(2**30 * cubert(3)) */
+    0x6D703EF3u,    /* Round 3: floor(2**30 * cubert(5)) */
+    0x7A6D76E9u,    /* Round 4: floor(2**30 * cubert(7)) */
+    0x00000000u     /* Round 5: 0 */
+};
+
+/* The RIPEMD160 compression function.  Operates on self->buf */
+static void ripemd160_compress(ripemd160_state *self)
+{
+    uint8_t w, round;
+    uint32_t T;
+    uint32_t AL, BL, CL, DL, EL;    /* left line */
+    uint32_t AR, BR, CR, DR, ER;    /* right line */
+
+    /* Load the left and right lines with the initial state */
+    AL = AR = self->h[0];
+    BL = BR = self->h[1];
+    CL = CR = self->h[2];
+    DL = DR = self->h[3];
+    EL = ER = self->h[4];
+
+    /* Round 1 */
+    round = 0;
+    for (w = 0; w < 16; w++) { /* left line */
+        T = ROL(SL[round][w], AL + F1(BL, CL, DL) + self->buf.w[RL[round][w]] + KL[round]) + EL;
+        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
+    }
+    for (w = 0; w < 16; w++) { /* right line */
+        T = ROL(SR[round][w], AR + F5(BR, CR, DR) + self->buf.w[RR[round][w]] + KR[round]) + ER;
+        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
+    }
+
+    /* Round 2 */
+    round++;
+    for (w = 0; w < 16; w++) { /* left line */
+        T = ROL(SL[round][w], AL + F2(BL, CL, DL) + self->buf.w[RL[round][w]] + KL[round]) + EL;
+        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
+    }
+    for (w = 0; w < 16; w++) { /* right line */
+        T = ROL(SR[round][w], AR + F4(BR, CR, DR) + self->buf.w[RR[round][w]] + KR[round]) + ER;
+        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
+    }
+
+    /* Round 3 */
+    round++;
+    for (w = 0; w < 16; w++) { /* left line */
+        T = ROL(SL[round][w], AL + F3(BL, CL, DL) + self->buf.w[RL[round][w]] + KL[round]) + EL;
+        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
+    }
+    for (w = 0; w < 16; w++) { /* right line */
+        T = ROL(SR[round][w], AR + F3(BR, CR, DR) + self->buf.w[RR[round][w]] + KR[round]) + ER;
+        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
+    }
+
+    /* Round 4 */
+    round++;
+    for (w = 0; w < 16; w++) { /* left line */
+        T = ROL(SL[round][w], AL + F4(BL, CL, DL) + self->buf.w[RL[round][w]] + KL[round]) + EL;
+        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
+    }
+    for (w = 0; w < 16; w++) { /* right line */
+        T = ROL(SR[round][w], AR + F2(BR, CR, DR) + self->buf.w[RR[round][w]] + KR[round]) + ER;
+        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
+    }
+
+    /* Round 5 */
+    round++;
+    for (w = 0; w < 16; w++) { /* left line */
+        T = ROL(SL[round][w], AL + F5(BL, CL, DL) + self->buf.w[RL[round][w]] + KL[round]) + EL;
+        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
+    }
+    for (w = 0; w < 16; w++) { /* right line */
+        T = ROL(SR[round][w], AR + F1(BR, CR, DR) + self->buf.w[RR[round][w]] + KR[round]) + ER;
+        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
+    }
+
+    /* Final mixing stage */
+    T = self->h[1] + CL + DR;
+    self->h[1] = self->h[2] + DL + ER;
+    self->h[2] = self->h[3] + EL + AR;
+    self->h[3] = self->h[4] + AL + BR;
+    self->h[4] = self->h[0] + BL + CR;
+    self->h[0] = T;
+
+    /* Clear the buffer and wipe the temporary variables */
+    T = AL = BL = CL = DL = EL = AR = BR = CR = DR = ER = 0;
+    __memset(&self->buf, 0, sizeof(self->buf));
+    self->bufpos = 0;
+}
+
+static void ripemd160_update(ripemd160_state *self, const unsigned char *p, int length)
+{
+    unsigned int bytes_needed;
+
+    while (length > 0) {
+        /* Figure out how many bytes we need to fill the internal buffer. */
+        bytes_needed = 64 - self->bufpos;
+
+        if ((unsigned int) length >= bytes_needed) {
+            /* We have enough bytes, so copy them into the internal buffer and run
+             * the compression function. */
+            __memcpy(&self->buf.b[self->bufpos], p, bytes_needed);
+            self->bufpos += bytes_needed;
+            self->length += bytes_needed << 3;    /* length is in bits */
+            p += bytes_needed;
+            ripemd160_compress(self);
+            length -= bytes_needed;
+            continue;
+        }
+
+        /* We do not have enough bytes to fill the internal buffer.
+         * Copy what's there and return. */
+        __memcpy(&self->buf.b[self->bufpos], p, length);
+        self->bufpos += length;
+        self->length += length << 3;    /* length is in bits */
+        return;
+    }
+}
+
+static void ripemd160_digest(ripemd160_state *self, unsigned char *out)
+{
+    /* Append the padding */
+    self->buf.b[self->bufpos++] = 0x80;
+
+    if (self->bufpos > 56) {
+        self->bufpos = 64;
+        ripemd160_compress(self);
+    }
+
+    /* Append the length */
+    self->buf.w[14] = (uint32_t) (self->length & 0xFFFFffffu);
+    self->buf.w[15] = (uint32_t) ((self->length >> 32) & 0xFFFFffffu);
+    self->bufpos = 64;
+    ripemd160_compress(self);
+
+    /* Copy the final state into the output buffer */
+    __memcpy(out, &self->h, RIPEMD160_DIGEST_SIZE);
+}
+
+
+void ripemd160(void *in, int inlen, void *out)
+{
+    ripemd160_state state;
+
+    __memset(&state, 0, sizeof(state));
+    __memcpy(&state.h, initial_h, sizeof(initial_h));
+
+    ripemd160_update(&state, in, inlen);
+
+    ripemd160_digest(&state, out);
+}
+
+/* vim:set ts=4 sw=4 sts=4 expandtab: */

BIN
stdlib/stdlib.bc


+ 7 - 2
stdlib/stdlib.c

@@ -17,8 +17,10 @@ void __memset8(void *_dest, uint64_t val, size_t length)
 	} while (--length);
 }
 
-void __memset(uint8_t *dest, uint8_t val, size_t length)
+void __memset(void *_dest, uint8_t val, size_t length)
 {
+	uint8_t *dest = _dest;
+
 	do
 	{
 		*dest++ = val;
@@ -39,8 +41,11 @@ void __memcpy8(void *_dest, void *_src, size_t length)
 	} while (--length);
 }
 
-void __memcpy(uint8_t *dest, uint8_t *src, size_t length)
+void __memcpy(void *_dest, const void *_src, size_t length)
 {
+	uint8_t *dest = _dest;
+	const uint8_t *src = _src;
+
 	while (length--)
 	{
 		*dest++ = *src++;

+ 4 - 1
stdlib/stdlib.h

@@ -8,4 +8,7 @@ struct vector
     uint8_t data[];
 };
 
-void *__malloc(size_t size);
+void *__malloc(size_t size);
+void __memset(void *dest, uint8_t val, size_t length);
+void __memcpy(void *dest, const void *src, size_t length);
+