N
N
Nicholas Kim2015-03-10 12:33:26
Cryptography
Nicholas Kim, 2015-03-10 12:33:26

How to perform addition modulo 2^512?

Hello! It is necessary to perform the operation of addition modulo 2^512 for the "Stiribog" hashing algorithm described by the GOST 34.11-2012 standard. Two 512-bit numbers are added.
I studied the examples of implementations of this operation that I found, but they all use a bitwise shift, which is not in the language used. For example, in JavaScript it looks like this:

/* https://github.com/rudonick/crypto/blob/670cef467fc4ed19896baee6044710779a0843fb/gostR3411.js#L184 */
function add512(x, y) {
    var CF = 0, w0, w1;
    for (var i = 0; i < 16; i++) {
        w0 = (x[i] & 0xffff) + (y[i] & 0xffff) + (CF || 0);
        w1 = (x[i] >>> 16) + (y[i] >>> 16) + (w0 >>> 16);
        x[i] = (w0 & 0xffff) | (w1 << 16);
        CF = (w1 >>> 16);
    }
}

Or in C:
/* https://github.com/okazymyrov/stribog/blob/master/C/standard/stribog.c */
void AddModulo512(const unsigned char *a,const unsigned char *b,unsigned char *c)
{
  int i = 0, t = 0;

  for(i=63;i>=0;i--)
  {
    t = a[i] + b[i] + (t >> 8);
    c[i] = t & 0xFF;
  }
}

Question:
  • Is there a way to perform such an addition without a bitwise shift operation?
  • Maybe there is a way to express the bitwise shift in terms of other operations?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
A
Armenian Radio, 2015-03-10
@gbg

A bitwise shift to the right by 1 bit is a division by 2 with the fractional part discarded.
A bitwise shift left by 1 bit is a multiplication by 2. Do you know
about GMP ?

J
jcmvbkbc, 2015-03-10
@jcmvbkbc

I studied the examples of implementations of this operation that I found, but they all use a bitwise shift

But why? To determine if there was an overflow or not? But this can be determined simply by comparing the result of the addition (unsigned) with any of the terms: in case of overflow, the sum is less than any term.
Those. having arrays representing the 32-bit parts of the terms and the result can be written like this (C):
void AddModulo512(const uint32_t *a,const uint32_t *b, uint32_t *c)
{
    unsigned carry = 0;
    unsigned i;
    for (i = 0; i < 16; ++i) {
        c[i] = a[i] + b[i] + carry;
        carry = a[i] + carry < carry || c[i] < b[i];
    }
}

S
Sumor, 2015-03-10
@Sumor

It is not known what features of your programming language.
You can pervert and rewrite the code in C without using shift:

void AddModulo512(const unsigned char *a,const unsigned char *b,unsigned char *c)
{
  int i = 0, t = 0;
  unsigned char * pResult = (unsigned char *)(&t);
  unsigned char * pNext = pResult + 1;

  for(i=63;i>=0;i--)
  {
    t = a[i] + b[i] + *pNext;
    c[i] = *pResult;
  }
}

The point is that you are looking at the number as if it were an array of 4 bytes. In the older one there will be the result of adding two bytes, and in the second byte the result of overflow, which will go to the next byte of the result.
There is a suspicion that working with pointers will be slower than working with numbers. It all depends on the compiler though.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question