github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/others/siphash/siphash.go (about)

     1  // Written in 2012-2014 by Dmitry Chestnykh.
     2  //
     3  // To the extent possible under law, the author have dedicated all copyright
     4  // and related and neighboring rights to this software to the public domain
     5  // worldwide. This software is distributed without any warranty.
     6  // http://creativecommons.org/publicdomain/zero/1.0/
     7  
     8  // Package siphash implements SipHash-2-4, a fast short-input PRF
     9  // created by Jean-Philippe Aumasson and Daniel J. Bernstein.
    10  package siphash
    11  
    12  import "hash"
    13  
    14  const (
    15  	// BlockSize is the block size of hash algorithm in bytes.
    16  	BlockSize = 8
    17  
    18  	// Size is the size of hash output in bytes.
    19  	Size = 8
    20  
    21  	// Size128 is the size of 128-bit hash output in bytes.
    22  	Size128 = 16
    23  )
    24  
    25  type digest struct {
    26  	v0, v1, v2, v3 uint64  // state
    27  	k0, k1         uint64  // two parts of key
    28  	x              [8]byte // buffer for unprocessed bytes
    29  	nx             int     // number of bytes in buffer x
    30  	size           int     // output size in bytes (8 or 16)
    31  	t              uint8   // message bytes counter (mod 256)
    32  }
    33  
    34  // newDigest returns a new digest with the given output size in bytes (must be 8 or 16).
    35  func newDigest(size int, key []byte) *digest {
    36  	if size != Size && size != Size128 {
    37  		panic("size must be 8 or 16")
    38  	}
    39  	d := new(digest)
    40  	d.k0 = uint64(key[0]) | uint64(key[1])<<8 | uint64(key[2])<<16 | uint64(key[3])<<24 |
    41  		uint64(key[4])<<32 | uint64(key[5])<<40 | uint64(key[6])<<48 | uint64(key[7])<<56
    42  	d.k1 = uint64(key[8]) | uint64(key[9])<<8 | uint64(key[10])<<16 | uint64(key[11])<<24 |
    43  		uint64(key[12])<<32 | uint64(key[13])<<40 | uint64(key[14])<<48 | uint64(key[15])<<56
    44  	d.size = size
    45  	d.Reset()
    46  	return d
    47  }
    48  
    49  // New returns a new hash.Hash64 computing SipHash-2-4 with 16-byte key and 8-byte output.
    50  func New(key []byte) hash.Hash64 {
    51  	return newDigest(Size, key)
    52  }
    53  
    54  // New128 returns a new hash.Hash computing SipHash-2-4 with 16-byte key and 16-byte output.
    55  //
    56  // Note that 16-byte output is considered experimental by SipHash authors at this time.
    57  func New128(key []byte) hash.Hash {
    58  	return newDigest(Size128, key)
    59  }
    60  
    61  func (d *digest) Reset() {
    62  	d.v0 = d.k0 ^ 0x736f6d6570736575
    63  	d.v1 = d.k1 ^ 0x646f72616e646f6d
    64  	d.v2 = d.k0 ^ 0x6c7967656e657261
    65  	d.v3 = d.k1 ^ 0x7465646279746573
    66  	d.t = 0
    67  	d.nx = 0
    68  	if d.size == Size128 {
    69  		d.v1 ^= 0xee
    70  	}
    71  }
    72  
    73  func (d *digest) Size() int { return d.size }
    74  
    75  func (d *digest) BlockSize() int { return BlockSize }
    76  
    77  func (d *digest) Write(p []byte) (nn int, err error) {
    78  	nn = len(p)
    79  	d.t += uint8(nn)
    80  	if d.nx > 0 {
    81  		n := len(p)
    82  		if n > BlockSize-d.nx {
    83  			n = BlockSize - d.nx
    84  		}
    85  		d.nx += copy(d.x[d.nx:], p)
    86  		if d.nx == BlockSize {
    87  			once(d)
    88  			d.nx = 0
    89  		}
    90  		p = p[n:]
    91  	}
    92  	if len(p) >= BlockSize {
    93  		n := len(p) &^ (BlockSize - 1)
    94  		blocks(d, p[:n])
    95  		p = p[n:]
    96  	}
    97  	if len(p) > 0 {
    98  		d.nx = copy(d.x[:], p)
    99  	}
   100  	return
   101  }
   102  
   103  func (d *digest) Sum64() uint64 {
   104  	for i := d.nx; i < BlockSize-1; i++ {
   105  		d.x[i] = 0
   106  	}
   107  	d.x[7] = d.t
   108  	return finalize(d)
   109  }
   110  
   111  func (d0 *digest) sum128() (r0, r1 uint64) {
   112  	// Make a copy of d0 so that caller can keep writing and summing.
   113  	d := *d0
   114  
   115  	for i := d.nx; i < BlockSize-1; i++ {
   116  		d.x[i] = 0
   117  	}
   118  	d.x[7] = d.t
   119  	blocks(&d, d.x[:])
   120  
   121  	v0, v1, v2, v3 := d.v0, d.v1, d.v2, d.v3
   122  	v2 ^= 0xee
   123  
   124  	// Round 1.
   125  	v0 += v1
   126  	v1 = v1<<13 | v1>>(64-13)
   127  	v1 ^= v0
   128  	v0 = v0<<32 | v0>>(64-32)
   129  
   130  	v2 += v3
   131  	v3 = v3<<16 | v3>>(64-16)
   132  	v3 ^= v2
   133  
   134  	v0 += v3
   135  	v3 = v3<<21 | v3>>(64-21)
   136  	v3 ^= v0
   137  
   138  	v2 += v1
   139  	v1 = v1<<17 | v1>>(64-17)
   140  	v1 ^= v2
   141  	v2 = v2<<32 | v2>>(64-32)
   142  
   143  	// Round 2.
   144  	v0 += v1
   145  	v1 = v1<<13 | v1>>(64-13)
   146  	v1 ^= v0
   147  	v0 = v0<<32 | v0>>(64-32)
   148  
   149  	v2 += v3
   150  	v3 = v3<<16 | v3>>(64-16)
   151  	v3 ^= v2
   152  
   153  	v0 += v3
   154  	v3 = v3<<21 | v3>>(64-21)
   155  	v3 ^= v0
   156  
   157  	v2 += v1
   158  	v1 = v1<<17 | v1>>(64-17)
   159  	v1 ^= v2
   160  	v2 = v2<<32 | v2>>(64-32)
   161  
   162  	// Round 3.
   163  	v0 += v1
   164  	v1 = v1<<13 | v1>>(64-13)
   165  	v1 ^= v0
   166  	v0 = v0<<32 | v0>>(64-32)
   167  
   168  	v2 += v3
   169  	v3 = v3<<16 | v3>>(64-16)
   170  	v3 ^= v2
   171  
   172  	v0 += v3
   173  	v3 = v3<<21 | v3>>(64-21)
   174  	v3 ^= v0
   175  
   176  	v2 += v1
   177  	v1 = v1<<17 | v1>>(64-17)
   178  	v1 ^= v2
   179  	v2 = v2<<32 | v2>>(64-32)
   180  
   181  	// Round 4.
   182  	v0 += v1
   183  	v1 = v1<<13 | v1>>(64-13)
   184  	v1 ^= v0
   185  	v0 = v0<<32 | v0>>(64-32)
   186  
   187  	v2 += v3
   188  	v3 = v3<<16 | v3>>(64-16)
   189  	v3 ^= v2
   190  
   191  	v0 += v3
   192  	v3 = v3<<21 | v3>>(64-21)
   193  	v3 ^= v0
   194  
   195  	v2 += v1
   196  	v1 = v1<<17 | v1>>(64-17)
   197  	v1 ^= v2
   198  	v2 = v2<<32 | v2>>(64-32)
   199  
   200  	r0 = v0 ^ v1 ^ v2 ^ v3
   201  
   202  	v1 ^= 0xdd
   203  
   204  	// Round 1.
   205  	v0 += v1
   206  	v1 = v1<<13 | v1>>(64-13)
   207  	v1 ^= v0
   208  	v0 = v0<<32 | v0>>(64-32)
   209  
   210  	v2 += v3
   211  	v3 = v3<<16 | v3>>(64-16)
   212  	v3 ^= v2
   213  
   214  	v0 += v3
   215  	v3 = v3<<21 | v3>>(64-21)
   216  	v3 ^= v0
   217  
   218  	v2 += v1
   219  	v1 = v1<<17 | v1>>(64-17)
   220  	v1 ^= v2
   221  	v2 = v2<<32 | v2>>(64-32)
   222  
   223  	// Round 2.
   224  	v0 += v1
   225  	v1 = v1<<13 | v1>>(64-13)
   226  	v1 ^= v0
   227  	v0 = v0<<32 | v0>>(64-32)
   228  
   229  	v2 += v3
   230  	v3 = v3<<16 | v3>>(64-16)
   231  	v3 ^= v2
   232  
   233  	v0 += v3
   234  	v3 = v3<<21 | v3>>(64-21)
   235  	v3 ^= v0
   236  
   237  	v2 += v1
   238  	v1 = v1<<17 | v1>>(64-17)
   239  	v1 ^= v2
   240  	v2 = v2<<32 | v2>>(64-32)
   241  
   242  	// Round 3.
   243  	v0 += v1
   244  	v1 = v1<<13 | v1>>(64-13)
   245  	v1 ^= v0
   246  	v0 = v0<<32 | v0>>(64-32)
   247  
   248  	v2 += v3
   249  	v3 = v3<<16 | v3>>(64-16)
   250  	v3 ^= v2
   251  
   252  	v0 += v3
   253  	v3 = v3<<21 | v3>>(64-21)
   254  	v3 ^= v0
   255  
   256  	v2 += v1
   257  	v1 = v1<<17 | v1>>(64-17)
   258  	v1 ^= v2
   259  	v2 = v2<<32 | v2>>(64-32)
   260  
   261  	// Round 4.
   262  	v0 += v1
   263  	v1 = v1<<13 | v1>>(64-13)
   264  	v1 ^= v0
   265  	v0 = v0<<32 | v0>>(64-32)
   266  
   267  	v2 += v3
   268  	v3 = v3<<16 | v3>>(64-16)
   269  	v3 ^= v2
   270  
   271  	v0 += v3
   272  	v3 = v3<<21 | v3>>(64-21)
   273  	v3 ^= v0
   274  
   275  	v2 += v1
   276  	v1 = v1<<17 | v1>>(64-17)
   277  	v1 ^= v2
   278  	v2 = v2<<32 | v2>>(64-32)
   279  
   280  	r1 = v0 ^ v1 ^ v2 ^ v3
   281  
   282  	return r0, r1
   283  }
   284  
   285  func (d *digest) Sum(in []byte) []byte {
   286  	if d.size == Size {
   287  		r := d.Sum64()
   288  		in = append(in,
   289  			byte(r),
   290  			byte(r>>8),
   291  			byte(r>>16),
   292  			byte(r>>24),
   293  			byte(r>>32),
   294  			byte(r>>40),
   295  			byte(r>>48),
   296  			byte(r>>56))
   297  	} else {
   298  		r0, r1 := d.sum128()
   299  		in = append(in,
   300  			byte(r0),
   301  			byte(r0>>8),
   302  			byte(r0>>16),
   303  			byte(r0>>24),
   304  			byte(r0>>32),
   305  			byte(r0>>40),
   306  			byte(r0>>48),
   307  			byte(r0>>56),
   308  			byte(r1),
   309  			byte(r1>>8),
   310  			byte(r1>>16),
   311  			byte(r1>>24),
   312  			byte(r1>>32),
   313  			byte(r1>>40),
   314  			byte(r1>>48),
   315  			byte(r1>>56))
   316  	}
   317  	return in
   318  }