blob: f280d18a3a6b5f80a9d8474845b5ccde96a6b033 [file] [log] [blame]
/* Copyright lowRISC contributors. */
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
/* SPDX-License-Identifier: Apache-2.0 */
/**
* Standalone unit tests for point addition of extended twisted Edwards
* coordinates for Ed25519.
*
* Tests included in this file are intended for quick sanity-checks of
* subroutines; they will not cover all edge cases.
*
* 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
/* Initialize failure counter to 0. */
bn.mov w0, w31
/* w30 <= (2*d) mod p. */
li x2, 30
la x3, two_d
bn.lid x2, 0(x3)
/* Run test. */
jal x1, run_test1
ecall
/**
* Check that P + origin = P.
*
* Increment failure counter if the test fails. In extended twisted Edwards
* coordinates, the identity is (0, Z, Z, 0) for any non-zero Z (as described in
* RFC 8032, section 5.1.4).
*
* @param[in] w19: constant, w19 = 19
* @param[in] MOD: p, modulus = 2^255 - 19
* @param[in] w30: constant, w30 = (2*d) mod p, d = (-121665/121666) mod p
* @param[in] w31: all-zero
* @param[in,out] w0: test failure counter
*
* clobbered registers: w4 to w7, w10 to w18, w20 to w23, w24 to w27
* clobbered flag groups: FG0
*/
run_test1:
/* Construct origin point (0, 1, 1, 0) in registers w10 to w13. */
bn.mov w10, w31
bn.addi w11, w31, 1
bn.addi w12, w31, 1
bn.mov w13, w31
/* Load test point P into registers w14 to w17. */
/* w14 <= dmem[p_x] */
li x2, 14
la x3, p_x
bn.lid x2++, 0(x3)
/* w15 <= dmem[p_y] */
la x3, p_y
bn.lid x2++, 0(x3)
/* w16 <= dmem[p_z] */
la x3, p_z
bn.lid x2++, 0(x3)
/* w17 <= dmem[p_t] */
la x3, p_t
bn.lid x2++, 0(x3)
/* Call ext_add.
[w13:w10] <= (0, 1, 1, 0) + P */
jal x1, ext_add
/* Check if the result is equivalent to P.
w4 <= 1 if [w13:w10] equivalent to P else 0 */
jal x1, ext_equal
/* Invert the single-bit result of the check.
w4 <= (~w4) & 1 = 0 if w4 else 1 */
bn.not w4, w4
bn.addi w5, w31, 1
bn.and w4, w4, w5
/* Increment failure counter if the test failed.
w0 <= w0 + w4 */
bn.add w0, w0, w4
ret
/**
* Check if two points in extended coordinates are equal.
*
* Returns 1 if (X1, Y1, Z1, T1) is equivalent to (x2, Y2, Z2, T2), otherwise
* returns 0.
*
* As per RFC 8032, returns 1 iff:
* (X1 * Z2 - X2 * Z1) mod p = 0, and
* (Y1 * Z2 - Y2 * Z2) mod p = 0.
*
* @param[in] w19: constant, w19 = 19
* @param[in] MOD: p, modulus = 2^255 - 19
* @param[in] w10: input X1 (X1 < p)
* @param[in] w11: input Y1 (Y1 < p)
* @param[in] w12: input Z1 (Z1 < p)
* @param[in] w13: input T1 (T1 < p)
* @param[in] w14: input X2 (X2 < p)
* @param[in] w15: input Y2 (Y2 < p)
* @param[in] w16: input Z2 (Z2 < p)
* @param[in] w17: input T2 (T2 < p)
* @param[in] w31: all-zero
* @param[out] w4: result, 1 or 0
*
* clobbered registers: w4 to w7
* clobbered flag groups: FG0
*/
ext_equal:
/* w5 <= 1 */
bn.addi w5, w31, 1
/* Compute (X1 * Z2). */
/* w22 <= w10 = X1 */
bn.mov w22, w10
/* w23 <= w16 = Z2 */
bn.mov w23, w16
/* w22 <= w22 * w23 = X1 * Z2 */
jal x1, fe_mul
/* w6 <= w22 <= X1 * Z2 */
bn.mov w6, w22
/* Compute (X2 * Z1). */
/* w22 <= w14 = X2 */
bn.mov w22, w14
/* w23 <= w12 = Z1 */
bn.mov w23, w12
/* w22 <= w22 * w23 = X2 * Z1 */
jal x1, fe_mul
/* First check. */
/* w6 <= w6 - w22 <= (X1 * Z2) - (X2 * Z1) */
bn.sub w6, w6, w22
/* w7 <= w5 if FG0.Z else w31 = 1 iff first check passed */
bn.sel w7, w5, w31, FG0.Z
/* Compute (Y1 * Z2). */
/* w22 <= w11 = Y1 */
bn.mov w22, w11
/* w23 <= w16 = Z2 */
bn.mov w23, w16
/* w22 <= w22 * w23 = Y1 * Z2 */
jal x1, fe_mul
/* w6 <= w22 <= Y1 * Z2 */
bn.mov w6, w22
/* Compute (Y2 * Z1). */
/* w22 <= w15 = Y2 */
bn.mov w22, w15
/* w23 <= w12 = Z1 */
bn.mov w23, w12
/* w22 <= w22 * w23 = Y2 * Z1 */
jal x1, fe_mul
/* Second check. */
/* w6 <= w6 - w22 <= (Y1 * Z2) - (Y2 * Z1) */
bn.sub w6, w6, w22
/* w4 <= w5 if FG0.Z else w31 = 1 iff second check passed */
bn.sel w4, w5, w31, FG0.Z
/* w4 <= w4 & w7 = check1 & check2 */
bn.and w4, w4, w7
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
/* Constant (2*d) mod p where d=(-121665/121666) mod p. */
.balign 32
two_d:
.word 0x26b2f159
.word 0xebd69b94
.word 0x8283b156
.word 0x00e0149a
.word 0xeef3d130
.word 0x198e80f2
.word 0x56dffce7
.word 0x2406d9dc
/* Randomly-generated point P = (X, Y, Z, T) for testing. */
.balign 32
p_x:
.word 0xfb26b8ad
.word 0x985868f2
.word 0x959024ff
.word 0xad05713d
.word 0x4c13236f
.word 0x4cb962fa
.word 0x94e3ec9b
.word 0x6cb4791c
.balign 32
p_y:
.word 0x02ddf0f9
.word 0x12939d50
.word 0xb60b8772
.word 0xf4a2fd69
.word 0x83e01450
.word 0x35358712
.word 0xe23a98a7
.word 0x111d76fb
.balign 32
p_z:
.word 0x00000001
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.balign 32
p_t:
.word 0xa1f92700
.word 0x90a4e7b8
.word 0x050bc191
.word 0x6fc656c2
.word 0x2b780407
.word 0x349b3769
.word 0x879cdac2
.word 0x588b3f8e