mips-mont.pl 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. # This module doesn't present direct interest for OpenSSL, because it
  10. # doesn't provide better performance for longer keys, at least not on
  11. # in-order-execution cores. While 512-bit RSA sign operations can be
  12. # 65% faster in 64-bit mode, 1024-bit ones are only 15% faster, and
  13. # 4096-bit ones are up to 15% slower. In 32-bit mode it varies from
  14. # 16% improvement for 512-bit RSA sign to -33% for 4096-bit RSA
  15. # verify:-( All comparisons are against bn_mul_mont-free assembler.
  16. # The module might be of interest to embedded system developers, as
  17. # the code is smaller than 1KB, yet offers >3x improvement on MIPS64
  18. # and 75-30% [less for longer keys] on MIPS32 over compiler-generated
  19. # code.
  20. ######################################################################
  21. # There is a number of MIPS ABI in use, O32 and N32/64 are most
  22. # widely used. Then there is a new contender: NUBI. It appears that if
  23. # one picks the latter, it's possible to arrange code in ABI neutral
  24. # manner. Therefore let's stick to NUBI register layout:
  25. #
  26. ($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
  27. ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
  28. ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
  29. ($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
  30. #
  31. # The return value is placed in $a0. Following coding rules facilitate
  32. # interoperability:
  33. #
  34. # - never ever touch $tp, "thread pointer", former $gp;
  35. # - copy return value to $t0, former $v0 [or to $a0 if you're adapting
  36. # old code];
  37. # - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
  38. #
  39. # For reference here is register layout for N32/64 MIPS ABIs:
  40. #
  41. # ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
  42. # ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
  43. # ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
  44. # ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
  45. # ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
  46. #
  47. $flavour = shift; # supported flavours are o32,n32,64,nubi32,nubi64
  48. if ($flavour =~ /64|n32/i) {
  49. $PTR_ADD="dadd"; # incidentally works even on n32
  50. $PTR_SUB="dsub"; # incidentally works even on n32
  51. $REG_S="sd";
  52. $REG_L="ld";
  53. $SZREG=8;
  54. } else {
  55. $PTR_ADD="add";
  56. $PTR_SUB="sub";
  57. $REG_S="sw";
  58. $REG_L="lw";
  59. $SZREG=4;
  60. }
  61. $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? 0x00fff000 : 0x00ff0000;
  62. #
  63. # <appro@openssl.org>
  64. #
  65. ######################################################################
  66. while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
  67. open STDOUT,">$output";
  68. if ($flavour =~ /64|n32/i) {
  69. $LD="ld";
  70. $ST="sd";
  71. $MULTU="dmultu";
  72. $ADDU="daddu";
  73. $SUBU="dsubu";
  74. $BNSZ=8;
  75. } else {
  76. $LD="lw";
  77. $ST="sw";
  78. $MULTU="multu";
  79. $ADDU="addu";
  80. $SUBU="subu";
  81. $BNSZ=4;
  82. }
  83. # int bn_mul_mont(
  84. $rp=$a0; # BN_ULONG *rp,
  85. $ap=$a1; # const BN_ULONG *ap,
  86. $bp=$a2; # const BN_ULONG *bp,
  87. $np=$a3; # const BN_ULONG *np,
  88. $n0=$a4; # const BN_ULONG *n0,
  89. $num=$a5; # int num);
  90. $lo0=$a6;
  91. $hi0=$a7;
  92. $lo1=$t1;
  93. $hi1=$t2;
  94. $aj=$s0;
  95. $bi=$s1;
  96. $nj=$s2;
  97. $tp=$s3;
  98. $alo=$s4;
  99. $ahi=$s5;
  100. $nlo=$s6;
  101. $nhi=$s7;
  102. $tj=$s8;
  103. $i=$s9;
  104. $j=$s10;
  105. $m1=$s11;
  106. $FRAMESIZE=14;
  107. $code=<<___;
  108. .text
  109. .set noat
  110. .set noreorder
  111. .align 5
  112. .globl bn_mul_mont
  113. .ent bn_mul_mont
  114. bn_mul_mont:
  115. ___
  116. $code.=<<___ if ($flavour =~ /o32/i);
  117. lw $n0,16($sp)
  118. lw $num,20($sp)
  119. ___
  120. $code.=<<___;
  121. slt $at,$num,4
  122. bnez $at,1f
  123. li $t0,0
  124. slt $at,$num,17 # on in-order CPU
  125. bnezl $at,bn_mul_mont_internal
  126. nop
  127. 1: jr $ra
  128. li $a0,0
  129. .end bn_mul_mont
  130. .align 5
  131. .ent bn_mul_mont_internal
  132. bn_mul_mont_internal:
  133. .frame $fp,$FRAMESIZE*$SZREG,$ra
  134. .mask 0x40000000|$SAVED_REGS_MASK,-$SZREG
  135. $PTR_SUB $sp,$FRAMESIZE*$SZREG
  136. $REG_S $fp,($FRAMESIZE-1)*$SZREG($sp)
  137. $REG_S $s11,($FRAMESIZE-2)*$SZREG($sp)
  138. $REG_S $s10,($FRAMESIZE-3)*$SZREG($sp)
  139. $REG_S $s9,($FRAMESIZE-4)*$SZREG($sp)
  140. $REG_S $s8,($FRAMESIZE-5)*$SZREG($sp)
  141. $REG_S $s7,($FRAMESIZE-6)*$SZREG($sp)
  142. $REG_S $s6,($FRAMESIZE-7)*$SZREG($sp)
  143. $REG_S $s5,($FRAMESIZE-8)*$SZREG($sp)
  144. $REG_S $s4,($FRAMESIZE-9)*$SZREG($sp)
  145. ___
  146. $code.=<<___ if ($flavour =~ /nubi/i);
  147. $REG_S $s3,($FRAMESIZE-10)*$SZREG($sp)
  148. $REG_S $s2,($FRAMESIZE-11)*$SZREG($sp)
  149. $REG_S $s1,($FRAMESIZE-12)*$SZREG($sp)
  150. $REG_S $s0,($FRAMESIZE-13)*$SZREG($sp)
  151. ___
  152. $code.=<<___;
  153. move $fp,$sp
  154. .set reorder
  155. $LD $n0,0($n0)
  156. $LD $bi,0($bp) # bp[0]
  157. $LD $aj,0($ap) # ap[0]
  158. $LD $nj,0($np) # np[0]
  159. $PTR_SUB $sp,2*$BNSZ # place for two extra words
  160. sll $num,`log($BNSZ)/log(2)`
  161. li $at,-4096
  162. $PTR_SUB $sp,$num
  163. and $sp,$at
  164. $MULTU $aj,$bi
  165. $LD $alo,$BNSZ($ap)
  166. $LD $nlo,$BNSZ($np)
  167. mflo $lo0
  168. mfhi $hi0
  169. $MULTU $lo0,$n0
  170. mflo $m1
  171. $MULTU $alo,$bi
  172. mflo $alo
  173. mfhi $ahi
  174. $MULTU $nj,$m1
  175. mflo $lo1
  176. mfhi $hi1
  177. $MULTU $nlo,$m1
  178. $ADDU $lo1,$lo0
  179. sltu $at,$lo1,$lo0
  180. $ADDU $hi1,$at
  181. mflo $nlo
  182. mfhi $nhi
  183. move $tp,$sp
  184. li $j,2*$BNSZ
  185. .align 4
  186. .L1st:
  187. .set noreorder
  188. $PTR_ADD $aj,$ap,$j
  189. $PTR_ADD $nj,$np,$j
  190. $LD $aj,($aj)
  191. $LD $nj,($nj)
  192. $MULTU $aj,$bi
  193. $ADDU $lo0,$alo,$hi0
  194. $ADDU $lo1,$nlo,$hi1
  195. sltu $at,$lo0,$hi0
  196. sltu $t0,$lo1,$hi1
  197. $ADDU $hi0,$ahi,$at
  198. $ADDU $hi1,$nhi,$t0
  199. mflo $alo
  200. mfhi $ahi
  201. $ADDU $lo1,$lo0
  202. sltu $at,$lo1,$lo0
  203. $MULTU $nj,$m1
  204. $ADDU $hi1,$at
  205. addu $j,$BNSZ
  206. $ST $lo1,($tp)
  207. sltu $t0,$j,$num
  208. mflo $nlo
  209. mfhi $nhi
  210. bnez $t0,.L1st
  211. $PTR_ADD $tp,$BNSZ
  212. .set reorder
  213. $ADDU $lo0,$alo,$hi0
  214. sltu $at,$lo0,$hi0
  215. $ADDU $hi0,$ahi,$at
  216. $ADDU $lo1,$nlo,$hi1
  217. sltu $t0,$lo1,$hi1
  218. $ADDU $hi1,$nhi,$t0
  219. $ADDU $lo1,$lo0
  220. sltu $at,$lo1,$lo0
  221. $ADDU $hi1,$at
  222. $ST $lo1,($tp)
  223. $ADDU $hi1,$hi0
  224. sltu $at,$hi1,$hi0
  225. $ST $hi1,$BNSZ($tp)
  226. $ST $at,2*$BNSZ($tp)
  227. li $i,$BNSZ
  228. .align 4
  229. .Louter:
  230. $PTR_ADD $bi,$bp,$i
  231. $LD $bi,($bi)
  232. $LD $aj,($ap)
  233. $LD $alo,$BNSZ($ap)
  234. $LD $tj,($sp)
  235. $MULTU $aj,$bi
  236. $LD $nj,($np)
  237. $LD $nlo,$BNSZ($np)
  238. mflo $lo0
  239. mfhi $hi0
  240. $ADDU $lo0,$tj
  241. $MULTU $lo0,$n0
  242. sltu $at,$lo0,$tj
  243. $ADDU $hi0,$at
  244. mflo $m1
  245. $MULTU $alo,$bi
  246. mflo $alo
  247. mfhi $ahi
  248. $MULTU $nj,$m1
  249. mflo $lo1
  250. mfhi $hi1
  251. $MULTU $nlo,$m1
  252. $ADDU $lo1,$lo0
  253. sltu $at,$lo1,$lo0
  254. $ADDU $hi1,$at
  255. mflo $nlo
  256. mfhi $nhi
  257. move $tp,$sp
  258. li $j,2*$BNSZ
  259. $LD $tj,$BNSZ($tp)
  260. .align 4
  261. .Linner:
  262. .set noreorder
  263. $PTR_ADD $aj,$ap,$j
  264. $PTR_ADD $nj,$np,$j
  265. $LD $aj,($aj)
  266. $LD $nj,($nj)
  267. $MULTU $aj,$bi
  268. $ADDU $lo0,$alo,$hi0
  269. $ADDU $lo1,$nlo,$hi1
  270. sltu $at,$lo0,$hi0
  271. sltu $t0,$lo1,$hi1
  272. $ADDU $hi0,$ahi,$at
  273. $ADDU $hi1,$nhi,$t0
  274. mflo $alo
  275. mfhi $ahi
  276. $ADDU $lo0,$tj
  277. addu $j,$BNSZ
  278. $MULTU $nj,$m1
  279. sltu $at,$lo0,$tj
  280. $ADDU $lo1,$lo0
  281. $ADDU $hi0,$at
  282. sltu $t0,$lo1,$lo0
  283. $LD $tj,2*$BNSZ($tp)
  284. $ADDU $hi1,$t0
  285. sltu $at,$j,$num
  286. mflo $nlo
  287. mfhi $nhi
  288. $ST $lo1,($tp)
  289. bnez $at,.Linner
  290. $PTR_ADD $tp,$BNSZ
  291. .set reorder
  292. $ADDU $lo0,$alo,$hi0
  293. sltu $at,$lo0,$hi0
  294. $ADDU $hi0,$ahi,$at
  295. $ADDU $lo0,$tj
  296. sltu $t0,$lo0,$tj
  297. $ADDU $hi0,$t0
  298. $LD $tj,2*$BNSZ($tp)
  299. $ADDU $lo1,$nlo,$hi1
  300. sltu $at,$lo1,$hi1
  301. $ADDU $hi1,$nhi,$at
  302. $ADDU $lo1,$lo0
  303. sltu $t0,$lo1,$lo0
  304. $ADDU $hi1,$t0
  305. $ST $lo1,($tp)
  306. $ADDU $lo1,$hi1,$hi0
  307. sltu $hi1,$lo1,$hi0
  308. $ADDU $lo1,$tj
  309. sltu $at,$lo1,$tj
  310. $ADDU $hi1,$at
  311. $ST $lo1,$BNSZ($tp)
  312. $ST $hi1,2*$BNSZ($tp)
  313. addu $i,$BNSZ
  314. sltu $t0,$i,$num
  315. bnez $t0,.Louter
  316. .set noreorder
  317. $PTR_ADD $tj,$sp,$num # &tp[num]
  318. move $tp,$sp
  319. move $ap,$sp
  320. li $hi0,0 # clear borrow bit
  321. .align 4
  322. .Lsub: $LD $lo0,($tp)
  323. $LD $lo1,($np)
  324. $PTR_ADD $tp,$BNSZ
  325. $PTR_ADD $np,$BNSZ
  326. $SUBU $lo1,$lo0,$lo1 # tp[i]-np[i]
  327. sgtu $at,$lo1,$lo0
  328. $SUBU $lo0,$lo1,$hi0
  329. sgtu $hi0,$lo0,$lo1
  330. $ST $lo0,($rp)
  331. or $hi0,$at
  332. sltu $at,$tp,$tj
  333. bnez $at,.Lsub
  334. $PTR_ADD $rp,$BNSZ
  335. $SUBU $hi0,$hi1,$hi0 # handle upmost overflow bit
  336. move $tp,$sp
  337. $PTR_SUB $rp,$num # restore rp
  338. not $hi1,$hi0
  339. and $ap,$hi0,$sp
  340. and $bp,$hi1,$rp
  341. or $ap,$ap,$bp # ap=borrow?tp:rp
  342. .align 4
  343. .Lcopy: $LD $aj,($ap)
  344. $PTR_ADD $ap,$BNSZ
  345. $ST $zero,($tp)
  346. $PTR_ADD $tp,$BNSZ
  347. sltu $at,$tp,$tj
  348. $ST $aj,($rp)
  349. bnez $at,.Lcopy
  350. $PTR_ADD $rp,$BNSZ
  351. li $a0,1
  352. li $t0,1
  353. .set noreorder
  354. move $sp,$fp
  355. $REG_L $fp,($FRAMESIZE-1)*$SZREG($sp)
  356. $REG_L $s11,($FRAMESIZE-2)*$SZREG($sp)
  357. $REG_L $s10,($FRAMESIZE-3)*$SZREG($sp)
  358. $REG_L $s9,($FRAMESIZE-4)*$SZREG($sp)
  359. $REG_L $s8,($FRAMESIZE-5)*$SZREG($sp)
  360. $REG_L $s7,($FRAMESIZE-6)*$SZREG($sp)
  361. $REG_L $s6,($FRAMESIZE-7)*$SZREG($sp)
  362. $REG_L $s5,($FRAMESIZE-8)*$SZREG($sp)
  363. $REG_L $s4,($FRAMESIZE-9)*$SZREG($sp)
  364. ___
  365. $code.=<<___ if ($flavour =~ /nubi/i);
  366. $REG_L $s3,($FRAMESIZE-10)*$SZREG($sp)
  367. $REG_L $s2,($FRAMESIZE-11)*$SZREG($sp)
  368. $REG_L $s1,($FRAMESIZE-12)*$SZREG($sp)
  369. $REG_L $s0,($FRAMESIZE-13)*$SZREG($sp)
  370. ___
  371. $code.=<<___;
  372. jr $ra
  373. $PTR_ADD $sp,$FRAMESIZE*$SZREG
  374. .end bn_mul_mont_internal
  375. .rdata
  376. .asciiz "Montgomery Multiplication for MIPS, CRYPTOGAMS by <appro\@openssl.org>"
  377. ___
  378. $code =~ s/\`([^\`]*)\`/eval $1/gem;
  379. print $code;
  380. close STDOUT;