vgetrandom-chacha.S 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/linkage.h>
  3. #include <asm/cache.h>
  4. #include <asm/assembler.h>
  5. .text
  6. #define state0 v0
  7. #define state1 v1
  8. #define state2 v2
  9. #define state3 v3
  10. #define copy0 v4
  11. #define copy0_q q4
  12. #define copy1 v5
  13. #define copy2 v6
  14. #define copy3 v7
  15. #define copy3_d d7
  16. #define one_d d16
  17. #define one_q q16
  18. #define one_v v16
  19. #define tmp v17
  20. #define rot8 v18
  21. /*
  22. * ARM64 ChaCha20 implementation meant for vDSO. Produces a given positive
  23. * number of blocks of output with nonce 0, taking an input key and 8-bytes
  24. * counter. Importantly does not spill to the stack.
  25. *
  26. * This implementation avoids d8-d15 because they are callee-save in user
  27. * space.
  28. *
  29. * void __arch_chacha20_blocks_nostack(uint8_t *dst_bytes,
  30. * const uint8_t *key,
  31. * uint32_t *counter,
  32. * size_t nblocks)
  33. *
  34. * x0: output bytes
  35. * x1: 32-byte key input
  36. * x2: 8-byte counter input/output
  37. * x3: number of 64-byte block to write to output
  38. */
  39. SYM_FUNC_START(__arch_chacha20_blocks_nostack)
  40. /* copy0 = "expand 32-byte k" */
  41. mov_q x8, 0x3320646e61707865
  42. mov_q x9, 0x6b20657479622d32
  43. mov copy0.d[0], x8
  44. mov copy0.d[1], x9
  45. /* copy1,copy2 = key */
  46. ld1 { copy1.4s, copy2.4s }, [x1]
  47. /* copy3 = counter || zero nonce */
  48. ld1 { copy3.2s }, [x2]
  49. movi one_v.2s, #1
  50. uzp1 one_v.4s, one_v.4s, one_v.4s
  51. .Lblock:
  52. /* copy state to auxiliary vectors for the final add after the permute. */
  53. mov state0.16b, copy0.16b
  54. mov state1.16b, copy1.16b
  55. mov state2.16b, copy2.16b
  56. mov state3.16b, copy3.16b
  57. mov w4, 20
  58. .Lpermute:
  59. /*
  60. * Permute one 64-byte block where the state matrix is stored in the four NEON
  61. * registers state0-state3. It performs matrix operations on four words in parallel,
  62. * but requires shuffling to rearrange the words after each round.
  63. */
  64. .Ldoubleround:
  65. /* state0 += state1, state3 = rotl32(state3 ^ state0, 16) */
  66. add state0.4s, state0.4s, state1.4s
  67. eor state3.16b, state3.16b, state0.16b
  68. rev32 state3.8h, state3.8h
  69. /* state2 += state3, state1 = rotl32(state1 ^ state2, 12) */
  70. add state2.4s, state2.4s, state3.4s
  71. eor tmp.16b, state1.16b, state2.16b
  72. shl state1.4s, tmp.4s, #12
  73. sri state1.4s, tmp.4s, #20
  74. /* state0 += state1, state3 = rotl32(state3 ^ state0, 8) */
  75. add state0.4s, state0.4s, state1.4s
  76. eor tmp.16b, state3.16b, state0.16b
  77. shl state3.4s, tmp.4s, #8
  78. sri state3.4s, tmp.4s, #24
  79. /* state2 += state3, state1 = rotl32(state1 ^ state2, 7) */
  80. add state2.4s, state2.4s, state3.4s
  81. eor tmp.16b, state1.16b, state2.16b
  82. shl state1.4s, tmp.4s, #7
  83. sri state1.4s, tmp.4s, #25
  84. /* state1[0,1,2,3] = state1[1,2,3,0] */
  85. ext state1.16b, state1.16b, state1.16b, #4
  86. /* state2[0,1,2,3] = state2[2,3,0,1] */
  87. ext state2.16b, state2.16b, state2.16b, #8
  88. /* state3[0,1,2,3] = state3[1,2,3,0] */
  89. ext state3.16b, state3.16b, state3.16b, #12
  90. /* state0 += state1, state3 = rotl32(state3 ^ state0, 16) */
  91. add state0.4s, state0.4s, state1.4s
  92. eor state3.16b, state3.16b, state0.16b
  93. rev32 state3.8h, state3.8h
  94. /* state2 += state3, state1 = rotl32(state1 ^ state2, 12) */
  95. add state2.4s, state2.4s, state3.4s
  96. eor tmp.16b, state1.16b, state2.16b
  97. shl state1.4s, tmp.4s, #12
  98. sri state1.4s, tmp.4s, #20
  99. /* state0 += state1, state3 = rotl32(state3 ^ state0, 8) */
  100. add state0.4s, state0.4s, state1.4s
  101. eor tmp.16b, state3.16b, state0.16b
  102. shl state3.4s, tmp.4s, #8
  103. sri state3.4s, tmp.4s, #24
  104. /* state2 += state3, state1 = rotl32(state1 ^ state2, 7) */
  105. add state2.4s, state2.4s, state3.4s
  106. eor tmp.16b, state1.16b, state2.16b
  107. shl state1.4s, tmp.4s, #7
  108. sri state1.4s, tmp.4s, #25
  109. /* state1[0,1,2,3] = state1[3,0,1,2] */
  110. ext state1.16b, state1.16b, state1.16b, #12
  111. /* state2[0,1,2,3] = state2[2,3,0,1] */
  112. ext state2.16b, state2.16b, state2.16b, #8
  113. /* state3[0,1,2,3] = state3[1,2,3,0] */
  114. ext state3.16b, state3.16b, state3.16b, #4
  115. subs w4, w4, #2
  116. b.ne .Ldoubleround
  117. /* output0 = state0 + state0 */
  118. add state0.4s, state0.4s, copy0.4s
  119. /* output1 = state1 + state1 */
  120. add state1.4s, state1.4s, copy1.4s
  121. /* output2 = state2 + state2 */
  122. add state2.4s, state2.4s, copy2.4s
  123. /* output2 = state3 + state3 */
  124. add state3.4s, state3.4s, copy3.4s
  125. st1 { state0.16b - state3.16b }, [x0]
  126. /*
  127. * ++copy3.counter, the 'add' clears the upper half of the SIMD register
  128. * which is the expected behaviour here.
  129. */
  130. add copy3_d, copy3_d, one_d
  131. /* output += 64, --nblocks */
  132. add x0, x0, 64
  133. subs x3, x3, #1
  134. b.ne .Lblock
  135. /* counter = copy3.counter */
  136. st1 { copy3.2s }, [x2]
  137. /* Zero out the potentially sensitive regs, in case nothing uses these again. */
  138. movi state0.16b, #0
  139. movi state1.16b, #0
  140. movi state2.16b, #0
  141. movi state3.16b, #0
  142. movi copy1.16b, #0
  143. movi copy2.16b, #0
  144. ret
  145. SYM_FUNC_END(__arch_chacha20_blocks_nostack)
  146. emit_aarch64_feature_1_and