| // Copyright 2020 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. |
| |
| #include "textflag.h" |
| |
| // func kdsaSign(message, signature, privateKey []byte) bool |
| TEXT ·kdsaSign(SB), $4096-73 |
| // The kdsa instruction takes function code, |
| // buffer's location, message's location and message len |
| // as parameters. Out of those, the function code and buffer's location |
| // should be placed in R0 and R1 respectively. The message's location |
| // and message length should be placed in an even-odd register pair. (e.g: R2 and R3) |
| |
| // The content of parameter block(buffer) looks like the following: |
| // Signature R, Signature S and Private Key all take 32 bytes. |
| // In the signing case, the signatures(R and S) will be generated by |
| // the signing instruction and get placed in the locations shown in the parameter block. |
| // 0 +---------------+ |
| // | Signature(R) | |
| // 32 +---------------+ |
| // | Signature(S) | |
| // 64 +---------------+ |
| // | Private Key | |
| // 96 +---------------+ |
| // | Reserved | |
| // 112+---------------+ |
| // | | |
| // | ... | |
| // | | |
| // 4088 +---------------+ |
| |
| // The following code section setups the buffer from stack: |
| // Get the address of the buffer stack variable. |
| MOVD $buffer-4096(SP), R1 |
| |
| // Zero the buffer. |
| MOVD R1, R2 |
| MOVD $(4096/256), R0 // number of 256 byte chunks to clear |
| |
| clear: |
| XC $256, (R2), (R2) |
| MOVD $256(R2), R2 |
| BRCTG R0, clear |
| |
| MOVD $40, R0 // EDDSA-25519 sign has a function code of 40 |
| LMG message+0(FP), R2, R3 // R2=base R3=len |
| LMG signature+24(FP), R4, R5 // R4=base R5=len |
| LMG privateKey+48(FP), R6, R7 // R6=base R7=len |
| |
| // Checks the length of signature and private key |
| CMPBNE R5, $64, panic |
| CMPBNE R7, $32, panic |
| |
| // The instruction uses RFC 8032's private key, which is the first 32 bytes |
| // of the private key in this package. So we copy that into the buffer. |
| MVC $32, (R6), 64(R1) |
| |
| loop: |
| WORD $0xB93A0002 // The KDSA instruction |
| BVS loop // The instruction is exectued by hardware and can be interrupted. This does a retry when that happens. |
| BNE error |
| |
| success: |
| // The signatures generated are in big-endian form, so we |
| // need to reverse the bytes of Signature(R) and Signature(S) in the buffers to transform |
| // them from big-endian to little-endian. |
| |
| // Transform Signature(R) from big endian to little endian and copy into the signature |
| MVCIN $32, 31(R1), (R4) |
| |
| // Transform Signature(S) from big endian to little endian and copy into the signature |
| MVCIN $32, 63(R1), 32(R4) |
| |
| MOVB $1, ret+72(FP) |
| RET |
| |
| error: |
| // return false |
| MOVB $0, ret+72(FP) |
| RET |
| |
| panic: |
| UNDEF |
| |
| // func kdsaVerify(message, signature, publicKey []byte) bool |
| TEXT ·kdsaVerify(SB), $4096-73 |
| // The kdsa instruction takes function code, |
| // buffer's location, message's location and message len |
| // as parameters. Out of those, the function code and buffer's location |
| // should be placed in R0 and R1 respectively. The message's location |
| // and message length should be placed in an even-odd register pair. (e.g: R2 and R3) |
| |
| // The parameter block(buffer) is similar to that of signing, except that |
| // we use public key for verification, and Signatures(R and S) are provided |
| // as input parameters to the parameter block. |
| // 0 +---------------+ |
| // | Signature(R) | |
| // 32 +---------------+ |
| // | Signature(S) | |
| // 64 +---------------+ |
| // | Public Key | |
| // 96 +---------------+ |
| // | Reserved | |
| // 112+---------------+ |
| // | | |
| // | ... | |
| // | | |
| // 4088 +---------------+ |
| |
| // The following code section setups the buffer from stack: |
| // Get the address of the buffer stack variable. |
| MOVD $buffer-4096(SP), R1 |
| |
| // Zero the buffer. |
| MOVD R1, R2 |
| MOVD $(4096/256), R0 // number of 256 byte chunks to clear |
| |
| clear: |
| XC $256, (R2), (R2) |
| MOVD $256(R2), R2 |
| BRCTG R0, clear |
| |
| MOVD $32, R0 // EDDSA-25519 verify has a function code of 32 |
| LMG message+0(FP), R2, R3 // R2=base R3=len |
| LMG signature+24(FP), R4, R5 // R4=base R5=len |
| LMG publicKey+48(FP), R6, R7 // R6=base R7=len |
| |
| // Checks the length of public key and signature |
| CMPBNE R5, $64, panic |
| CMPBNE R7, $32, panic |
| |
| verify: |
| // The instruction needs Signature(R), Signature(S) and public key |
| // to be in big-endian form during computation. Therefore, |
| // we do the transformation (from little endian to big endian) and copy those into the buffer. |
| |
| // Transform Signature(R) from little endian to big endian and copy into the buffer |
| MVCIN $32, 31(R4), (R1) |
| |
| // Transform Signature(S) from little endian to big endian and copy into the buffer |
| MVCIN $32, 63(R4), 32(R1) |
| |
| // Transform Public Key from little endian to big endian and copy into the buffer |
| MVCIN $32, 31(R6), 64(R1) |
| |
| verifyLoop: |
| WORD $0xB93A0002 // KDSA instruction |
| BVS verifyLoop // Retry upon hardware interrupt |
| BNE error |
| |
| success: |
| MOVB $1, ret+72(FP) |
| RET |
| |
| error: |
| MOVB $0, ret+72(FP) |
| RET |
| |
| panic: |
| UNDEF |