|  | /* Copyright lowRISC contributors. */ | 
|  | /* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ | 
|  | /* SPDX-License-Identifier: Apache-2.0 */ | 
|  |  | 
|  | /** | 
|  | * Standalone test for X25519/Ed25519 finite field arithmetic routines. | 
|  | * | 
|  | * This test will exit with the number of failures written to the w0 register; | 
|  | * w0=0 means all tests succeeded. | 
|  | */ | 
|  |  | 
|  | .section .text.start | 
|  |  | 
|  | main: | 
|  | /* Prepare all-zero register. */ | 
|  | bn.xor w31, w31, w31 | 
|  |  | 
|  | /* MOD <= dmem[modulus] = p */ | 
|  | li      x2, 2 | 
|  | la      x3, modulus | 
|  | bn.lid  x2, 0(x3) | 
|  | bn.wsrw 0x0, w2 | 
|  |  | 
|  | /* w19 <= 19 */ | 
|  | bn.addi w19, w31, 19 | 
|  |  | 
|  | /* Call multiply test. */ | 
|  | jal     x1, fe_mul_test | 
|  |  | 
|  | /* Call square test. */ | 
|  | jal     x1, fe_square_test | 
|  |  | 
|  | /* Call inverse test. */ | 
|  | jal     x1, fe_inv_test | 
|  |  | 
|  | ecall | 
|  |  | 
|  | fe_mul_test: | 
|  | /* w22 <= dmem[value_x] = x */ | 
|  | li      x2, 22 | 
|  | la      x3, value_x | 
|  | bn.lid  x2++, 0(x3) | 
|  |  | 
|  | /* w23 <= dmem[value_y] = y */ | 
|  | la      x3, value_y | 
|  | bn.lid  x2, 0(x3) | 
|  |  | 
|  | /* w22 <= femul(w22, w23) = (x * y) mod p */ | 
|  | jal     x1, fe_mul | 
|  |  | 
|  | /* Since x = 1, we expect (x * y) mod p == y. */ | 
|  | bn.mov  w25, w23 | 
|  | jal     x1, check_result | 
|  |  | 
|  | ret | 
|  |  | 
|  | fe_square_test: | 
|  | /* w22 <= dmem[value_y] = y */ | 
|  | li      x2, 22 | 
|  | la      x3, value_y | 
|  | bn.lid  x2, 0(x3) | 
|  |  | 
|  | /* w22 <= fe_square(w22) = (y^2) mod p */ | 
|  | jal     x1, fe_square | 
|  |  | 
|  | /* Since y = p-2, we expect (y^2) mod p == 4. */ | 
|  | bn.addi w25, w31, 4 | 
|  | jal     x1, check_result | 
|  |  | 
|  | ret | 
|  |  | 
|  | fe_inv_test: | 
|  | /* w16 <= dmem[value_y] = y */ | 
|  | li      x2, 16 | 
|  | la      x3, value_y | 
|  | bn.lid  x2, 0(x3) | 
|  |  | 
|  | /* w2 <= w16 = y */ | 
|  | bn.mov  w2, w16 | 
|  |  | 
|  | /* w22 <= fe_inv(w16) = (y^-1) mod p */ | 
|  | jal     x1, fe_inv | 
|  |  | 
|  | /* w22 <= fe_mul(w22, w23) = (y * y^-1) mod p */ | 
|  | bn.mov  w23, w2 | 
|  | jal     x1, fe_mul | 
|  |  | 
|  | /* Check that (y * y^-1) mod p is 1. */ | 
|  | bn.addi w25, w31, 1 | 
|  | jal     x1, check_result | 
|  |  | 
|  | ret | 
|  |  | 
|  | /** | 
|  | * Increment the error register if expected/actual results don't match. | 
|  | * | 
|  | * @param[in] w25: expected result | 
|  | * @param[in] w22: actual result | 
|  | * @param[in,out] w0: error count | 
|  | * | 
|  | * clobbered registers: w0, w1 | 
|  | * clobbered flag groups: FG0 | 
|  | */ | 
|  | check_result: | 
|  | /* Increment error register if expected < actual. */ | 
|  | bn.addi w1, w0, 1 | 
|  | bn.cmp  w22, w25 | 
|  | bn.sel  w0, w1, w0, C | 
|  |  | 
|  | /* Increment error register if actual < expected. */ | 
|  | bn.addi w1, w0, 1 | 
|  | bn.cmp  w25, w22 | 
|  | bn.sel  w0, w1, w0, C | 
|  | ret | 
|  |  | 
|  | .data | 
|  |  | 
|  | /* Modulus p = 2^255 - 19. */ | 
|  | .balign 32 | 
|  | modulus: | 
|  | .word 0xffffffed | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0x7fffffff | 
|  |  | 
|  | /* Test input value x = 1. */ | 
|  | .balign 32 | 
|  | value_x: | 
|  | .word 0x00000001 | 
|  | .word 0x00000000 | 
|  | .word 0x00000000 | 
|  | .word 0x00000000 | 
|  | .word 0x00000000 | 
|  | .word 0x00000000 | 
|  | .word 0x00000000 | 
|  | .word 0x00000000 | 
|  |  | 
|  | /* Test input value y = p - 2. */ | 
|  | .balign 32 | 
|  | value_y: | 
|  | .word 0xffffffeb | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0xffffffff | 
|  | .word 0x7fffffff |