Blame crypto/sha/asm/sha1-ppc.pl

Packit Service 084de1
#! /usr/bin/env perl
Packit Service 084de1
# Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
Packit Service 084de1
#
Packit Service 084de1
# Licensed under the OpenSSL license (the "License").  You may not use
Packit Service 084de1
# this file except in compliance with the License.  You can obtain a copy
Packit Service 084de1
# in the file LICENSE in the source distribution or at
Packit Service 084de1
# https://www.openssl.org/source/license.html
Packit Service 084de1
Packit Service 084de1
Packit Service 084de1
# ====================================================================
Packit Service 084de1
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
Packit Service 084de1
# project. The module is, however, dual licensed under OpenSSL and
Packit Service 084de1
# CRYPTOGAMS licenses depending on where you obtain it. For further
Packit Service 084de1
# details see http://www.openssl.org/~appro/cryptogams/.
Packit Service 084de1
# ====================================================================
Packit Service 084de1
Packit Service 084de1
# I let hardware handle unaligned input(*), except on page boundaries
Packit Service 084de1
# (see below for details). Otherwise straightforward implementation
Packit Service 084de1
# with X vector in register bank.
Packit Service 084de1
#
Packit Service 084de1
# (*) this means that this module is inappropriate for PPC403? Does
Packit Service 084de1
#     anybody know if pre-POWER3 can sustain unaligned load?
Packit Service 084de1
Packit Service 084de1
# 			-m64	-m32
Packit Service 084de1
# ----------------------------------
Packit Service 084de1
# PPC970,gcc-4.0.0	+76%	+59%
Packit Service 084de1
# Power6,xlc-7		+68%	+33%
Packit Service 084de1
Packit Service 084de1
$flavour = shift;
Packit Service 084de1
Packit Service 084de1
if ($flavour =~ /64/) {
Packit Service 084de1
	$SIZE_T	=8;
Packit Service 084de1
	$LRSAVE	=2*$SIZE_T;
Packit Service 084de1
	$UCMP	="cmpld";
Packit Service 084de1
	$STU	="stdu";
Packit Service 084de1
	$POP	="ld";
Packit Service 084de1
	$PUSH	="std";
Packit Service 084de1
} elsif ($flavour =~ /32/) {
Packit Service 084de1
	$SIZE_T	=4;
Packit Service 084de1
	$LRSAVE	=$SIZE_T;
Packit Service 084de1
	$UCMP	="cmplw";
Packit Service 084de1
	$STU	="stwu";
Packit Service 084de1
	$POP	="lwz";
Packit Service 084de1
	$PUSH	="stw";
Packit Service 084de1
} else { die "nonsense $flavour"; }
Packit Service 084de1
Packit Service 084de1
# Define endianness based on flavour
Packit Service 084de1
# i.e.: linux64le
Packit Service 084de1
$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
Packit Service 084de1
Packit Service 084de1
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
Packit Service 084de1
( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
Packit Service 084de1
( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
Packit Service 084de1
die "can't locate ppc-xlate.pl";
Packit Service 084de1
Packit Service 084de1
open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
Packit Service 084de1
Packit Service 084de1
$FRAME=24*$SIZE_T+64;
Packit Service 084de1
$LOCALS=6*$SIZE_T;
Packit Service 084de1
Packit Service 084de1
$K  ="r0";
Packit Service 084de1
$sp ="r1";
Packit Service 084de1
$toc="r2";
Packit Service 084de1
$ctx="r3";
Packit Service 084de1
$inp="r4";
Packit Service 084de1
$num="r5";
Packit Service 084de1
$t0 ="r15";
Packit Service 084de1
$t1 ="r6";
Packit Service 084de1
Packit Service 084de1
$A  ="r7";
Packit Service 084de1
$B  ="r8";
Packit Service 084de1
$C  ="r9";
Packit Service 084de1
$D  ="r10";
Packit Service 084de1
$E  ="r11";
Packit Service 084de1
$T  ="r12";
Packit Service 084de1
Packit Service 084de1
@V=($A,$B,$C,$D,$E,$T);
Packit Service 084de1
@X=("r16","r17","r18","r19","r20","r21","r22","r23",
Packit Service 084de1
    "r24","r25","r26","r27","r28","r29","r30","r31");
Packit Service 084de1
Packit Service 084de1
sub loadbe {
Packit Service 084de1
my ($dst, $src, $temp_reg) = @_;
Packit Service 084de1
$code.=<<___ if (!$LITTLE_ENDIAN);
Packit Service 084de1
	lwz	$dst,$src
Packit Service 084de1
___
Packit Service 084de1
$code.=<<___ if ($LITTLE_ENDIAN);
Packit Service 084de1
	lwz	$temp_reg,$src
Packit Service 084de1
	rotlwi	$dst,$temp_reg,8
Packit Service 084de1
	rlwimi	$dst,$temp_reg,24,0,7
Packit Service 084de1
	rlwimi	$dst,$temp_reg,24,16,23
Packit Service 084de1
___
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
sub BODY_00_19 {
Packit Service 084de1
my ($i,$a,$b,$c,$d,$e,$f)=@_;
Packit Service 084de1
my $j=$i+1;
Packit Service 084de1
Packit Service 084de1
	# Since the last value of $f is discarded, we can use
Packit Service 084de1
	# it as a temp reg to swap byte-order when needed.
Packit Service 084de1
	loadbe("@X[$i]","`$i*4`($inp)",$f) if ($i==0);
Packit Service 084de1
	loadbe("@X[$j]","`$j*4`($inp)",$f) if ($i<15);
Packit Service 084de1
$code.=<<___ if ($i<15);
Packit Service 084de1
	add	$f,$K,$e
Packit Service 084de1
	rotlwi	$e,$a,5
Packit Service 084de1
	add	$f,$f,@X[$i]
Packit Service 084de1
	and	$t0,$c,$b
Packit Service 084de1
	add	$f,$f,$e
Packit Service 084de1
	andc	$t1,$d,$b
Packit Service 084de1
	rotlwi	$b,$b,30
Packit Service 084de1
	or	$t0,$t0,$t1
Packit Service 084de1
	add	$f,$f,$t0
Packit Service 084de1
___
Packit Service 084de1
$code.=<<___ if ($i>=15);
Packit Service 084de1
	add	$f,$K,$e
Packit Service 084de1
	rotlwi	$e,$a,5
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+2)%16]
Packit Service 084de1
	add	$f,$f,@X[$i%16]
Packit Service 084de1
	and	$t0,$c,$b
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+8)%16]
Packit Service 084de1
	add	$f,$f,$e
Packit Service 084de1
	andc	$t1,$d,$b
Packit Service 084de1
	rotlwi	$b,$b,30
Packit Service 084de1
	or	$t0,$t0,$t1
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+13)%16]
Packit Service 084de1
	add	$f,$f,$t0
Packit Service 084de1
	rotlwi	@X[$j%16],@X[$j%16],1
Packit Service 084de1
___
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
sub BODY_20_39 {
Packit Service 084de1
my ($i,$a,$b,$c,$d,$e,$f)=@_;
Packit Service 084de1
my $j=$i+1;
Packit Service 084de1
$code.=<<___ if ($i<79);
Packit Service 084de1
	add	$f,$K,$e
Packit Service 084de1
	xor	$t0,$b,$d
Packit Service 084de1
	rotlwi	$e,$a,5
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+2)%16]
Packit Service 084de1
	add	$f,$f,@X[$i%16]
Packit Service 084de1
	xor	$t0,$t0,$c
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+8)%16]
Packit Service 084de1
	add	$f,$f,$t0
Packit Service 084de1
	rotlwi	$b,$b,30
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+13)%16]
Packit Service 084de1
	add	$f,$f,$e
Packit Service 084de1
	rotlwi	@X[$j%16],@X[$j%16],1
Packit Service 084de1
___
Packit Service 084de1
$code.=<<___ if ($i==79);
Packit Service 084de1
	add	$f,$K,$e
Packit Service 084de1
	xor	$t0,$b,$d
Packit Service 084de1
	rotlwi	$e,$a,5
Packit Service 084de1
	lwz	r16,0($ctx)
Packit Service 084de1
	add	$f,$f,@X[$i%16]
Packit Service 084de1
	xor	$t0,$t0,$c
Packit Service 084de1
	lwz	r17,4($ctx)
Packit Service 084de1
	add	$f,$f,$t0
Packit Service 084de1
	rotlwi	$b,$b,30
Packit Service 084de1
	lwz	r18,8($ctx)
Packit Service 084de1
	lwz	r19,12($ctx)
Packit Service 084de1
	add	$f,$f,$e
Packit Service 084de1
	lwz	r20,16($ctx)
Packit Service 084de1
___
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
sub BODY_40_59 {
Packit Service 084de1
my ($i,$a,$b,$c,$d,$e,$f)=@_;
Packit Service 084de1
my $j=$i+1;
Packit Service 084de1
$code.=<<___;
Packit Service 084de1
	add	$f,$K,$e
Packit Service 084de1
	rotlwi	$e,$a,5
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+2)%16]
Packit Service 084de1
	add	$f,$f,@X[$i%16]
Packit Service 084de1
	and	$t0,$b,$c
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+8)%16]
Packit Service 084de1
	add	$f,$f,$e
Packit Service 084de1
	or	$t1,$b,$c
Packit Service 084de1
	rotlwi	$b,$b,30
Packit Service 084de1
	xor	@X[$j%16],@X[$j%16],@X[($j+13)%16]
Packit Service 084de1
	and	$t1,$t1,$d
Packit Service 084de1
	or	$t0,$t0,$t1
Packit Service 084de1
	rotlwi	@X[$j%16],@X[$j%16],1
Packit Service 084de1
	add	$f,$f,$t0
Packit Service 084de1
___
Packit Service 084de1
}
Packit Service 084de1
Packit Service 084de1
$code=<<___;
Packit Service 084de1
.machine	"any"
Packit Service 084de1
.text
Packit Service 084de1
Packit Service 084de1
.globl	.sha1_block_data_order
Packit Service 084de1
.align	4
Packit Service 084de1
.sha1_block_data_order:
Packit Service 084de1
	$STU	$sp,-$FRAME($sp)
Packit Service 084de1
	mflr	r0
Packit Service 084de1
	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
Packit Service 084de1
	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
Packit Service 084de1
	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
Packit Service 084de1
	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
Packit Service 084de1
	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
Packit Service 084de1
	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
Packit Service 084de1
	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
Packit Service 084de1
	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
Packit Service 084de1
	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
Packit Service 084de1
	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
Packit Service 084de1
	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
Packit Service 084de1
	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
Packit Service 084de1
	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
Packit Service 084de1
	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
Packit Service 084de1
	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
Packit Service 084de1
	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
Packit Service 084de1
	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
Packit Service 084de1
	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
Packit Service 084de1
	lwz	$A,0($ctx)
Packit Service 084de1
	lwz	$B,4($ctx)
Packit Service 084de1
	lwz	$C,8($ctx)
Packit Service 084de1
	lwz	$D,12($ctx)
Packit Service 084de1
	lwz	$E,16($ctx)
Packit Service 084de1
	andi.	r0,$inp,3
Packit Service 084de1
	bne	Lunaligned
Packit Service 084de1
Laligned:
Packit Service 084de1
	mtctr	$num
Packit Service 084de1
	bl	Lsha1_block_private
Packit Service 084de1
	b	Ldone
Packit Service 084de1
Packit Service 084de1
; PowerPC specification allows an implementation to be ill-behaved
Packit Service 084de1
; upon unaligned access which crosses page boundary. "Better safe
Packit Service 084de1
; than sorry" principle makes me treat it specially. But I don't
Packit Service 084de1
; look for particular offending word, but rather for 64-byte input
Packit Service 084de1
; block which crosses the boundary. Once found that block is aligned
Packit Service 084de1
; and hashed separately...
Packit Service 084de1
.align	4
Packit Service 084de1
Lunaligned:
Packit Service 084de1
	subfic	$t1,$inp,4096
Packit Service 084de1
	andi.	$t1,$t1,4095	; distance to closest page boundary
Packit Service 084de1
	srwi.	$t1,$t1,6	; t1/=64
Packit Service 084de1
	beq	Lcross_page
Packit Service 084de1
	$UCMP	$num,$t1
Packit Service 084de1
	ble	Laligned	; didn't cross the page boundary
Packit Service 084de1
	mtctr	$t1
Packit Service 084de1
	subfc	$num,$t1,$num
Packit Service 084de1
	bl	Lsha1_block_private
Packit Service 084de1
Lcross_page:
Packit Service 084de1
	li	$t1,16
Packit Service 084de1
	mtctr	$t1
Packit Service 084de1
	addi	r20,$sp,$LOCALS	; spot within the frame
Packit Service 084de1
Lmemcpy:
Packit Service 084de1
	lbz	r16,0($inp)
Packit Service 084de1
	lbz	r17,1($inp)
Packit Service 084de1
	lbz	r18,2($inp)
Packit Service 084de1
	lbz	r19,3($inp)
Packit Service 084de1
	addi	$inp,$inp,4
Packit Service 084de1
	stb	r16,0(r20)
Packit Service 084de1
	stb	r17,1(r20)
Packit Service 084de1
	stb	r18,2(r20)
Packit Service 084de1
	stb	r19,3(r20)
Packit Service 084de1
	addi	r20,r20,4
Packit Service 084de1
	bdnz	Lmemcpy
Packit Service 084de1
Packit Service 084de1
	$PUSH	$inp,`$FRAME-$SIZE_T*18`($sp)
Packit Service 084de1
	li	$t1,1
Packit Service 084de1
	addi	$inp,$sp,$LOCALS
Packit Service 084de1
	mtctr	$t1
Packit Service 084de1
	bl	Lsha1_block_private
Packit Service 084de1
	$POP	$inp,`$FRAME-$SIZE_T*18`($sp)
Packit Service 084de1
	addic.	$num,$num,-1
Packit Service 084de1
	bne	Lunaligned
Packit Service 084de1
Packit Service 084de1
Ldone:
Packit Service 084de1
	$POP	r0,`$FRAME+$LRSAVE`($sp)
Packit Service 084de1
	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
Packit Service 084de1
	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
Packit Service 084de1
	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
Packit Service 084de1
	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
Packit Service 084de1
	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
Packit Service 084de1
	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
Packit Service 084de1
	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
Packit Service 084de1
	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
Packit Service 084de1
	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
Packit Service 084de1
	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
Packit Service 084de1
	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
Packit Service 084de1
	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
Packit Service 084de1
	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
Packit Service 084de1
	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
Packit Service 084de1
	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
Packit Service 084de1
	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
Packit Service 084de1
	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
Packit Service 084de1
	mtlr	r0
Packit Service 084de1
	addi	$sp,$sp,$FRAME
Packit Service 084de1
	blr
Packit Service 084de1
	.long	0
Packit Service 084de1
	.byte	0,12,4,1,0x80,18,3,0
Packit Service 084de1
	.long	0
Packit Service 084de1
___
Packit Service 084de1
Packit Service 084de1
# This is private block function, which uses tailored calling
Packit Service 084de1
# interface, namely upon entry SHA_CTX is pre-loaded to given
Packit Service 084de1
# registers and counter register contains amount of chunks to
Packit Service 084de1
# digest...
Packit Service 084de1
$code.=<<___;
Packit Service 084de1
.align	4
Packit Service 084de1
Lsha1_block_private:
Packit Service 084de1
___
Packit Service 084de1
$code.=<<___;	# load K_00_19
Packit Service 084de1
	lis	$K,0x5a82
Packit Service 084de1
	ori	$K,$K,0x7999
Packit Service 084de1
___
Packit Service 084de1
for($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
Packit Service 084de1
$code.=<<___;	# load K_20_39
Packit Service 084de1
	lis	$K,0x6ed9
Packit Service 084de1
	ori	$K,$K,0xeba1
Packit Service 084de1
___
Packit Service 084de1
for(;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
Packit Service 084de1
$code.=<<___;	# load K_40_59
Packit Service 084de1
	lis	$K,0x8f1b
Packit Service 084de1
	ori	$K,$K,0xbcdc
Packit Service 084de1
___
Packit Service 084de1
for(;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
Packit Service 084de1
$code.=<<___;	# load K_60_79
Packit Service 084de1
	lis	$K,0xca62
Packit Service 084de1
	ori	$K,$K,0xc1d6
Packit Service 084de1
___
Packit Service 084de1
for(;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
Packit Service 084de1
$code.=<<___;
Packit Service 084de1
	add	r16,r16,$E
Packit Service 084de1
	add	r17,r17,$T
Packit Service 084de1
	add	r18,r18,$A
Packit Service 084de1
	add	r19,r19,$B
Packit Service 084de1
	add	r20,r20,$C
Packit Service 084de1
	stw	r16,0($ctx)
Packit Service 084de1
	mr	$A,r16
Packit Service 084de1
	stw	r17,4($ctx)
Packit Service 084de1
	mr	$B,r17
Packit Service 084de1
	stw	r18,8($ctx)
Packit Service 084de1
	mr	$C,r18
Packit Service 084de1
	stw	r19,12($ctx)
Packit Service 084de1
	mr	$D,r19
Packit Service 084de1
	stw	r20,16($ctx)
Packit Service 084de1
	mr	$E,r20
Packit Service 084de1
	addi	$inp,$inp,`16*4`
Packit Service 084de1
	bdnz	Lsha1_block_private
Packit Service 084de1
	blr
Packit Service 084de1
	.long	0
Packit Service 084de1
	.byte	0,12,0x14,0,0,0,0,0
Packit Service 084de1
.size	.sha1_block_data_order,.-.sha1_block_data_order
Packit Service 084de1
___
Packit Service 084de1
$code.=<<___;
Packit Service 084de1
.asciz	"SHA1 block transform for PPC, CRYPTOGAMS by <appro\@fy.chalmers.se>"
Packit Service 084de1
___
Packit Service 084de1
Packit Service 084de1
$code =~ s/\`([^\`]*)\`/eval $1/gem;
Packit Service 084de1
print $code;
Packit Service 084de1
close STDOUT or die "error closing STDOUT: $!";