crypto/poly1305: don't break carry chains.
[openssl.git] / crypto / poly1305 / asm / poly1305-s390x.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # This module implements Poly1305 hash for s390x.
11 #
12 # June 2015
13 #
14 # ~6.6/2.3 cpb on z10/z196+, >2x improvement over compiler-generated
15 # code. For older compiler improvement coefficient is >3x, because
16 # then base 2^64 and base 2^32 implementations are compared.
17 #
18 # On side note, z13 enables vector base 2^26 implementation...
19
20 $flavour = shift;
21
22 if ($flavour =~ /3[12]/) {
23         $SIZE_T=4;
24         $g="";
25 } else {
26         $SIZE_T=8;
27         $g="g";
28 }
29
30 while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
31 open STDOUT,">$output";
32
33 $sp="%r15";
34
35 my ($ctx,$inp,$len,$padbit) = map("%r$_",(2..5));
36
37 $code.=<<___;
38 .text
39
40 .globl  poly1305_init
41 .type   poly1305_init,\@function
42 .align  16
43 poly1305_init:
44         lghi    %r0,0
45         lghi    %r1,-1
46         stg     %r0,0($ctx)             # zero hash value
47         stg     %r0,8($ctx)
48         stg     %r0,16($ctx)
49
50         cl${g}r $inp,%r0
51         je      .Lno_key
52
53         lrvg    %r4,0($inp)             # load little-endian key
54         lrvg    %r5,8($inp)
55
56         nihl    %r1,0xffc0              # 0xffffffc0ffffffff
57         srlg    %r0,%r1,4               # 0x0ffffffc0fffffff
58         srlg    %r1,%r1,4
59         nill    %r1,0xfffc              # 0x0ffffffc0ffffffc
60
61         ngr     %r4,%r0
62         ngr     %r5,%r1
63
64         stg     %r4,32($ctx)
65         stg     %r5,40($ctx)
66
67 .Lno_key:
68         lghi    %r2,0
69         br      %r14
70 .size   poly1305_init,.-poly1305_init
71 ___
72 {
73 my ($d0hi,$d0lo,$d1hi,$d1lo,$t0,$h0,$t1,$h1,$h2) = map("%r$_",(6..14));
74 my ($r0,$r1,$s1) = map("%r$_",(0..2));
75
76 $code.=<<___;
77 .globl  poly1305_blocks
78 .type   poly1305_blocks,\@function
79 .align  16
80 poly1305_blocks:
81         srl${g} $len,4                  # fixed-up in 64-bit build
82         lghi    %r0,0
83         cl${g}r $len,%r0
84         je      .Lno_data
85
86         stm${g} %r6,%r14,`6*$SIZE_T`($sp)
87
88         llgfr   $padbit,$padbit         # clear upper half, much needed with
89                                         # non-64-bit ABI
90         lg      $r0,32($ctx)            # load key
91         lg      $r1,40($ctx)
92
93         lg      $h0,0($ctx)             # load hash value
94         lg      $h1,8($ctx)
95         lg      $h2,16($ctx)
96
97         st$g    $ctx,`2*$SIZE_T`($sp)   # off-load $ctx
98         srlg    $s1,$r1,2
99         algr    $s1,$r1                 # s1 = r1 + r1>>2
100         j       .Loop
101
102 .align  16
103 .Loop:
104         lrvg    $d0lo,0($inp)           # load little-endian input
105         lrvg    $d1lo,8($inp)
106         la      $inp,16($inp)
107
108         algr    $d0lo,$h0               # accumulate input
109         alcgr   $d1lo,$h1
110
111         lgr     $h0,$d0lo
112         mlgr    $d0hi,$r0               # h0*r0   -> $d0hi:$d0lo
113         lgr     $h1,$d1lo
114         mlgr    $d1hi,$s1               # h1*5*r1 -> $d1hi:$d1lo
115
116         mlgr    $t0,$r1                 # h0*r1   -> $t0:$h0
117         mlgr    $t1,$r0                 # h1*r0   -> $t1:$h1
118         alcgr   $h2,$padbit
119
120         algr    $d0lo,$d1lo
121         lgr     $d1lo,$h2
122         alcgr   $d0hi,$d1hi
123         lghi    $d1hi,0
124
125         algr    $h1,$h0
126         alcgr   $t1,$t0
127
128         msgr    $d1lo,$s1               # h2*s1
129         msgr    $h2,$r0                 # h2*r0
130
131         algr    $h1,$d1lo
132         alcgr   $t1,$d1hi               # $d1hi is zero
133
134         algr    $h1,$d0hi
135         alcgr   $h2,$t1
136
137         lghi    $h0,-4                  # final reduction step
138         ngr     $h0,$h2
139         srlg    $t0,$h2,2
140         algr    $h0,$t0
141         lghi    $t1,3
142         ngr     $h2,$t1
143
144         algr    $h0,$d0lo
145         alcgr   $h1,$d1hi               # $d1hi is still zero
146         alcgr   $h2,$d1hi               # $d1hi is still zero
147
148         brct$g  $len,.Loop
149
150         l$g     $ctx,`2*$SIZE_T`($sp)   # restore $ctx
151
152         stg     $h0,0($ctx)             # store hash value
153         stg     $h1,8($ctx)
154         stg     $h2,16($ctx)
155
156         lm${g}  %r6,%r14,`6*$SIZE_T`($sp)
157 .Lno_data:
158         br      %r14
159 .size   poly1305_blocks,.-poly1305_blocks
160 ___
161 }
162 {
163 my ($mac,$nonce)=($inp,$len);
164 my ($h0,$h1,$h2,$d0,$d1)=map("%r$_",(5..9));
165
166 $code.=<<___;
167 .globl  poly1305_emit
168 .type   poly1305_emit,\@function
169 .align  16
170 poly1305_emit:
171         stm${g} %r6,%r9,`6*$SIZE_T`($sp)
172
173         lg      $h0,0($ctx)
174         lg      $h1,8($ctx)
175         lg      $h2,16($ctx)
176
177         lghi    %r0,5
178         lghi    %r1,0
179         lgr     $d0,$h0
180         lgr     $d1,$h1
181
182         algr    $h0,%r0                 # compare to modulus
183         alcgr   $h1,%r1
184         alcgr   $h2,%r1
185
186         srlg    $h2,$h2,2               # did it borrow/carry?
187         slgr    %r1,$h2                 # 0-$h2>>2
188         lg      $h2,0($nonce)           # load nonce
189         lghi    %r0,-1
190         lg      $ctx,8($nonce)
191         xgr     %r0,%r1                 # ~%r1
192
193         ngr     $h0,%r1
194         ngr     $d0,%r0
195         ngr     $h1,%r1
196         ngr     $d1,%r0
197         ogr     $h0,$d0
198         rllg    $d0,$h2,32              # flip nonce words
199         ogr     $h1,$d1
200         rllg    $d1,$ctx,32
201
202         algr    $h0,$d0                 # accumulate nonce
203         alcgr   $h1,$d1
204
205         strvg   $h0,0($mac)             # write little-endian result
206         strvg   $h1,8($mac)
207
208         lm${g}  %r6,%r9,`6*$SIZE_T`($sp)
209         br      %r14
210 .size   poly1305_emit,.-poly1305_emit
211
212 .string "Poly1305 for s390x, CRYPTOGAMS by <appro\@openssl.org>"
213 ___
214 }
215
216 $code =~ s/\`([^\`]*)\`/eval $1/gem;
217 $code =~ s/\b(srlg\s+)(%r[0-9]+\s*,)\s*([0-9]+)/$1$2$2$3/gm;
218
219 print $code;
220 close STDOUT;