| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| // |
| // ARM version of md5block.go |
| |
| //go:build !purego |
| |
| #include "textflag.h" |
| |
| // SHA-1 block routine. See sha1block.go for Go equivalent. |
| // |
| // There are 80 rounds of 4 types: |
| // - rounds 0-15 are type 1 and load data (ROUND1 macro). |
| // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). |
| // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). |
| // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). |
| // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). |
| // |
| // Each round loads or shuffles the data, then computes a per-round |
| // function of b, c, d, and then mixes the result into and rotates the |
| // five registers a, b, c, d, e holding the intermediate results. |
| // |
| // The register rotation is implemented by rotating the arguments to |
| // the round macros instead of by explicit move instructions. |
| |
| // Register definitions |
| #define Rdata R0 // Pointer to incoming data |
| #define Rconst R1 // Current constant for SHA round |
| #define Ra R2 // SHA-1 accumulator |
| #define Rb R3 // SHA-1 accumulator |
| #define Rc R4 // SHA-1 accumulator |
| #define Rd R5 // SHA-1 accumulator |
| #define Re R6 // SHA-1 accumulator |
| #define Rt0 R7 // Temporary |
| #define Rt1 R8 // Temporary |
| // r9, r10 are forbidden |
| // r11 is OK provided you check the assembler that no synthetic instructions use it |
| #define Rt2 R11 // Temporary |
| #define Rctr R12 // loop counter |
| #define Rw R14 // point to w buffer |
| |
| // func block(dig *digest, p []byte) |
| // 0(FP) is *digest |
| // 4(FP) is p.array (struct Slice) |
| // 8(FP) is p.len |
| //12(FP) is p.cap |
| // |
| // Stack frame |
| #define p_end end-4(SP) // pointer to the end of data |
| #define p_data data-8(SP) // current data pointer (unused?) |
| #define w_buf buf-(8+4*80)(SP) //80 words temporary buffer w uint32[80] |
| #define saved abcde-(8+4*80+4*5)(SP) // saved sha1 registers a,b,c,d,e - these must be last (unused?) |
| // Total size +4 for saved LR is 352 |
| |
| // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3] |
| // e += w[i] |
| #define LOAD(Re) \ |
| MOVBU 2(Rdata), Rt0 ; \ |
| MOVBU 3(Rdata), Rt1 ; \ |
| MOVBU 1(Rdata), Rt2 ; \ |
| ORR Rt0<<8, Rt1, Rt0 ; \ |
| MOVBU.P 4(Rdata), Rt1 ; \ |
| ORR Rt2<<16, Rt0, Rt0 ; \ |
| ORR Rt1<<24, Rt0, Rt0 ; \ |
| MOVW.P Rt0, 4(Rw) ; \ |
| ADD Rt0, Re, Re |
| |
| // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] |
| // w[i&0xf] = tmp<<1 | tmp>>(32-1) |
| // e += w[i&0xf] |
| #define SHUFFLE(Re) \ |
| MOVW (-16*4)(Rw), Rt0 ; \ |
| MOVW (-14*4)(Rw), Rt1 ; \ |
| MOVW (-8*4)(Rw), Rt2 ; \ |
| EOR Rt0, Rt1, Rt0 ; \ |
| MOVW (-3*4)(Rw), Rt1 ; \ |
| EOR Rt2, Rt0, Rt0 ; \ |
| EOR Rt0, Rt1, Rt0 ; \ |
| MOVW Rt0@>(32-1), Rt0 ; \ |
| MOVW.P Rt0, 4(Rw) ; \ |
| ADD Rt0, Re, Re |
| |
| // t1 = (b & c) | ((~b) & d) |
| #define FUNC1(Ra, Rb, Rc, Rd, Re) \ |
| MVN Rb, Rt1 ; \ |
| AND Rb, Rc, Rt0 ; \ |
| AND Rd, Rt1, Rt1 ; \ |
| ORR Rt0, Rt1, Rt1 |
| |
| // t1 = b ^ c ^ d |
| #define FUNC2(Ra, Rb, Rc, Rd, Re) \ |
| EOR Rb, Rc, Rt1 ; \ |
| EOR Rd, Rt1, Rt1 |
| |
| // t1 = (b & c) | (b & d) | (c & d) = |
| // t1 = (b & c) | ((b | c) & d) |
| #define FUNC3(Ra, Rb, Rc, Rd, Re) \ |
| ORR Rb, Rc, Rt0 ; \ |
| AND Rb, Rc, Rt1 ; \ |
| AND Rd, Rt0, Rt0 ; \ |
| ORR Rt0, Rt1, Rt1 |
| |
| #define FUNC4 FUNC2 |
| |
| // a5 := a<<5 | a>>(32-5) |
| // b = b<<30 | b>>(32-30) |
| // e = a5 + t1 + e + const |
| #define MIX(Ra, Rb, Rc, Rd, Re) \ |
| ADD Rt1, Re, Re ; \ |
| MOVW Rb@>(32-30), Rb ; \ |
| ADD Ra@>(32-5), Re, Re ; \ |
| ADD Rconst, Re, Re |
| |
| #define ROUND1(Ra, Rb, Rc, Rd, Re) \ |
| LOAD(Re) ; \ |
| FUNC1(Ra, Rb, Rc, Rd, Re) ; \ |
| MIX(Ra, Rb, Rc, Rd, Re) |
| |
| #define ROUND1x(Ra, Rb, Rc, Rd, Re) \ |
| SHUFFLE(Re) ; \ |
| FUNC1(Ra, Rb, Rc, Rd, Re) ; \ |
| MIX(Ra, Rb, Rc, Rd, Re) |
| |
| #define ROUND2(Ra, Rb, Rc, Rd, Re) \ |
| SHUFFLE(Re) ; \ |
| FUNC2(Ra, Rb, Rc, Rd, Re) ; \ |
| MIX(Ra, Rb, Rc, Rd, Re) |
| |
| #define ROUND3(Ra, Rb, Rc, Rd, Re) \ |
| SHUFFLE(Re) ; \ |
| FUNC3(Ra, Rb, Rc, Rd, Re) ; \ |
| MIX(Ra, Rb, Rc, Rd, Re) |
| |
| #define ROUND4(Ra, Rb, Rc, Rd, Re) \ |
| SHUFFLE(Re) ; \ |
| FUNC4(Ra, Rb, Rc, Rd, Re) ; \ |
| MIX(Ra, Rb, Rc, Rd, Re) |
| |
| |
| // func block(dig *digest, p []byte) |
| TEXT ·block(SB), 0, $352-16 |
| MOVW p+4(FP), Rdata // pointer to the data |
| MOVW p_len+8(FP), Rt0 // number of bytes |
| ADD Rdata, Rt0 |
| MOVW Rt0, p_end // pointer to end of data |
| |
| // Load up initial SHA-1 accumulator |
| MOVW dig+0(FP), Rt0 |
| MOVM.IA (Rt0), [Ra,Rb,Rc,Rd,Re] |
| |
| loop: |
| // Save registers at SP+4 onwards |
| MOVM.IB [Ra,Rb,Rc,Rd,Re], (R13) |
| |
| MOVW $w_buf, Rw |
| MOVW $0x5A827999, Rconst |
| MOVW $3, Rctr |
| loop1: ROUND1(Ra, Rb, Rc, Rd, Re) |
| ROUND1(Re, Ra, Rb, Rc, Rd) |
| ROUND1(Rd, Re, Ra, Rb, Rc) |
| ROUND1(Rc, Rd, Re, Ra, Rb) |
| ROUND1(Rb, Rc, Rd, Re, Ra) |
| SUB.S $1, Rctr |
| BNE loop1 |
| |
| ROUND1(Ra, Rb, Rc, Rd, Re) |
| ROUND1x(Re, Ra, Rb, Rc, Rd) |
| ROUND1x(Rd, Re, Ra, Rb, Rc) |
| ROUND1x(Rc, Rd, Re, Ra, Rb) |
| ROUND1x(Rb, Rc, Rd, Re, Ra) |
| |
| MOVW $0x6ED9EBA1, Rconst |
| MOVW $4, Rctr |
| loop2: ROUND2(Ra, Rb, Rc, Rd, Re) |
| ROUND2(Re, Ra, Rb, Rc, Rd) |
| ROUND2(Rd, Re, Ra, Rb, Rc) |
| ROUND2(Rc, Rd, Re, Ra, Rb) |
| ROUND2(Rb, Rc, Rd, Re, Ra) |
| SUB.S $1, Rctr |
| BNE loop2 |
| |
| MOVW $0x8F1BBCDC, Rconst |
| MOVW $4, Rctr |
| loop3: ROUND3(Ra, Rb, Rc, Rd, Re) |
| ROUND3(Re, Ra, Rb, Rc, Rd) |
| ROUND3(Rd, Re, Ra, Rb, Rc) |
| ROUND3(Rc, Rd, Re, Ra, Rb) |
| ROUND3(Rb, Rc, Rd, Re, Ra) |
| SUB.S $1, Rctr |
| BNE loop3 |
| |
| MOVW $0xCA62C1D6, Rconst |
| MOVW $4, Rctr |
| loop4: ROUND4(Ra, Rb, Rc, Rd, Re) |
| ROUND4(Re, Ra, Rb, Rc, Rd) |
| ROUND4(Rd, Re, Ra, Rb, Rc) |
| ROUND4(Rc, Rd, Re, Ra, Rb) |
| ROUND4(Rb, Rc, Rd, Re, Ra) |
| SUB.S $1, Rctr |
| BNE loop4 |
| |
| // Accumulate - restoring registers from SP+4 |
| MOVM.IB (R13), [Rt0,Rt1,Rt2,Rctr,Rw] |
| ADD Rt0, Ra |
| ADD Rt1, Rb |
| ADD Rt2, Rc |
| ADD Rctr, Rd |
| ADD Rw, Re |
| |
| MOVW p_end, Rt0 |
| CMP Rt0, Rdata |
| BLO loop |
| |
| // Save final SHA-1 accumulator |
| MOVW dig+0(FP), Rt0 |
| MOVM.IA [Ra,Rb,Rc,Rd,Re], (Rt0) |
| |
| RET |