git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/crypto/chacha/hchacha20_generic.go (about)

     1  package chacha
     2  
     3  import (
     4  	"encoding/binary"
     5  	"math/bits"
     6  )
     7  
     8  // calls to binary.LittleEndian.Uint32 and quarterRound are inlined
     9  func hChaCha20Generic(out *[32]byte, nonce *[16]byte, key *[32]byte) {
    10  	x0, x1, x2, x3 := chachaConstants[0], chachaConstants[1], chachaConstants[2], chachaConstants[3]
    11  	x4 := binary.LittleEndian.Uint32(key[0:4])
    12  	x5 := binary.LittleEndian.Uint32(key[4:8])
    13  	x6 := binary.LittleEndian.Uint32(key[8:12])
    14  	x7 := binary.LittleEndian.Uint32(key[12:16])
    15  	x8 := binary.LittleEndian.Uint32(key[16:20])
    16  	x9 := binary.LittleEndian.Uint32(key[20:24])
    17  	x10 := binary.LittleEndian.Uint32(key[24:28])
    18  	x11 := binary.LittleEndian.Uint32(key[28:32])
    19  	x12 := binary.LittleEndian.Uint32(nonce[0:4])
    20  	x13 := binary.LittleEndian.Uint32(nonce[4:8])
    21  	x14 := binary.LittleEndian.Uint32(nonce[8:12])
    22  	x15 := binary.LittleEndian.Uint32(nonce[12:16])
    23  
    24  	for i := 0; i < 10; i++ {
    25  		// Diagonal round.
    26  		x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
    27  		x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
    28  		x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
    29  		x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
    30  
    31  		// Column round.
    32  		x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
    33  		x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
    34  		x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
    35  		x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
    36  	}
    37  
    38  	// _ = out[31] // bounds check elimination hint
    39  	binary.LittleEndian.PutUint32(out[0:4], x0)
    40  	binary.LittleEndian.PutUint32(out[4:8], x1)
    41  	binary.LittleEndian.PutUint32(out[8:12], x2)
    42  	binary.LittleEndian.PutUint32(out[12:16], x3)
    43  	binary.LittleEndian.PutUint32(out[16:20], x12)
    44  	binary.LittleEndian.PutUint32(out[20:24], x13)
    45  	binary.LittleEndian.PutUint32(out[24:28], x14)
    46  	binary.LittleEndian.PutUint32(out[28:32], x15)
    47  }
    48  
    49  func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
    50  	a += b
    51  	d ^= a
    52  	d = bits.RotateLeft32(d, 16)
    53  	c += d
    54  	b ^= c
    55  	b = bits.RotateLeft32(b, 12)
    56  	a += b
    57  	d ^= a
    58  	d = bits.RotateLeft32(d, 8)
    59  	c += d
    60  	b ^= c
    61  	b = bits.RotateLeft32(b, 7)
    62  	return a, b, c, d
    63  }