|
|
|
|
|
|
|
|
|
|
|
|
| module sov_monster_kernel
|
| use, intrinsic :: iso_c_binding, only: c_int64_t, c_ptr, c_f_pointer, c_size_t, c_loc
|
| use, intrinsic :: iso_fortran_env, only: int64, real64, int8, error_unit
|
| implicit none
|
| private
|
|
|
| public :: sov_plasma_verify
|
| public :: sov_bifrost_sign
|
| public :: sov_bifrost_verify
|
| public :: sov_apl_step_zgemm_fused
|
| public :: sov_apl_evolve_sequence
|
|
|
| integer, parameter :: dp = real64
|
| integer, parameter :: i64 = int64
|
| integer, parameter :: i8 = int8
|
| complex(dp), parameter :: ci = (0.0_dp, 1.0_dp)
|
| complex(dp), parameter :: czero = (0.0_dp, 0.0_dp)
|
|
|
| integer, parameter :: HASH_LEN = 32
|
| integer, parameter :: SIG_LEN = 64
|
| integer, parameter :: SK_LEN = 32
|
| integer, parameter :: MAX_DIM = 256
|
| integer, parameter :: BLAKE3_BLOCK_LEN = 64
|
|
|
| integer(i64), parameter :: BLAKE3_IV(8) = [ &
|
| int(Z'6A09E667F3BCC908', i64), int(Z'BB67AE8584CAA73B', i64), &
|
| int(Z'3C6EF372FE94F82B', i64), int(Z'A54FF53A5F1D36F1', i64), &
|
| int(Z'510E527FADE682D1', i64), int(Z'9B05688C2B3E6C1F', i64), &
|
| int(Z'1F83D9ABFB41BD6B', i64), int(Z'5BE0CD19137E2179', i64) ]
|
|
|
| type :: blake3_state
|
| integer(i64), dimension(8) :: chaining_value
|
| integer(i8), dimension(64) :: block
|
| integer(i64) :: block_len, counter, flags
|
| end type
|
|
|
| contains
|
|
|
|
|
|
|
|
|
| pure function sov_plasma_verify(shape_ptr, rank, herm, trace_one, &
|
| hash_ptr, buffer_ptr, buffer_bytes) &
|
| bind(C, name="sov_plasma_verify") result(ok)
|
| type(c_ptr), intent(in), value :: shape_ptr, hash_ptr, buffer_ptr
|
| integer(c_int64_t), intent(in), value :: rank, buffer_bytes
|
| logical, intent(in), value :: herm, trace_one
|
| logical :: ok
|
| integer(c_int64_t), pointer :: shape(:)
|
| integer(c_int64_t) :: i
|
| ok = .false.
|
| if (rank < 1 .or. rank > 8) return
|
| call c_f_pointer(shape_ptr, shape, [rank])
|
| do i = 1, rank
|
| if (shape(i) <= 0 .or. shape(i) > MAX_DIM) return
|
| end do
|
| if (.not. herm) return
|
| if (.not. trace_one) return
|
| ok = sov_blake3_verify_buffer(buffer_ptr, buffer_bytes, hash_ptr)
|
| end function
|
|
|
|
|
|
|
|
|
| pure subroutine sov_bifrost_sign(payload_ptr, payload_len, sk_ptr, sig_ptr) &
|
| bind(C, name="sov_bifrost_sign")
|
| type(c_ptr), intent(in), value :: payload_ptr, sk_ptr, sig_ptr
|
| integer(c_size_t), intent(in), value :: payload_len
|
| integer(i8), pointer :: payload(:), sk(:), sig(:)
|
| integer(i8) :: h_sk(64), R_enc(32), s_bytes(32), h_ram(64)
|
| integer(i64) :: r_sc(10), a_sc(10), hram_sc(10), s_sc(10)
|
| integer(i64) :: Rx(10), Ry(10), Rz(10), Rt(10)
|
| call c_f_pointer(payload_ptr, payload, [payload_len])
|
| call c_f_pointer(sk_ptr, sk, [SK_LEN])
|
| call c_f_pointer(sig_ptr, sig, [SIG_LEN])
|
| call sov_blake3_hash_bytes(sk, SK_LEN, h_sk, 64)
|
| call sov_ed25519_clamp_and_decode(h_sk(1:32), a_sc)
|
| call sov_blake3_hash_concat(h_sk(33:64), 32, payload, int(payload_len), h_ram, 64)
|
| call sov_ed25519_reduce_scalar(h_ram, r_sc)
|
| call sov_ed25519_scalar_mul_base(r_sc, Rx, Ry, Rz, Rt)
|
| call sov_ed25519_encode_point(Rx, Ry, Rz, Rt, R_enc)
|
| call sov_blake3_hash_concat3(R_enc, 32, sk(33:64), 32, payload, int(payload_len), h_ram, 64)
|
| call sov_ed25519_reduce_scalar(h_ram, hram_sc)
|
| call sov_ed25519_scalar_mul(hram_sc, a_sc, s_sc)
|
| call sov_ed25519_scalar_add_mod_l(r_sc, s_sc, s_sc)
|
| call sov_ed25519_scalar_to_bytes(s_sc, s_bytes)
|
| sig(1:32) = R_enc; sig(33:64) = s_bytes
|
| end subroutine
|
|
|
| pure function sov_bifrost_verify(payload_ptr, payload_len, sig_ptr, pk_ptr) &
|
| bind(C, name="sov_bifrost_verify") result(ok)
|
| type(c_ptr), intent(in), value :: payload_ptr, sig_ptr, pk_ptr
|
| integer(c_size_t), intent(in), value :: payload_len
|
| logical :: ok
|
| integer(i8), pointer :: payload(:), sig(:), pk(:)
|
| integer(i8) :: R_enc(32), s_bytes(32), pk_bytes(32), h_ram(64), check_enc(32)
|
| integer(i64) :: s_sc(10), hram_sc(10), Rx(10),Ry(10),Rz(10),Rt(10)
|
| integer(i64) :: Ax(10),Ay(10),Az(10),At(10), cx(10),cy(10),cz(10),ct(10)
|
| call c_f_pointer(payload_ptr, payload, [payload_len])
|
| call c_f_pointer(sig_ptr, sig, [SIG_LEN])
|
| call c_f_pointer(pk_ptr, pk, [32])
|
| R_enc = sig(1:32); s_bytes = sig(33:64); pk_bytes = pk(1:32)
|
| call sov_ed25519_scalar_from_bytes(s_bytes, s_sc)
|
| if (.not. sov_ed25519_scalar_valid(s_sc)) then; ok=.false.; return; end if
|
| if (.not. sov_ed25519_decode_point(R_enc, Rx,Ry,Rz,Rt)) then; ok=.false.; return; end if
|
| if (.not. sov_ed25519_decode_point(pk_bytes, Ax,Ay,Az,At)) then; ok=.false.; return; end if
|
| call sov_blake3_hash_concat3(R_enc,32, pk_bytes,32, payload,int(payload_len), h_ram,64)
|
| call sov_ed25519_reduce_scalar(h_ram, hram_sc)
|
| call sov_ed25519_scalar_mul_base(s_sc, cx, cy, cz, ct)
|
| call sov_ed25519_point_negate(Ax, Ay, Az, At)
|
| call sov_ed25519_scalar_mul_point(hram_sc, Ax,Ay,Az,At, cx,cy,cz,ct)
|
| call sov_ed25519_point_add(Rx,Ry,Rz,Rt, cx,cy,cz,ct, cx,cy,cz,ct)
|
| call sov_ed25519_encode_point(cx,cy,cz,ct, check_enc)
|
| ok = all(check_enc == R_enc)
|
| end function
|
|
|
|
|
|
|
|
|
| subroutine sov_apl_step_zgemm_fused(H, ldH, rho, ldr, dt, &
|
| sk, pk, out_rho, out_hash, out_sig) &
|
| bind(C, name="sov_apl_step_zgemm_fused")
|
| complex(dp), intent(in), dimension(ldH,*) :: H
|
| integer(c_int64_t), intent(in), value :: ldH
|
| complex(dp), intent(in), dimension(ldr,*) :: rho
|
| integer(c_int64_t), intent(in), value :: ldr
|
| real(dp), intent(in), value :: dt
|
| type(c_ptr), intent(in), value :: sk, pk
|
| complex(dp), intent(out), dimension(ldr,*) :: out_rho
|
| type(c_ptr), intent(inout), value :: out_hash, out_sig
|
| integer(c_int64_t) :: n, i, j, k
|
| complex(dp), allocatable :: U(:,:), Ut(:,:), tmp(:,:)
|
| n = ldr
|
| if (.not. sov_is_hermitian_matrix(H, n)) call sov_fault(1)
|
| if (.not. sov_is_density_matrix(rho, n)) call sov_fault(2)
|
| allocate(U(n,n), Ut(n,n), tmp(n,n))
|
| U = -ci * dt * H(1:n, 1:n)
|
| call sov_zmexp_scaling_squaring(U, int(n))
|
|
|
| do j = 1, n; do i = 1, n; Ut(i,j) = conjg(U(j,i)); end do; end do
|
|
|
|
|
|
|
| do j = 1, n; do i = 1, n
|
| tmp(i,j) = czero
|
| do k = 1, n; tmp(i,j) = tmp(i,j) + U(i,k)*rho(k,j); end do
|
| end do; end do
|
|
|
|
|
|
|
| do j = 1, n; do i = 1, n
|
| out_rho(i,j) = czero
|
| do k = 1, n; out_rho(i,j) = out_rho(i,j) + tmp(i,k)*Ut(k,j); end do
|
| end do; end do
|
|
|
| if (.not. sov_is_density_matrix(out_rho, n)) call sov_fault(3)
|
| call sov_blake3_hash_matrix(out_rho, int(n), out_hash)
|
| call sov_bifrost_sign(out_hash, int(HASH_LEN, c_size_t), sk, out_sig)
|
| deallocate(U, Ut, tmp)
|
| end subroutine
|
|
|
|
|
|
|
|
|
| subroutine sov_apl_evolve_sequence(H, ldH, rho, ldr, steps, dt, &
|
| sk, pk, out_receipts, out_receipts_len) &
|
| bind(C, name="sov_apl_evolve_sequence")
|
| complex(dp), intent(in), dimension(ldH,*) :: H
|
| integer(c_int64_t), intent(in), value :: ldH
|
| complex(dp), intent(inout), dimension(ldr,*) :: rho
|
| integer(c_int64_t), intent(in), value :: ldr, steps
|
| real(dp), intent(in), value :: dt
|
| type(c_ptr), intent(in), value :: sk, pk, out_receipts
|
| integer(c_int64_t), intent(in), value :: out_receipts_len
|
| integer(c_int64_t) :: n, step, receipt_sz
|
| complex(dp), allocatable :: tmp_rho(:,:)
|
| type(c_ptr) :: hash_ptr, sig_ptr
|
| integer(i8), pointer :: receipts(:)
|
| n = ldr; receipt_sz = HASH_LEN + SIG_LEN
|
| if (out_receipts_len < steps * receipt_sz) call sov_fault(4)
|
| call c_f_pointer(out_receipts, receipts, [out_receipts_len])
|
| if (.not. sov_is_hermitian_matrix(H, n)) call sov_fault(1)
|
| if (.not. sov_is_density_matrix(rho, n)) call sov_fault(2)
|
| allocate(tmp_rho(n,n))
|
| do step = 1, steps
|
| hash_ptr = c_loc(receipts((step-1)*receipt_sz + 1))
|
| sig_ptr = c_loc(receipts((step-1)*receipt_sz + HASH_LEN + 1))
|
| call sov_apl_step_zgemm_fused(H, n, rho, n, dt, sk, pk, tmp_rho, hash_ptr, sig_ptr)
|
| rho(1:n, 1:n) = tmp_rho
|
| end do
|
| deallocate(tmp_rho)
|
| end subroutine
|
|
|
|
|
|
|
|
|
| subroutine sov_zmexp_scaling_squaring(A, n)
|
| complex(dp), intent(inout), dimension(n,n) :: A
|
| integer, intent(in) :: n
|
| real(dp), parameter :: THETA13 = 5.371920351148152_dp
|
| integer :: m, i, j
|
| real(dp) :: norm, row_sum
|
| complex(dp), allocatable :: A2(:,:), A4(:,:), A6(:,:), U(:,:), V(:,:), tmp(:,:)
|
|
|
| real(dp), parameter :: c(0:13) = [ &
|
| 64764752532480000.0_dp, 32382376266240000.0_dp, &
|
| 7771770303897600.0_dp, 1187353796428800.0_dp, &
|
| 129060195264000.0_dp, 10559470521600.0_dp, &
|
| 670442572800.0_dp, 33522128640.0_dp, &
|
| 1323241920.0_dp, 40840800.0_dp, &
|
| 960960.0_dp, 16380.0_dp, &
|
| 182.0_dp, 1.0_dp ]
|
| norm = 0.0_dp
|
| do i = 1, n
|
| row_sum = 0.0_dp
|
| do j = 1, n; row_sum = row_sum + abs(A(i,j)); end do
|
| norm = max(norm, row_sum)
|
| end do
|
| m = 0
|
| if (norm > THETA13) m = ceiling(log(norm/THETA13)/log(2.0_dp))
|
| if (m > 0) A = A * (1.0_dp / 2.0_dp**m)
|
| allocate(A2(n,n), A4(n,n), A6(n,n), U(n,n), V(n,n), tmp(n,n))
|
| A2 = matmul(A, A); A4 = matmul(A2, A2); A6 = matmul(A2, A4)
|
|
|
| tmp = c(12)*A6 + c(10)*A4 + c(8)*A2
|
| do i=1,n; tmp(i,i)=tmp(i,i)+c(6); end do
|
| V = c(4)*A4 + c(2)*A2
|
| do i=1,n; V(i,i)=V(i,i)+c(0); end do
|
| V = V + matmul(A6, tmp)
|
|
|
| tmp = c(13)*A6 + c(11)*A4 + c(9)*A2
|
| do i=1,n; tmp(i,i)=tmp(i,i)+c(7); end do
|
| U = c(5)*A4 + c(3)*A2
|
| do i=1,n; U(i,i)=U(i,i)+c(1); end do
|
| U = matmul(A, U + matmul(A6, tmp))
|
|
|
| tmp = V + U
|
| V = V - U
|
| call sov_zgetrf(V, n)
|
| call sov_zgetrs(V, n, tmp)
|
| A = tmp
|
| do i = 1, m; A = matmul(A, A); end do
|
| deallocate(A2, A4, A6, U, V, tmp)
|
| end subroutine
|
|
|
|
|
|
|
|
|
| pure subroutine sov_zgetrf(A, n)
|
| complex(dp), intent(inout), dimension(n,n) :: A
|
| integer, intent(in) :: n
|
| integer :: i, j, k, piv
|
| complex(dp) :: row(n), fac
|
| real(dp) :: mx
|
| do k = 1, n-1
|
| piv = k; mx = abs(A(k,k))
|
| do i = k+1, n
|
| if (abs(A(i,k)) > mx) then; mx = abs(A(i,k)); piv = i; end if
|
| end do
|
| if (piv /= k) then; row=A(k,:); A(k,:)=A(piv,:); A(piv,:)=row; end if
|
| if (abs(A(k,k)) > tiny(0.0_dp)) then
|
| do i = k+1, n
|
| fac = A(i,k)/A(k,k); A(i,k) = fac
|
| do j = k+1, n; A(i,j) = A(i,j) - fac*A(k,j); end do
|
| end do
|
| end if
|
| end do
|
| end subroutine
|
|
|
| pure subroutine sov_zgetrs(LU, n, B)
|
| complex(dp), intent(in), dimension(n,n) :: LU
|
| integer, intent(in) :: n
|
| complex(dp), intent(inout), dimension(n,n) :: B
|
| integer :: i, j, k
|
| complex(dp) :: s
|
| do j = 1, n
|
| do i = 1, n
|
| s = B(i,j); do k=1,i-1; s=s-LU(i,k)*B(k,j); end do; B(i,j)=s
|
| end do
|
| do i = n, 1, -1
|
| s = B(i,j); do k=i+1,n; s=s-LU(i,k)*B(k,j); end do; B(i,j)=s/LU(i,i)
|
| end do
|
| end do
|
| end subroutine
|
|
|
| pure function sov_is_hermitian_matrix(A, n) result(ok)
|
| complex(dp), intent(in), dimension(n,n) :: A
|
| integer(c_int64_t), intent(in) :: n
|
| logical :: ok
|
| integer :: i, j
|
| real(dp) :: tol
|
| tol = 1.0e-10_dp * real(n, dp); ok = .true.
|
| do j = 1, n
|
| if (abs(aimag(A(j,j))) > tol) then; ok=.false.; return; end if
|
| do i = 1, j-1
|
| if (abs(A(i,j)-conjg(A(j,i))) > tol) then; ok=.false.; return; end if
|
| end do
|
| end do
|
| end function
|
|
|
| pure function sov_is_density_matrix(rho, n) result(ok)
|
| complex(dp), intent(in), dimension(n,n) :: rho
|
| integer(c_int64_t), intent(in) :: n
|
| logical :: ok
|
| real(dp) :: tr, tol
|
| integer :: i
|
| tol = 1.0e-10_dp * real(n, dp); ok = .false.
|
| if (.not. sov_is_hermitian_matrix(rho, n)) return
|
| tr = 0.0_dp; do i=1,n; tr=tr+real(rho(i,i)); end do
|
| if (abs(tr-1.0_dp) > tol) return
|
| ok = .true.
|
| end function
|
|
|
|
|
|
|
|
|
| pure subroutine sov_blake3_init(s)
|
| type(blake3_state), intent(out) :: s
|
| s%chaining_value = BLAKE3_IV; s%block=0_i8; s%block_len=0; s%counter=0; s%flags=0
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_update(s, input, in_len)
|
| type(blake3_state), intent(inout) :: s
|
| integer(i8), intent(in), dimension(*) :: input
|
| integer, intent(in) :: in_len
|
| integer :: i
|
| do i = 1, in_len
|
| s%block_len = s%block_len + 1
|
| s%block(s%block_len) = input(i)
|
| if (s%block_len == BLAKE3_BLOCK_LEN) then
|
| call sov_blake3_compress(s); s%counter=s%counter+BLAKE3_BLOCK_LEN; s%block_len=0; s%block=0_i8
|
| end if
|
| end do
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_finalize(s, out, out_len)
|
| type(blake3_state), intent(inout) :: s
|
| integer(i8), intent(out), dimension(*) :: out
|
| integer, intent(in) :: out_len
|
| integer :: i, j
|
| s%flags = ior(s%flags, 4_i64)
|
| call sov_blake3_compress(s)
|
| do i = 1, min(out_len/8, 8)
|
| do j = 1, 8
|
| out((i-1)*8+j) = int(iand(shiftr(s%chaining_value(i),8*(j-1)),Z'FF'),i8)
|
| end do
|
| end do
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_compress(s)
|
| type(blake3_state), intent(inout) :: s
|
| integer(i64) :: v(16), m(16)
|
| integer :: i, j, r
|
| integer, parameter :: SIGMA(16,7) = reshape([ &
|
| 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, &
|
| 2,6,3,10,7,0,4,13,1,11,12,5,9,14,15,8, &
|
| 3,4,10,12,13,2,7,14,6,5,9,0,11,15,8,1, &
|
| 10,7,12,9,14,3,13,15,4,0,11,2,5,8,1,6, &
|
| 12,13,9,11,15,10,14,8,7,2,5,3,0,1,6,4, &
|
| 9,14,11,5,8,12,15,1,13,3,0,7,2,4,6,10, &
|
| 11,15,5,0,1,9,8,2,10,7,3,12,4,6,13,14 /],[16,7])
|
| do i=1,8; v(i)=s%chaining_value(i); end do
|
| v(9:16) = BLAKE3_IV
|
| v(13) = ieor(v(13), s%counter)
|
| v(15) = ieor(v(15), s%block_len)
|
| v(16) = ieor(v(16), s%flags)
|
| do i = 1, 16
|
| m(i) = 0_i64
|
| do j = 1, 4
|
| m(i) = ior(m(i), shiftl(int(iand(s%block((i-1)*4+j),int(Z'FF',i8)),i64),8*(j-1)))
|
| end do
|
| end do
|
| do r = 1, 7
|
| call sov_blake3_g(v, m(SIGMA(1,r)+1), m(SIGMA(2,r)+1), 1, 5, 9,13)
|
| call sov_blake3_g(v, m(SIGMA(3,r)+1), m(SIGMA(4,r)+1), 2, 6,10,14)
|
| call sov_blake3_g(v, m(SIGMA(5,r)+1), m(SIGMA(6,r)+1), 3, 7,11,15)
|
| call sov_blake3_g(v, m(SIGMA(7,r)+1), m(SIGMA(8,r)+1), 4, 8,12,16)
|
| call sov_blake3_g(v, m(SIGMA(9,r)+1), m(SIGMA(10,r)+1), 1, 6,11,16)
|
| call sov_blake3_g(v, m(SIGMA(11,r)+1),m(SIGMA(12,r)+1), 2, 7,12,13)
|
| call sov_blake3_g(v, m(SIGMA(13,r)+1),m(SIGMA(14,r)+1), 3, 8, 9,14)
|
| call sov_blake3_g(v, m(SIGMA(15,r)+1),m(SIGMA(16,r)+1), 4, 5,10,15)
|
| end do
|
| do i=1,8; s%chaining_value(i)=ieor(v(i),v(i+8)); end do
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_g(v, mx, my, a, b, c, d)
|
| integer(i64), intent(inout), dimension(16) :: v
|
| integer(i64), intent(in) :: mx, my
|
| integer, intent(in) :: a, b, c, d
|
| v(a)=v(a)+v(b)+mx; v(d)=ishftc(ieor(v(d),v(a)),-32)
|
| v(c)=v(c)+v(d); v(b)=ishftc(ieor(v(b),v(c)),-24)
|
| v(a)=v(a)+v(b)+my; v(d)=ishftc(ieor(v(d),v(a)),-16)
|
| v(c)=v(c)+v(d); v(b)=ishftc(ieor(v(b),v(c)),-63)
|
| end subroutine
|
|
|
| pure function sov_blake3_verify_buffer(buf_ptr, buf_len, hash_ptr) result(ok)
|
| type(c_ptr), intent(in), value :: buf_ptr, hash_ptr
|
| integer(c_int64_t), intent(in), value :: buf_len
|
| logical :: ok
|
| integer(i8), pointer :: buf(:), expected(:)
|
| integer(i8) :: computed(32)
|
| type(blake3_state) :: state
|
| call c_f_pointer(buf_ptr, buf, [buf_len]); call c_f_pointer(hash_ptr, expected, [32])
|
| call sov_blake3_init(state); call sov_blake3_update(state, buf, int(buf_len))
|
| call sov_blake3_finalize(state, computed, 32); ok = all(computed == expected)
|
| end function
|
|
|
| pure subroutine sov_blake3_hash_matrix(mat, n, hash_ptr)
|
| complex(dp), intent(in), dimension(n,n) :: mat
|
| integer, intent(in) :: n
|
| type(c_ptr), intent(in), value :: hash_ptr
|
| integer(i8), pointer :: hash_bytes(:)
|
| type(blake3_state) :: state
|
| integer(i8) :: buf(16)
|
| integer(i64) :: bits
|
| integer :: i, j, k
|
| call c_f_pointer(hash_ptr, hash_bytes, [32])
|
| call sov_blake3_init(state)
|
| do j = 1, n; do i = 1, n
|
| bits = transfer(real(mat(i,j)), bits)
|
| do k=1,8; buf(k) =int(iand(shiftr(bits,8*(k-1)),Z'FF'),i8); end do
|
| bits = transfer(aimag(mat(i,j)), bits)
|
| do k=1,8; buf(8+k)=int(iand(shiftr(bits,8*(k-1)),Z'FF'),i8); end do
|
| call sov_blake3_update(state, buf, 16)
|
| end do; end do
|
| call sov_blake3_finalize(state, hash_bytes, 32)
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_hash_bytes(input, in_len, out, out_len)
|
| integer(i8), intent(in), dimension(*) :: input
|
| integer, intent(in) :: in_len, out_len
|
| integer(i8), intent(out), dimension(*) :: out
|
| type(blake3_state) :: state
|
| call sov_blake3_init(state); call sov_blake3_update(state, input, in_len)
|
| call sov_blake3_finalize(state, out, out_len)
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_hash_concat(a, la, b, lb, out, out_len)
|
| integer(i8), intent(in), dimension(*) :: a, b
|
| integer, intent(in) :: la, lb, out_len
|
| integer(i8), intent(out), dimension(*) :: out
|
| type(blake3_state) :: state
|
| call sov_blake3_init(state); call sov_blake3_update(state, a, la)
|
| call sov_blake3_update(state, b, lb); call sov_blake3_finalize(state, out, out_len)
|
| end subroutine
|
|
|
| pure subroutine sov_blake3_hash_concat3(a,la, b,lb, c,lc, out,out_len)
|
| integer(i8), intent(in), dimension(*) :: a, b, c
|
| integer, intent(in) :: la, lb, lc, out_len
|
| integer(i8), intent(out), dimension(*) :: out
|
| type(blake3_state) :: state
|
| call sov_blake3_init(state); call sov_blake3_update(state, a, la)
|
| call sov_blake3_update(state, b, lb); call sov_blake3_update(state, c, lc)
|
| call sov_blake3_finalize(state, out, out_len)
|
| end subroutine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| pure subroutine fe_reduce(f)
|
| integer(i64), intent(inout), dimension(10) :: f
|
| integer(i64) :: c
|
|
|
| c=shiftr(f(1),26); f(1)=iand(f(1),int(Z'3FFFFFF',i64)); f(2)=f(2)+c
|
| c=shiftr(f(2),25); f(2)=iand(f(2),int(Z'1FFFFFF',i64)); f(3)=f(3)+c
|
| c=shiftr(f(3),26); f(3)=iand(f(3),int(Z'3FFFFFF',i64)); f(4)=f(4)+c
|
| c=shiftr(f(4),25); f(4)=iand(f(4),int(Z'1FFFFFF',i64)); f(5)=f(5)+c
|
| c=shiftr(f(5),26); f(5)=iand(f(5),int(Z'3FFFFFF',i64)); f(6)=f(6)+c
|
| c=shiftr(f(6),25); f(6)=iand(f(6),int(Z'1FFFFFF',i64)); f(7)=f(7)+c
|
| c=shiftr(f(7),26); f(7)=iand(f(7),int(Z'3FFFFFF',i64)); f(8)=f(8)+c
|
| c=shiftr(f(8),25); f(8)=iand(f(8),int(Z'1FFFFFF',i64)); f(9)=f(9)+c
|
| c=shiftr(f(9),26); f(9)=iand(f(9),int(Z'3FFFFFF',i64)); f(10)=f(10)+c
|
| c=shiftr(f(10),25); f(10)=iand(f(10),int(Z'1FFFFFF',i64)); f(1)=f(1)+19*c
|
| c=shiftr(f(1),26); f(1)=iand(f(1),int(Z'3FFFFFF',i64)); f(2)=f(2)+c
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_add(a, b, f)
|
| integer(i64), intent(in), dimension(10) :: a, b
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer :: i
|
| do i=1,10; f(i)=a(i)+b(i); end do
|
| call fe_reduce(f)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_sub(a, b, f)
|
| integer(i64), intent(in), dimension(10) :: a, b
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer :: i
|
|
|
| integer(i64), parameter :: TWO_P(10) = [ &
|
| int(Z'7FFFFDA', i64), int(Z'3FFFFFE', i64), int(Z'7FFFFFE', i64), &
|
| int(Z'3FFFFFE', i64), int(Z'7FFFFFE', i64), int(Z'3FFFFFE', i64), &
|
| int(Z'7FFFFFE', i64), int(Z'3FFFFFE', i64), int(Z'7FFFFFE', i64), &
|
| int(Z'3FFFFFE', i64) ]
|
| do i=1,10; f(i)=a(i)-b(i)+TWO_P(i); end do
|
| call fe_reduce(f)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_mul(a, b, f)
|
| integer(i64), intent(in), dimension(10) :: a, b
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer(i64) :: h(10), b2(2:10)
|
| integer :: i
|
|
|
| do i=2,10,2; b2(i)=2*b(i); end do
|
|
|
| integer(i64) :: b19(10)
|
| do i=1,10; b19(i)=19*b(i); end do
|
| integer(i64) :: b219(2:10)
|
| do i=2,10,2; b219(i)=2*b19(i); end do
|
|
|
| h(1) = a(1)*b(1) + a(3)*b19(9) *2 + a(5)*b19(7) *2 + a(7)*b19(5) *2 + a(9)*b19(3) *2 &
|
| + a(2)*b19(10) + a(4)*b19(8) *2 + a(6)*b19(6) + a(8)*b19(4) *2 + a(10)*b19(2)
|
| h(2) = a(1)*b(2) + a(2)*b(1) + a(3)*b19(10) + a(4)*b19(9) *2 + a(5)*b19(8) *2 &
|
| + a(6)*b19(7) *2 + a(7)*b19(6) *2 + a(8)*b19(5) *2 + a(9)*b19(4) *2 + a(10)*b19(3) *2
|
| h(3) = a(1)*b(3) + a(3)*b(1) + a(5)*b19(9) *2 + a(7)*b19(7) *2 + a(9)*b19(5) *2 &
|
| + a(2)*b2(2) + a(4)*b19(10)*2 + a(6)*b19(8) *2 + a(8)*b19(6) *2 + a(10)*b19(4) *2
|
| h(4) = a(1)*b(4) + a(2)*b(3) + a(3)*b(2) + a(4)*b(1) + a(5)*b19(10)*2 &
|
| + a(6)*b19(9) *2 + a(7)*b19(8) *2 + a(8)*b19(7) *2 + a(9)*b19(6) *2 + a(10)*b19(5) *2
|
| h(5) = a(1)*b(5) + a(3)*b(3) + a(5)*b(1) + a(7)*b19(9) *2 + a(9)*b19(7) *2 &
|
| + a(2)*b2(4) + a(4)*b2(2) + a(6)*b19(10)*2 + a(8)*b19(8) *2 + a(10)*b19(6) *2
|
| h(6) = a(1)*b(6) + a(2)*b(5) + a(3)*b(4) + a(4)*b(3) + a(5)*b(2) + a(6)*b(1) &
|
| + a(7)*b19(10)*2 + a(8)*b19(9) *2 + a(9)*b19(8) *2 + a(10)*b19(7) *2
|
| h(7) = a(1)*b(7) + a(3)*b(5) + a(5)*b(3) + a(7)*b(1) + a(9)*b19(9) *2 &
|
| + a(2)*b2(6) + a(4)*b2(4) + a(6)*b2(2) + a(8)*b19(10)*2 + a(10)*b19(8) *2
|
| h(8) = a(1)*b(8) + a(2)*b(7) + a(3)*b(6) + a(4)*b(5) + a(5)*b(4) + a(6)*b(3) &
|
| + a(7)*b(2) + a(8)*b(1) + a(9)*b19(10)*2 + a(10)*b19(9) *2
|
| h(9) = a(1)*b(9) + a(3)*b(7) + a(5)*b(5) + a(7)*b(3) + a(9)*b(1) &
|
| + a(2)*b2(8) + a(4)*b2(6) + a(6)*b2(4) + a(8)*b2(2) + a(10)*b19(10)*2
|
| h(10) = a(1)*b(10) + a(2)*b(9) + a(3)*b(8) + a(4)*b(7) + a(5)*b(6) &
|
| + a(6)*b(5) + a(7)*b(4) + a(8)*b(3) + a(9)*b(2) + a(10)*b(1)
|
| f = h
|
| call fe_reduce(f)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_sq(a, f)
|
| integer(i64), intent(in), dimension(10) :: a
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer(i64) :: h(10), a2(10), a19(10), a219(10)
|
| integer :: i
|
| do i=1,10; a2(i)=2*a(i); end do
|
| do i=1,10; a19(i)=19*a(i); end do
|
| do i=1,10; a219(i)=2*a19(i); end do
|
|
|
| h(1) = a(1)*a(1) + a219(9)*a(2) + a219(8)*a(3) + a219(7)*a(4) + a219(6)*a(5)
|
| h(2) = a2(1)*a(2) + a219(9)*a(3) + a2(19)*a(8)*a(4) + a219(7)*a(5) + a219(6)*a(6)
|
|
|
| h(1) = a(1)*a(1) + 2*( a(2)*a19(10) + a(3)*2*a19(9) + a(4)*2*a19(8) + a(5)*2*a19(7) &
|
| + a(6)*a19(6) )
|
| h(2) = 2*a(1)*a(2) + 2*( a(3)*a19(10) + a(4)*2*a19(9) + a(5)*2*a19(8) + a(6)*2*a19(7) )
|
| h(3) = 2*a(1)*a(3) + a(2)*a(2) + 2*( a(4)*2*a19(10) + a(5)*2*a19(9) + a(6)*2*a19(8) )
|
| h(4) = 2*(a(1)*a(4)+a(2)*a(3)) + 2*( a(5)*2*a19(10) + a(6)*2*a19(9) + a(7)*2*a19(8) )
|
| h(5) = 2*(a(1)*a(5)+a(3)*a(3)*0)+2*a(1)*a(5)+a(3)*a(3)+2*a(2)*a(4) &
|
| + 2*( a(6)*2*a19(10) + a(7)*2*a19(9) )
|
|
|
| h(1) = a(1)*a(1) + 38*(a(6)*a(6)) + 76*(a(5)*a(7)+a(4)*a(8)+a(3)*a(9)+a(2)*a(10)) &
|
| + 38*(a(7)*a(7)*2)
|
| h(1) = a(1)*a(1) + 2*(a(2)*a19(10)+a(3)*38*a(9)+a(4)*38*a(8)+a(5)*38*a(7)) + 19*(a(6)*a(6))
|
|
|
|
|
| h(1) = a(1)*a(1) + 2*(a(2)*(19*a(10)) + a(3)*(2*19*a(9)) + a(4)*(2*19*a(8)) &
|
| + a(5)*(2*19*a(7))) + (19*a(6)*a(6))
|
| h(2) = 2*(a(1)*a(2) + a(3)*(19*a(10)) + a(4)*(2*19*a(9)) &
|
| + a(5)*(2*19*a(8)) + a(6)*(19*a(7)))
|
| h(3) = 2*a(1)*a(3) + a(2)*a(2) + 2*(a(4)*(2*19*a(10)) &
|
| + a(5)*(2*19*a(9)) + a(6)*(19*a(8))) + (2*19)*a(7)*a(7)
|
| h(4) = 2*(a(1)*a(4)+a(2)*a(3)) + 2*(a(5)*(2*19*a(10)) &
|
| + a(6)*(19*a(9)) + a(7)*(19*a(8))*2)
|
| h(5) = 2*(a(1)*a(5)+a(2)*a(4)) + a(3)*a(3) + 2*(a(6)*(2*19*a(10)) &
|
| + a(7)*(2*19*a(9))) + (19)*a(8)*a(8)
|
| h(6) = 2*(a(1)*a(6)+a(2)*a(5)+a(3)*a(4)) + 2*(a(7)*(2*19*a(10)) + a(8)*(19*a(9)))
|
| h(7) = 2*(a(1)*a(7)+a(2)*a(6)+a(3)*a(5)) + a(4)*a(4) + 2*a(8)*(2*19*a(10)) &
|
| + (2*19)*a(9)*a(9)
|
| h(8) = 2*(a(1)*a(8)+a(2)*a(7)+a(3)*a(6)+a(4)*a(5)) + 2*a(9)*(2*19*a(10))
|
| h(9) = 2*(a(1)*a(9)+a(2)*a(8)+a(3)*a(7)+a(4)*a(6)) + a(5)*a(5) + (2)*a(10)*(2*19*a(10))
|
| h(10)= 2*(a(1)*a(10)+a(2)*a(9)+a(3)*a(8)+a(4)*a(7)+a(5)*a(6))
|
| f = h
|
| call fe_reduce(f)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_sq_n(a, n, f)
|
| integer(i64), intent(in), dimension(10) :: a
|
| integer, intent(in) :: n
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer :: i
|
| f = a
|
| do i = 1, n; call fe_sq(f, f); end do
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_inv(a, f)
|
| integer(i64), intent(in), dimension(10) :: a
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer(i64) :: t0(10),t1(10),t2(10),t3(10)
|
| call fe_sq(a, t0)
|
| call fe_mul(a, t0, t1)
|
| call fe_sq(t1, t0)
|
| call fe_mul(a, t0, t0)
|
| call fe_sq_n(t0, 3, t1)
|
| call fe_mul(t0, t1, t1)
|
| call fe_sq(t1, t0)
|
| call fe_mul(a, t0, t0)
|
|
|
| call fe_sq(a, t0)
|
| call fe_mul(a, t0, t1)
|
| call fe_sq(t1, t2)
|
| call fe_mul(a, t2, t2)
|
| call fe_sq_n(t2,3, t3)
|
| call fe_mul(t2, t3, t3)
|
| call fe_sq_n(t3,6, t0)
|
| call fe_mul(t3, t0, t0)
|
| call fe_sq(t0, t2)
|
| call fe_mul(a, t2, t2)
|
|
|
| call fe_sq(a, t0)
|
| call fe_mul(a, t0, t1)
|
| call fe_sq(t1, t0)
|
| call fe_mul(a, t0, t0)
|
| call fe_sq(t0, t2)
|
| call fe_mul(a, t2, t2)
|
| call fe_sq_n(t2,5, t1)
|
| call fe_mul(t2, t1, t1)
|
| call fe_sq_n(t1,10, t2)
|
| call fe_mul(t1, t2, t2)
|
| call fe_sq_n(t2,20, t3)
|
| call fe_mul(t2, t3, t3)
|
| call fe_sq_n(t3,10, t0)
|
| call fe_mul(t1, t0, t0)
|
| call fe_sq_n(t0,50, t2)
|
| call fe_mul(t0, t2, t2)
|
| call fe_sq_n(t2,100,t3)
|
| call fe_mul(t2, t3, t3)
|
| call fe_sq_n(t3,50, t0)
|
| call fe_mul(t0, t0, t0)
|
|
|
| call fe_sq_n(t3,50, t0)
|
| call fe_mul(t2, t0, t0)
|
| call fe_sq_n(t0,5, t1)
|
| call fe_mul(t1, a, f)
|
|
|
| call fe_sq(t0, t0)
|
| integer(i64) :: a8(10),a11(10)
|
| call fe_sq(a,a8); call fe_sq(a8,a8); call fe_sq(a8,a8)
|
| call fe_mul(a8, t0, t0)
|
|
|
| call fe_sq(a, t0)
|
| call fe_sq(t0, t1)
|
| call fe_sq(t1, t1)
|
| call fe_mul(t1, a, t1)
|
| call fe_mul(t1, t0, t0)
|
| call fe_sq(t0, t2)
|
| call fe_mul(t2, t1, t1)
|
| call fe_sq_n(t1,5, t2)
|
| call fe_mul(t2, t1, t1)
|
| call fe_sq_n(t1,10, t2)
|
| call fe_mul(t2, t1, t2)
|
| call fe_sq_n(t2,20, t3)
|
| call fe_mul(t3, t2, t2)
|
| call fe_sq_n(t2,10, t3)
|
| call fe_mul(t3, t1, t1)
|
| call fe_sq_n(t1,50, t2)
|
| call fe_mul(t2, t1, t2)
|
| call fe_sq_n(t2,100,t3)
|
| call fe_mul(t3, t2, t2)
|
| call fe_sq_n(t2,50, t3)
|
| call fe_mul(t3, t1, t1)
|
| call fe_sq_n(t1,5, t2)
|
| call fe_mul(t2, t0, f)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_tobytes(f, b)
|
| integer(i64), intent(in), dimension(10) :: f
|
| integer(i8), intent(out), dimension(32) :: b
|
| integer(i64) :: h(10), c
|
| integer :: i
|
| h = f
|
| call fe_reduce(h)
|
|
|
|
|
|
|
| c = 19_i64
|
| do i=1,9
|
| h(i) = h(i)+c
|
| if (mod(i,2)==1) then; c=shiftr(h(i),26); h(i)=iand(h(i),int(Z'3FFFFFF',i64))
|
| else; c=shiftr(h(i),25); h(i)=iand(h(i),int(Z'1FFFFFF',i64)); end if
|
| end do
|
| h(10)=h(10)+c; c=shiftr(h(10),25); h(10)=iand(h(10),int(Z'1FFFFFF',i64))
|
| h(1)=h(1)+19*c
|
| c=shiftr(h(1),26); h(1)=iand(h(1),int(Z'3FFFFFF',i64)); h(2)=h(2)+c
|
|
|
| b = 0_i8
|
| b(1) = int(iand(h(1),Z'FF'),i8)
|
| b(2) = int(iand(shiftr(h(1),8),Z'FF'),i8)
|
| b(3) = int(iand(shiftr(h(1),16),Z'FF'),i8)
|
| b(4) = int(iand(ior(shiftr(h(1),24), shiftl(h(2),2)),Z'FF'),i8)
|
| b(5) = int(iand(shiftr(h(2),6),Z'FF'),i8)
|
| b(6) = int(iand(shiftr(h(2),14),Z'FF'),i8)
|
| b(7) = int(iand(ior(shiftr(h(2),22), shiftl(h(3),3)),Z'FF'),i8)
|
| b(8) = int(iand(shiftr(h(3),5),Z'FF'),i8)
|
| b(9) = int(iand(shiftr(h(3),13),Z'FF'),i8)
|
| b(10)= int(iand(ior(shiftr(h(3),21), shiftl(h(4),4)),Z'FF'),i8)
|
| b(11)= int(iand(shiftr(h(4),4),Z'FF'),i8)
|
| b(12)= int(iand(shiftr(h(4),12),Z'FF'),i8)
|
| b(13)= int(iand(ior(shiftr(h(4),20), shiftl(h(5),5)),Z'FF'),i8)
|
| b(14)= int(iand(shiftr(h(5),3),Z'FF'),i8)
|
| b(15)= int(iand(shiftr(h(5),11),Z'FF'),i8)
|
| b(16)= int(iand(ior(shiftr(h(5),19), shiftl(h(6),6)),Z'FF'),i8)
|
| b(16)= int(iand(ior(shiftr(h(5),19), shiftl(h(6),6)),Z'FF'),i8)
|
| b(17)= int(iand(shiftr(h(6),2),Z'FF'),i8)
|
| b(18)= int(iand(shiftr(h(6),10),Z'FF'),i8)
|
| b(19)= int(iand(shiftr(h(6),18),Z'FF'),i8)
|
| b(20)= int(iand(ior(shiftr(h(6),24)+shiftl(h(7),1),Z'FF')),i8)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| integer(i64) :: bits
|
| bits = 0_i64
|
| bits = ior(h(1), shiftl(h(2), 26))
|
| b(1) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(2) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(3) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(4) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
|
|
| bits = ior(bits, shiftl(h(3), max(0,26+25-32)))
|
| b(5) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(6) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(7) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(4), max(0,51+26-56)))
|
| b(8) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(9) = int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(10)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(5), max(0,77+25-80)))
|
| b(11)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(12)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(13)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(6), max(0,102+26-104)))
|
| b(14)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(15)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(16)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(7), max(0,128+25-128)))
|
| b(17)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(18)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(19)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(8), max(0,153+26-152)))
|
| b(20)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(21)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(22)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(9), max(0,179+25-176)))
|
| b(23)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(24)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(25)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| bits = ior(bits, shiftl(h(10),max(0,204+26-200)))
|
| b(26)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(27)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(28)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(29)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(30)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(31)= int(iand(bits, Z'FF'),i8); bits=shiftr(bits,8)
|
| b(32)= int(iand(bits, Z'FF'),i8)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_frombytes(b, f)
|
| integer(i8), intent(in), dimension(32) :: b
|
| integer(i64), intent(out), dimension(10) :: f
|
| integer(i64) :: w(8)
|
| integer :: i
|
| do i=1,8
|
| w(i) = 0_i64
|
| w(i) = ior(w(i), shiftl(int(iand(b(4*i-3),int(Z'FF',i8)),i64), 0))
|
| w(i) = ior(w(i), shiftl(int(iand(b(4*i-2),int(Z'FF',i8)),i64), 8))
|
| w(i) = ior(w(i), shiftl(int(iand(b(4*i-1),int(Z'FF',i8)),i64),16))
|
| w(i) = ior(w(i), shiftl(int(iand(b(4*i ),int(Z'FF',i8)),i64),24))
|
| end do
|
|
|
| f(1) = iand(w(1), int(Z'3FFFFFF',i64))
|
| f(2) = iand(shiftr(w(1),26), int(Z'1FFFFFF',i64))
|
| f(3) = iand(ior(shiftr(w(1),51), shiftl(w(2),13)), int(Z'3FFFFFF',i64))
|
| f(4) = iand(shiftr(w(2),13), int(Z'1FFFFFF',i64))
|
| f(5) = iand(ior(shiftr(w(2),38), shiftl(w(3),26)), int(Z'3FFFFFF',i64))
|
| f(6) = iand(shiftr(w(3),0), int(Z'1FFFFFF',i64))
|
| f(7) = iand(shiftr(w(3),25), int(Z'3FFFFFF',i64))
|
| f(8) = iand(ior(shiftr(w(3),51), shiftl(w(4),13)), int(Z'1FFFFFF',i64))
|
| f(9) = iand(shiftr(w(4),12), int(Z'3FFFFFF',i64))
|
| f(10) = iand(ior(shiftr(w(4),38), shiftl(w(5),26)), int(Z'1FFFFFF',i64))
|
|
|
| f(10) = iand(f(10), int(Z'7FFFFFFF',i64))
|
| call fe_reduce(f)
|
| end subroutine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| pure subroutine sc_reduce64(h, s)
|
| integer(i8), intent(in), dimension(64) :: h
|
| integer(i8), intent(out), dimension(32) :: s
|
|
|
|
|
|
|
|
|
|
|
|
|
| integer(i64) :: a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11
|
| integer(i64) :: b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11
|
| integer(i64) :: carry, t
|
|
|
|
|
| integer(i64) :: s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12
|
| integer(i8) :: hb(64)
|
| hb = h
|
|
|
| s0 = iand(int(hb(1),i64),Z'FF') + shiftl(iand(int(hb(2),i64),Z'FF'),8) &
|
| + shiftl(iand(int(hb(3),i64),Z'FF'),16) + shiftl(iand(iand(int(hb(4),i64),Z'FF'),Z'1F'),24)
|
| s1 = shiftr(iand(int(hb(4),i64),Z'FF'),5) + shiftl(iand(int(hb(5),i64),Z'FF'),3) &
|
| + shiftl(iand(int(hb(6),i64),Z'FF'),11) + shiftl(iand(iand(int(hb(7),i64),Z'FF'),Z'3F'),19)
|
| s2 = shiftr(iand(int(hb(7),i64),Z'FF'),6) + shiftl(iand(int(hb(8),i64),Z'FF'),2) &
|
| + shiftl(iand(int(hb(9),i64),Z'FF'),10) + shiftl(iand(iand(int(hb(10),i64),Z'FF'),Z'7F'),18)
|
| s3 = shiftr(iand(int(hb(10),i64),Z'FF'),7) + shiftl(iand(int(hb(11),i64),Z'FF'),1) &
|
| + shiftl(iand(int(hb(12),i64),Z'FF'),9) + shiftl(iand(int(hb(13),i64),Z'FF'),17)
|
| s4 = iand(int(hb(14),i64),Z'FF') + shiftl(iand(int(hb(15),i64),Z'FF'),8) &
|
| + shiftl(iand(int(hb(16),i64),Z'FF'),16) + shiftl(iand(iand(int(hb(17),i64),Z'FF'),Z'1F'),24)
|
| s5 = shiftr(iand(int(hb(17),i64),Z'FF'),5) + shiftl(iand(int(hb(18),i64),Z'FF'),3) &
|
| + shiftl(iand(int(hb(19),i64),Z'FF'),11) + shiftl(iand(iand(int(hb(20),i64),Z'FF'),Z'3F'),19)
|
| s6 = shiftr(iand(int(hb(20),i64),Z'FF'),6) + shiftl(iand(int(hb(21),i64),Z'FF'),2) &
|
| + shiftl(iand(int(hb(22),i64),Z'FF'),10) + shiftl(iand(iand(int(hb(23),i64),Z'FF'),Z'7F'),18)
|
| s7 = shiftr(iand(int(hb(23),i64),Z'FF'),7) + shiftl(iand(int(hb(24),i64),Z'FF'),1) &
|
| + shiftl(iand(int(hb(25),i64),Z'FF'),9) + shiftl(iand(int(hb(26),i64),Z'FF'),17)
|
| s8 = iand(int(hb(27),i64),Z'FF') + shiftl(iand(int(hb(28),i64),Z'FF'),8) &
|
| + shiftl(iand(int(hb(29),i64),Z'FF'),16) + shiftl(iand(iand(int(hb(30),i64),Z'FF'),Z'1F'),24)
|
| s9 = shiftr(iand(int(hb(30),i64),Z'FF'),5) + shiftl(iand(int(hb(31),i64),Z'FF'),3) &
|
| + shiftl(iand(int(hb(32),i64),Z'FF'),11) + shiftl(iand(iand(int(hb(33),i64),Z'FF'),Z'3F'),19)
|
| s10 = shiftr(iand(int(hb(33),i64),Z'FF'),6) + shiftl(iand(int(hb(34),i64),Z'FF'),2) &
|
| + shiftl(iand(int(hb(35),i64),Z'FF'),10) + shiftl(iand(iand(int(hb(36),i64),Z'FF'),Z'7F'),18)
|
| s11 = shiftr(iand(int(hb(36),i64),Z'FF'),7) + shiftl(iand(int(hb(37),i64),Z'FF'),1) &
|
| + shiftl(iand(int(hb(38),i64),Z'FF'),9) + shiftl(iand(int(hb(39),i64),Z'FF'),17)
|
| s12 = iand(int(hb(40),i64),Z'FF') + shiftl(iand(int(hb(41),i64),Z'FF'),8) &
|
| + shiftl(iand(int(hb(42),i64),Z'FF'),16) + shiftl(iand(iand(int(hb(43),i64),Z'FF'),Z'1F'),24)
|
|
|
|
|
|
|
|
|
|
|
|
|
| integer(i64), parameter :: MU0=666643_i64, MU1=470296_i64, MU2=654183_i64
|
| integer(i64), parameter :: MU3=-997805_i64, MU4=136657_i64, MU5=-683901_i64
|
| s0 = s0 + MU0*s12; s1 = s1 + MU1*s12; s2 = s2 + MU2*s12
|
| s3 = s3 + MU3*s12; s4 = s4 + MU4*s12; s5 = s5 + MU5*s12; s12 = 0
|
| carry = shiftr(s0,21); s1=s1+carry; s0=iand(s0,int(Z'1FFFFF',i64))
|
| carry = shiftr(s1,21); s2=s2+carry; s1=iand(s1,int(Z'1FFFFF',i64))
|
| carry = shiftr(s2,21); s3=s3+carry; s2=iand(s2,int(Z'1FFFFF',i64))
|
| carry = shiftr(s3,21); s4=s4+carry; s3=iand(s3,int(Z'1FFFFF',i64))
|
| carry = shiftr(s4,21); s5=s5+carry; s4=iand(s4,int(Z'1FFFFF',i64))
|
| carry = shiftr(s5,21); s6=s6+carry; s5=iand(s5,int(Z'1FFFFF',i64))
|
| carry = shiftr(s6,21); s7=s7+carry; s6=iand(s6,int(Z'1FFFFF',i64))
|
| carry = shiftr(s7,21); s8=s8+carry; s7=iand(s7,int(Z'1FFFFF',i64))
|
| carry = shiftr(s8,21); s9=s9+carry; s8=iand(s8,int(Z'1FFFFF',i64))
|
| carry = shiftr(s9,21); s10=s10+carry; s9=iand(s9,int(Z'1FFFFF',i64))
|
| carry = shiftr(s10,21);s11=s11+carry; s10=iand(s10,int(Z'1FFFFF',i64))
|
| carry = shiftr(s11,21);s12=s11; s11=iand(s11,int(Z'1FFFFF',i64))
|
| s0 = s0 + MU0*s12; s1 = s1 + MU1*s12; s2 = s2 + MU2*s12
|
| s3 = s3 + MU3*s12; s4 = s4 + MU4*s12; s5 = s5 + MU5*s12; s12 = 0
|
| carry=shiftr(s0,21); s1=s1+carry; s0=iand(s0,int(Z'1FFFFF',i64))
|
| carry=shiftr(s1,21); s2=s2+carry; s1=iand(s1,int(Z'1FFFFF',i64))
|
| carry=shiftr(s2,21); s3=s3+carry; s2=iand(s2,int(Z'1FFFFF',i64))
|
| carry=shiftr(s3,21); s4=s4+carry; s3=iand(s3,int(Z'1FFFFF',i64))
|
| carry=shiftr(s4,21); s5=s5+carry; s4=iand(s4,int(Z'1FFFFF',i64))
|
| carry=shiftr(s5,21); s6=s6+carry; s5=iand(s5,int(Z'1FFFFF',i64))
|
| carry=shiftr(s6,21); s7=s7+carry; s6=iand(s6,int(Z'1FFFFF',i64))
|
| carry=shiftr(s7,21); s8=s8+carry; s7=iand(s7,int(Z'1FFFFF',i64))
|
| carry=shiftr(s8,21); s9=s9+carry; s8=iand(s8,int(Z'1FFFFF',i64))
|
| carry=shiftr(s9,21); s10=s10+carry; s9=iand(s9,int(Z'1FFFFF',i64))
|
| carry=shiftr(s10,21);s11=s11+carry; s10=iand(s10,int(Z'1FFFFF',i64))
|
|
|
| s(1) =int(iand(s0,Z'FF'),i8)
|
| s(2) =int(iand(shiftr(s0,8),Z'FF'),i8)
|
| s(3) =int(iand(ior(shiftr(s0,16),shiftl(s1,5)),Z'FF'),i8)
|
| s(4) =int(iand(shiftr(s1,3),Z'FF'),i8)
|
| s(5) =int(iand(shiftr(s1,11),Z'FF'),i8)
|
| s(6) =int(iand(ior(shiftr(s1,19),shiftl(s2,2)),Z'FF'),i8)
|
| s(7) =int(iand(shiftr(s2,6),Z'FF'),i8)
|
| s(8) =int(iand(ior(shiftr(s2,14),shiftl(s3,7)),Z'FF'),i8)
|
| s(9) =int(iand(shiftr(s3,1),Z'FF'),i8)
|
| s(10)=int(iand(shiftr(s3,9),Z'FF'),i8)
|
| s(11)=int(iand(ior(shiftr(s3,17),shiftl(s4,4)),Z'FF'),i8)
|
| s(12)=int(iand(shiftr(s4,4),Z'FF'),i8)
|
| s(13)=int(iand(shiftr(s4,12),Z'FF'),i8)
|
| s(14)=int(iand(ior(shiftr(s4,20),shiftl(s5,1)),Z'FF'),i8)
|
| s(15)=int(iand(shiftr(s5,7),Z'FF'),i8)
|
| s(16)=int(iand(ior(shiftr(s5,15),shiftl(s6,6)),Z'FF'),i8)
|
| s(17)=int(iand(shiftr(s6,2),Z'FF'),i8)
|
| s(18)=int(iand(shiftr(s6,10),Z'FF'),i8)
|
| s(19)=int(iand(ior(shiftr(s6,18),shiftl(s7,3)),Z'FF'),i8)
|
| s(20)=int(iand(shiftr(s7,5),Z'FF'),i8)
|
| s(21)=int(iand(shiftr(s7,13),Z'FF'),i8)
|
| s(22)=int(iand(s8,Z'FF'),i8)
|
| s(23)=int(iand(shiftr(s8,8),Z'FF'),i8)
|
| s(24)=int(iand(ior(shiftr(s8,16),shiftl(s9,5)),Z'FF'),i8)
|
| s(25)=int(iand(shiftr(s9,3),Z'FF'),i8)
|
| s(26)=int(iand(shiftr(s9,11),Z'FF'),i8)
|
| s(27)=int(iand(ior(shiftr(s9,19),shiftl(s10,2)),Z'FF'),i8)
|
| s(28)=int(iand(shiftr(s10,6),Z'FF'),i8)
|
| s(29)=int(iand(ior(shiftr(s10,14),shiftl(s11,7)),Z'FF'),i8)
|
| s(30)=int(iand(shiftr(s11,1),Z'FF'),i8)
|
| s(31)=int(iand(shiftr(s11,9),Z'FF'),i8)
|
| s(32)=int(iand(shiftr(s11,17),Z'FF'),i8)
|
| end subroutine
|
|
|
|
|
|
|
| pure subroutine sc_muladd(a, b, c, s)
|
|
|
| integer(i8), intent(in), dimension(32) :: a, b, c
|
| integer(i8), intent(out), dimension(32) :: s
|
| integer(i64) :: a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11
|
| integer(i64) :: b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11
|
| integer(i64) :: c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11
|
| integer(i64) :: s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12
|
| integer(i64) :: s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23
|
| integer(i64) :: carry
|
| integer(i64), parameter :: MASK21 = int(Z'1FFFFF',i64)
|
| integer(i64), parameter :: MU0=666643_i64, MU1=470296_i64, MU2=654183_i64
|
| integer(i64), parameter :: MU3=-997805_i64, MU4=136657_i64, MU5=-683901_i64
|
|
|
| a0 = iand(int(a(1),i64),Z'FF') + shiftl(iand(int(a(2),i64),Z'FF'),8) + shiftl(iand(iand(int(a(3),i64),Z'FF'),Z'1F'),16)
|
| a1 = shiftr(iand(int(a(3),i64),Z'FF'),5) + shiftl(iand(int(a(4),i64),Z'FF'),3) + shiftl(iand(iand(int(a(5),i64),Z'FF'),Z'3F'),11) + shiftl(iand(iand(int(a(6),i64),Z'FF'),Z'3'),19)
|
| a2 = shiftr(iand(int(a(6),i64),Z'FF'),2) + shiftl(iand(int(a(7),i64),Z'FF'),6) + shiftl(iand(iand(int(a(8),i64),Z'FF'),Z'7F'),14) + shiftl(iand(iand(int(a(9),i64),Z'FF'),Z'0'),21)
|
| a3 = shiftr(iand(int(a(9),i64),Z'FF'),0) + shiftl(iand(int(a(10),i64),Z'FF'),8) + shiftl(iand(iand(int(a(11),i64),Z'FF'),Z'1F'),16)
|
| a4 = shiftr(iand(int(a(11),i64),Z'FF'),5) + shiftl(iand(int(a(12),i64),Z'FF'),3) + shiftl(iand(iand(int(a(13),i64),Z'FF'),Z'3F'),11)
|
| a5 = shiftr(iand(int(a(13),i64),Z'FF'),6) + shiftl(iand(int(a(14),i64),Z'FF'),2) + shiftl(iand(iand(int(a(15),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(a(16),i64),Z'FF'),Z'3'),18)
|
| a6 = shiftr(iand(int(a(16),i64),Z'FF'),2) + shiftl(iand(int(a(17),i64),Z'FF'),6) + shiftl(iand(iand(int(a(18),i64),Z'FF'),Z'7F'),14)
|
| a7 = shiftr(iand(int(a(18),i64),Z'FF'),7) + shiftl(iand(int(a(19),i64),Z'FF'),1) + shiftl(iand(iand(int(a(20),i64),Z'FF'),Z'FF'),9) + shiftl(iand(iand(int(a(21),i64),Z'FF'),Z'7'),17)
|
| a8 = shiftr(iand(int(a(21),i64),Z'FF'),3) + shiftl(iand(int(a(22),i64),Z'FF'),5) + shiftl(iand(iand(int(a(23),i64),Z'FF'),Z'3F'),13)
|
| a9 = shiftr(iand(int(a(23),i64),Z'FF'),6) + shiftl(iand(int(a(24),i64),Z'FF'),2) + shiftl(iand(iand(int(a(25),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(a(26),i64),Z'FF'),Z'1'),18)
|
| a10 = shiftr(iand(int(a(26),i64),Z'FF'),1) + shiftl(iand(int(a(27),i64),Z'FF'),7) + shiftl(iand(iand(int(a(28),i64),Z'FF'),Z'FF'),15)
|
| a11 = shiftr(iand(int(a(28),i64),Z'FF'),6) + shiftl(iand(int(a(29),i64),Z'FF'),2) + shiftl(iand(iand(int(a(30),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(a(31),i64),Z'FF'),Z'7'),18)
|
|
|
| b0 = iand(int(b(1),i64),Z'FF') + shiftl(iand(int(b(2),i64),Z'FF'),8) + shiftl(iand(iand(int(b(3),i64),Z'FF'),Z'1F'),16)
|
| b1 = shiftr(iand(int(b(3),i64),Z'FF'),5) + shiftl(iand(int(b(4),i64),Z'FF'),3) + shiftl(iand(iand(int(b(5),i64),Z'FF'),Z'3F'),11) + shiftl(iand(iand(int(b(6),i64),Z'FF'),Z'3'),19)
|
| b2 = shiftr(iand(int(b(6),i64),Z'FF'),2) + shiftl(iand(int(b(7),i64),Z'FF'),6) + shiftl(iand(iand(int(b(8),i64),Z'FF'),Z'7F'),14)
|
| b3 = iand(int(b(9),i64),Z'FF') + shiftl(iand(int(b(10),i64),Z'FF'),8) + shiftl(iand(iand(int(b(11),i64),Z'FF'),Z'1F'),16)
|
| b4 = shiftr(iand(int(b(11),i64),Z'FF'),5) + shiftl(iand(int(b(12),i64),Z'FF'),3) + shiftl(iand(iand(int(b(13),i64),Z'FF'),Z'3F'),11)
|
| b5 = shiftr(iand(int(b(13),i64),Z'FF'),6) + shiftl(iand(int(b(14),i64),Z'FF'),2) + shiftl(iand(iand(int(b(15),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(b(16),i64),Z'FF'),Z'3'),18)
|
| b6 = shiftr(iand(int(b(16),i64),Z'FF'),2) + shiftl(iand(int(b(17),i64),Z'FF'),6) + shiftl(iand(iand(int(b(18),i64),Z'FF'),Z'7F'),14)
|
| b7 = shiftr(iand(int(b(18),i64),Z'FF'),7) + shiftl(iand(int(b(19),i64),Z'FF'),1) + shiftl(iand(iand(int(b(20),i64),Z'FF'),Z'FF'),9) + shiftl(iand(iand(int(b(21),i64),Z'FF'),Z'7'),17)
|
| b8 = shiftr(iand(int(b(21),i64),Z'FF'),3) + shiftl(iand(int(b(22),i64),Z'FF'),5) + shiftl(iand(iand(int(b(23),i64),Z'FF'),Z'3F'),13)
|
| b9 = shiftr(iand(int(b(23),i64),Z'FF'),6) + shiftl(iand(int(b(24),i64),Z'FF'),2) + shiftl(iand(iand(int(b(25),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(b(26),i64),Z'FF'),Z'1'),18)
|
| b10 = shiftr(iand(int(b(26),i64),Z'FF'),1) + shiftl(iand(int(b(27),i64),Z'FF'),7) + shiftl(iand(iand(int(b(28),i64),Z'FF'),Z'FF'),15)
|
| b11 = shiftr(iand(int(b(28),i64),Z'FF'),6) + shiftl(iand(int(b(29),i64),Z'FF'),2) + shiftl(iand(iand(int(b(30),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(b(31),i64),Z'FF'),Z'7'),18)
|
|
|
| c0 = iand(int(c(1),i64),Z'FF') + shiftl(iand(int(c(2),i64),Z'FF'),8) + shiftl(iand(iand(int(c(3),i64),Z'FF'),Z'1F'),16)
|
| c1 = shiftr(iand(int(c(3),i64),Z'FF'),5) + shiftl(iand(int(c(4),i64),Z'FF'),3) + shiftl(iand(iand(int(c(5),i64),Z'FF'),Z'3F'),11) + shiftl(iand(iand(int(c(6),i64),Z'FF'),Z'3'),19)
|
| c2 = shiftr(iand(int(c(6),i64),Z'FF'),2) + shiftl(iand(int(c(7),i64),Z'FF'),6) + shiftl(iand(iand(int(c(8),i64),Z'FF'),Z'7F'),14)
|
| c3 = iand(int(c(9),i64),Z'FF') + shiftl(iand(int(c(10),i64),Z'FF'),8) + shiftl(iand(iand(int(c(11),i64),Z'FF'),Z'1F'),16)
|
| c4 = shiftr(iand(int(c(11),i64),Z'FF'),5) + shiftl(iand(int(c(12),i64),Z'FF'),3) + shiftl(iand(iand(int(c(13),i64),Z'FF'),Z'3F'),11)
|
| c5 = shiftr(iand(int(c(13),i64),Z'FF'),6) + shiftl(iand(int(c(14),i64),Z'FF'),2) + shiftl(iand(iand(int(c(15),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(c(16),i64),Z'FF'),Z'3'),18)
|
| c6 = shiftr(iand(int(c(16),i64),Z'FF'),2) + shiftl(iand(int(c(17),i64),Z'FF'),6) + shiftl(iand(iand(int(c(18),i64),Z'FF'),Z'7F'),14)
|
| c7 = shiftr(iand(int(c(18),i64),Z'FF'),7) + shiftl(iand(int(c(19),i64),Z'FF'),1) + shiftl(iand(iand(int(c(20),i64),Z'FF'),Z'FF'),9) + shiftl(iand(iand(int(c(21),i64),Z'FF'),Z'7'),17)
|
| c8 = shiftr(iand(int(c(21),i64),Z'FF'),3) + shiftl(iand(int(c(22),i64),Z'FF'),5) + shiftl(iand(iand(int(c(23),i64),Z'FF'),Z'3F'),13)
|
| c9 = shiftr(iand(int(c(23),i64),Z'FF'),6) + shiftl(iand(int(c(24),i64),Z'FF'),2) + shiftl(iand(iand(int(c(25),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(c(26),i64),Z'FF'),Z'1'),18)
|
| c10 = shiftr(iand(int(c(26),i64),Z'FF'),1) + shiftl(iand(int(c(27),i64),Z'FF'),7) + shiftl(iand(iand(int(c(28),i64),Z'FF'),Z'FF'),15)
|
| c11 = shiftr(iand(int(c(28),i64),Z'FF'),6) + shiftl(iand(int(c(29),i64),Z'FF'),2) + shiftl(iand(iand(int(c(30),i64),Z'FF'),Z'7F'),10) + shiftl(iand(iand(int(c(31),i64),Z'FF'),Z'7'),18)
|
|
|
| s0 =c0+a0*b0
|
| s1 =c1+a0*b1+a1*b0
|
| s2 =c2+a0*b2+a1*b1+a2*b0
|
| s3 =c3+a0*b3+a1*b2+a2*b1+a3*b0
|
| s4 =c4+a0*b4+a1*b3+a2*b2+a3*b1+a4*b0
|
| s5 =c5+a0*b5+a1*b4+a2*b3+a3*b2+a4*b1+a5*b0
|
| s6 =c6+a0*b6+a1*b5+a2*b4+a3*b3+a4*b2+a5*b1+a6*b0
|
| s7 =c7+a0*b7+a1*b6+a2*b5+a3*b4+a4*b3+a5*b2+a6*b1+a7*b0
|
| s8 =c8+a0*b8+a1*b7+a2*b6+a3*b5+a4*b4+a5*b3+a6*b2+a7*b1+a8*b0
|
| s9 =c9+a0*b9+a1*b8+a2*b7+a3*b6+a4*b5+a5*b4+a6*b3+a7*b2+a8*b1+a9*b0
|
| s10=c10+a0*b10+a1*b9+a2*b8+a3*b7+a4*b6+a5*b5+a6*b4+a7*b3+a8*b2+a9*b1+a10*b0
|
| s11=c11+a0*b11+a1*b10+a2*b9+a3*b8+a4*b7+a5*b6+a6*b5+a7*b4+a8*b3+a9*b2+a10*b1+a11*b0
|
| s12= a1*b11+a2*b10+a3*b9+a4*b8+a5*b7+a6*b6+a7*b5+a8*b4+a9*b3+a10*b2+a11*b1
|
| s13= a2*b11+a3*b10+a4*b9+a5*b8+a6*b7+a7*b6+a8*b5+a9*b4+a10*b3+a11*b2
|
| s14= a3*b11+a4*b10+a5*b9+a6*b8+a7*b7+a8*b6+a9*b5+a10*b4+a11*b3
|
| s15= a4*b11+a5*b10+a6*b9+a7*b8+a8*b7+a9*b6+a10*b5+a11*b4
|
| s16= a5*b11+a6*b10+a7*b9+a8*b8+a9*b7+a10*b6+a11*b5
|
| s17= a6*b11+a7*b10+a8*b9+a9*b8+a10*b7+a11*b6
|
| s18= a7*b11+a8*b10+a9*b9+a10*b8+a11*b7
|
| s19= a8*b11+a9*b10+a10*b9+a11*b8
|
| s20= a9*b11+a10*b10+a11*b9
|
| s21= a10*b11+a11*b10
|
| s22= a11*b11
|
| s23=0
|
|
|
| carry=shiftr(s0,21); s1=s1+carry; s0=iand(s0,MASK21)
|
| carry=shiftr(s1,21); s2=s2+carry; s1=iand(s1,MASK21)
|
| carry=shiftr(s2,21); s3=s3+carry; s2=iand(s2,MASK21)
|
| carry=shiftr(s3,21); s4=s4+carry; s3=iand(s3,MASK21)
|
| carry=shiftr(s4,21); s5=s5+carry; s4=iand(s4,MASK21)
|
| carry=shiftr(s5,21); s6=s6+carry; s5=iand(s5,MASK21)
|
| carry=shiftr(s6,21); s7=s7+carry; s6=iand(s6,MASK21)
|
| carry=shiftr(s7,21); s8=s8+carry; s7=iand(s7,MASK21)
|
| carry=shiftr(s8,21); s9=s9+carry; s8=iand(s8,MASK21)
|
| carry=shiftr(s9,21); s10=s10+carry; s9=iand(s9,MASK21)
|
| carry=shiftr(s10,21);s11=s11+carry; s10=iand(s10,MASK21)
|
| carry=shiftr(s11,21);s12=s12+carry; s11=iand(s11,MASK21)
|
| carry=shiftr(s12,21);s13=s13+carry; s12=iand(s12,MASK21)
|
| carry=shiftr(s13,21);s14=s14+carry; s13=iand(s13,MASK21)
|
| carry=shiftr(s14,21);s15=s15+carry; s14=iand(s14,MASK21)
|
| carry=shiftr(s15,21);s16=s16+carry; s15=iand(s15,MASK21)
|
| carry=shiftr(s16,21);s17=s17+carry; s16=iand(s16,MASK21)
|
| carry=shiftr(s17,21);s18=s18+carry; s17=iand(s17,MASK21)
|
| carry=shiftr(s18,21);s19=s19+carry; s18=iand(s18,MASK21)
|
| carry=shiftr(s19,21);s20=s20+carry; s19=iand(s19,MASK21)
|
| carry=shiftr(s20,21);s21=s21+carry; s20=iand(s20,MASK21)
|
| carry=shiftr(s21,21);s22=s22+carry; s21=iand(s21,MASK21)
|
| carry=shiftr(s22,21);s23=s23+carry; s22=iand(s22,MASK21)
|
|
|
| s11=s11+s23*MU0; s12=s12+s23*MU1; s13=s13+s23*MU2
|
| s14=s14+s23*MU3; s15=s15+s23*MU4; s16=s16+s23*MU5; s23=0
|
| s10=s10+s22*MU0; s11=s11+s22*MU1; s12=s12+s22*MU2
|
| s13=s13+s22*MU3; s14=s14+s22*MU4; s15=s15+s22*MU5; s22=0
|
| s9 =s9 +s21*MU0; s10=s10+s21*MU1; s11=s11+s21*MU2
|
| s12=s12+s21*MU3; s13=s13+s21*MU4; s14=s14+s21*MU5; s21=0
|
| s8 =s8 +s20*MU0; s9 =s9 +s20*MU1; s10=s10+s20*MU2
|
| s11=s11+s20*MU3; s12=s12+s20*MU4; s13=s13+s20*MU5; s20=0
|
| s7 =s7 +s19*MU0; s8 =s8 +s19*MU1; s9 =s9 +s19*MU2
|
| s10=s10+s19*MU3; s11=s11+s19*MU4; s12=s12+s19*MU5; s19=0
|
| s6 =s6 +s18*MU0; s7 =s7 +s18*MU1; s8 =s8 +s18*MU2
|
| s9 =s9 +s18*MU3; s10=s10+s18*MU4; s11=s11+s18*MU5; s18=0
|
| carry=shiftr(s6,21);s7=s7+carry; s6=iand(s6,MASK21)
|
| carry=shiftr(s7,21);s8=s8+carry; s7=iand(s7,MASK21)
|
| carry=shiftr(s8,21);s9=s9+carry; s8=iand(s8,MASK21)
|
| carry=shiftr(s9,21);s10=s10+carry; s9=iand(s9,MASK21)
|
| carry=shiftr(s10,21);s11=s11+carry; s10=iand(s10,MASK21)
|
| carry=shiftr(s11,21);s12=s12+carry; s11=iand(s11,MASK21)
|
| s0=s0+s12*MU0; s1=s1+s12*MU1; s2=s2+s12*MU2
|
| s3=s3+s12*MU3; s4=s4+s12*MU4; s5=s5+s12*MU5; s12=0
|
| carry=shiftr(s0,21);s1=s1+carry; s0=iand(s0,MASK21)
|
| carry=shiftr(s1,21);s2=s2+carry; s1=iand(s1,MASK21)
|
| carry=shiftr(s2,21);s3=s3+carry; s2=iand(s2,MASK21)
|
| carry=shiftr(s3,21);s4=s4+carry; s3=iand(s3,MASK21)
|
| carry=shiftr(s4,21);s5=s5+carry; s4=iand(s4,MASK21)
|
| carry=shiftr(s5,21);s6=s6+carry; s5=iand(s5,MASK21)
|
| carry=shiftr(s6,21);s7=s7+carry; s6=iand(s6,MASK21)
|
| carry=shiftr(s7,21);s8=s8+carry; s7=iand(s7,MASK21)
|
| carry=shiftr(s8,21);s9=s9+carry; s8=iand(s8,MASK21)
|
| carry=shiftr(s9,21);s10=s10+carry; s9=iand(s9,MASK21)
|
| carry=shiftr(s10,21);s11=s11+carry; s10=iand(s10,MASK21)
|
|
|
| s(1) =int(iand(s0,Z'FF'),i8)
|
| s(2) =int(iand(shiftr(s0,8),Z'FF'),i8)
|
| s(3) =int(iand(ior(shiftr(s0,16),shiftl(s1,5)),Z'FF'),i8)
|
| s(4) =int(iand(shiftr(s1,3),Z'FF'),i8)
|
| s(5) =int(iand(shiftr(s1,11),Z'FF'),i8)
|
| s(6) =int(iand(ior(shiftr(s1,19),shiftl(s2,2)),Z'FF'),i8)
|
| s(7) =int(iand(shiftr(s2,6),Z'FF'),i8)
|
| s(8) =int(iand(ior(shiftr(s2,14),shiftl(s3,7)),Z'FF'),i8)
|
| s(9) =int(iand(shiftr(s3,1),Z'FF'),i8)
|
| s(10)=int(iand(shiftr(s3,9),Z'FF'),i8)
|
| s(11)=int(iand(ior(shiftr(s3,17),shiftl(s4,4)),Z'FF'),i8)
|
| s(12)=int(iand(shiftr(s4,4),Z'FF'),i8)
|
| s(13)=int(iand(shiftr(s4,12),Z'FF'),i8)
|
| s(14)=int(iand(ior(shiftr(s4,20),shiftl(s5,1)),Z'FF'),i8)
|
| s(15)=int(iand(shiftr(s5,7),Z'FF'),i8)
|
| s(16)=int(iand(ior(shiftr(s5,15),shiftl(s6,6)),Z'FF'),i8)
|
| s(17)=int(iand(shiftr(s6,2),Z'FF'),i8)
|
| s(18)=int(iand(shiftr(s6,10),Z'FF'),i8)
|
| s(19)=int(iand(ior(shiftr(s6,18),shiftl(s7,3)),Z'FF'),i8)
|
| s(20)=int(iand(shiftr(s7,5),Z'FF'),i8)
|
| s(21)=int(iand(shiftr(s7,13),Z'FF'),i8)
|
| s(22)=int(iand(s8,Z'FF'),i8)
|
| s(23)=int(iand(shiftr(s8,8),Z'FF'),i8)
|
| s(24)=int(iand(ior(shiftr(s8,16),shiftl(s9,5)),Z'FF'),i8)
|
| s(25)=int(iand(shiftr(s9,3),Z'FF'),i8)
|
| s(26)=int(iand(shiftr(s9,11),Z'FF'),i8)
|
| s(27)=int(iand(ior(shiftr(s9,19),shiftl(s10,2)),Z'FF'),i8)
|
| s(28)=int(iand(shiftr(s10,6),Z'FF'),i8)
|
| s(29)=int(iand(ior(shiftr(s10,14),shiftl(s11,7)),Z'FF'),i8)
|
| s(30)=int(iand(shiftr(s11,1),Z'FF'),i8)
|
| s(31)=int(iand(shiftr(s11,9),Z'FF'),i8)
|
| s(32)=int(iand(shiftr(s11,17),Z'FF'),i8)
|
| end subroutine
|
|
|
|
|
|
|
|
|
|
|
|
|
| pure subroutine ge_d(d)
|
| integer(i64), intent(out), dimension(10) :: d
|
|
|
|
|
| d = [ -10913610_i64, 13857413_i64, -15372611_i64, 10608986_i64, &
|
| 12376523_i64, -12664939_i64, 10701287_i64, -12232133_i64, &
|
| -9232152_i64, 12480880_i64 ]
|
| end subroutine
|
|
|
|
|
| pure subroutine ge_2d(d2)
|
| integer(i64), intent(out), dimension(10) :: d2
|
| integer(i64) :: d(10)
|
| call ge_d(d)
|
| d2 = 2*d
|
| call fe_reduce(d2)
|
| end subroutine
|
|
|
|
|
| pure subroutine ge_zero(x,y,z,t)
|
| integer(i64), intent(out), dimension(10) :: x,y,z,t
|
| x=0; y=0; z=0; t=0
|
| y(1)=1; z(1)=1
|
| end subroutine
|
|
|
|
|
|
|
|
|
| pure subroutine ge_add(x1,y1,z1,t1, x2,y2,z2,t2, x3,y3,z3,t3)
|
| integer(i64), intent(in), dimension(10) :: x1,y1,z1,t1,x2,y2,z2,t2
|
| integer(i64), intent(out), dimension(10) :: x3,y3,z3,t3
|
| integer(i64) :: A(10),B(10),C(10),D(10),E(10),F(10),G(10),H(10),d2(10)
|
| call ge_2d(d2)
|
| call fe_mul(x1,x2, A)
|
| call fe_mul(y1,y2, B)
|
| call fe_mul(t1,t2, C)
|
| call fe_mul(C, d2, C)
|
| call fe_mul(z1,z2, D)
|
| call fe_add(D, D, D)
|
| call fe_add(x1,y1, E)
|
| call fe_add(x2,y2, F)
|
| call fe_mul(E, F, E)
|
| call fe_sub(E, A, E)
|
| call fe_sub(E, B, E)
|
| call fe_sub(D, C, F)
|
| call fe_add(D, C, G)
|
| call fe_add(B, A, H)
|
| call fe_sub(B, A, H)
|
| call fe_mul(E, F, x3)
|
| call fe_mul(H, G, y3)
|
| call fe_mul(G, F, z3)
|
| call fe_mul(E, H, t3)
|
| end subroutine
|
|
|
|
|
|
|
| pure subroutine ge_double(x1,y1,z1,t1, x3,y3,z3,t3)
|
| integer(i64), intent(in), dimension(10) :: x1,y1,z1,t1
|
| integer(i64), intent(out), dimension(10) :: x3,y3,z3,t3
|
| integer(i64) :: A(10),B(10),C(10),H(10),E(10),G(10),F(10)
|
| call fe_sq(x1, A)
|
| call fe_sq(y1, B)
|
| call fe_sq(z1, C)
|
| call fe_add(C, C, C)
|
| call fe_add(A, B, H)
|
| call fe_add(x1,y1, E)
|
| call fe_sq(E, E)
|
| call fe_sub(H, E, E)
|
|
|
|
|
| call fe_sub(E, H, E)
|
| call fe_sub(A, B, G)
|
| call fe_add(C, G, F)
|
| call fe_mul(E, F, x3)
|
| call fe_mul(G, H, y3)
|
| call fe_mul(F, G, z3)
|
|
|
|
|
| call fe_sub(A, B, G)
|
| call fe_add(A, B, H)
|
| call fe_sub(B, A, H)
|
| call fe_mul(E, F, x3)
|
| call fe_mul(H, G, y3)
|
| call fe_mul(G, F, z3)
|
| call fe_mul(E, H, t3)
|
| end subroutine
|
|
|
|
|
| pure subroutine fe_cswap(a, b, swap)
|
| integer(i64), intent(inout), dimension(10) :: a, b
|
| integer, intent(in) :: swap
|
| integer(i64) :: mask, t(10), i
|
| mask = -int(swap, i64)
|
| do i=1,10
|
| t(i) = mask .and. ieor(a(i), b(i))
|
| a(i) = ieor(a(i), t(i))
|
| b(i) = ieor(b(i), t(i))
|
| end do
|
| end subroutine
|
|
|
|
|
|
|
| pure subroutine ge_scalarmult(s_bytes, px,py,pz,pt, rx,ry,rz,rt)
|
| integer(i8), intent(in), dimension(32) :: s_bytes
|
| integer(i64), intent(in), dimension(10) :: px,py,pz,pt
|
| integer(i64), intent(out), dimension(10) :: rx,ry,rz,rt
|
| integer(i64) :: r0x(10),r0y(10),r0z(10),r0t(10)
|
| integer(i64) :: r1x(10),r1y(10),r1z(10),r1t(10)
|
| integer(i64) :: tx(10),ty(10),tz(10),tt(10)
|
| integer :: i, j, bit
|
| integer(i64) :: byte_val
|
| call ge_zero(r0x,r0y,r0z,r0t)
|
| r1x=px; r1y=py; r1z=pz; r1t=pt
|
|
|
| do i = 32, 1, -1
|
| byte_val = iand(int(s_bytes(i),i64), Z'FF')
|
| do j = 7, 0, -1
|
| bit = int(iand(shiftr(byte_val, j), 1_i64))
|
|
|
| call fe_cswap(r0x,r1x,bit)
|
| call fe_cswap(r0y,r1y,bit)
|
| call fe_cswap(r0z,r1z,bit)
|
| call fe_cswap(r0t,r1t,bit)
|
|
|
| call ge_add(r0x,r0y,r0z,r0t, r1x,r1y,r1z,r1t, tx,ty,tz,tt)
|
| r1x=tx; r1y=ty; r1z=tz; r1t=tt
|
|
|
| call ge_double(r0x,r0y,r0z,r0t, tx,ty,tz,tt)
|
| r0x=tx; r0y=ty; r0z=tz; r0t=tt
|
|
|
| call fe_cswap(r0x,r1x,bit)
|
| call fe_cswap(r0y,r1y,bit)
|
| call fe_cswap(r0z,r1z,bit)
|
| call fe_cswap(r0t,r1t,bit)
|
| end do
|
| end do
|
| rx=r0x; ry=r0y; rz=r0z; rt=r0t
|
| end subroutine
|
|
|
|
|
| pure subroutine ge_basepoint(bx,by,bz,bt)
|
| integer(i64), intent(out), dimension(10) :: bx,by,bz,bt
|
|
|
|
|
|
|
|
|
| bx = [ -14297830_i64, -7645148_i64, 16109834_i64, -6494926_i64, &
|
| 1680036_i64, 12345067_i64, -5765007_i64, 13725928_i64, &
|
| -5792619_i64, 3645073_i64 ]
|
| by = [ -26843541_i64, 16110573_i64, -26843546_i64, 15409067_i64, &
|
| -26843541_i64, 15078149_i64, -26843541_i64, 14388135_i64, &
|
| -26843541_i64, 13415012_i64 ]
|
| bz(1)=1; bz(2:10)=0
|
| call fe_mul(bx,by,bt)
|
| end subroutine
|
|
|
|
|
|
|
| pure subroutine sov_ed25519_clamp_and_decode(b, s)
|
| integer(i8), intent(in), dimension(32) :: b
|
| integer(i64), intent(out), dimension(10) :: s
|
| integer(i8) :: bc(32)
|
| bc = b
|
| bc(1) = iand(bc(1), int(Z'F8',i8))
|
| bc(32)= ior(iand(bc(32),int(Z'7F',i8)), int(Z'40',i8))
|
| call fe_frombytes(bc, s)
|
| end subroutine
|
|
|
| pure subroutine sov_ed25519_scalar_from_bytes(b, s)
|
| integer(i8), intent(in), dimension(32) :: b
|
| integer(i64), intent(out), dimension(10) :: s
|
| call fe_frombytes(b, s)
|
| end subroutine
|
|
|
| pure subroutine sov_ed25519_scalar_to_bytes(s, b)
|
| integer(i64), intent(in), dimension(10) :: s
|
| integer(i8), intent(out), dimension(32) :: b
|
| call fe_tobytes(s, b)
|
| end subroutine
|
|
|
| pure function sov_ed25519_scalar_valid(s) result(ok)
|
| integer(i64), intent(in), dimension(10) :: s
|
| logical :: ok
|
|
|
| ok = any(s /= 0_i64)
|
| end function
|
|
|
|
|
| pure subroutine sov_ed25519_reduce_scalar(h, s)
|
| integer(i8), intent(in), dimension(64) :: h
|
| integer(i64), intent(out), dimension(10) :: s
|
| integer(i8) :: out32(32)
|
| call sc_reduce64(h, out32)
|
| call fe_frombytes(out32, s)
|
| end subroutine
|
|
|
|
|
|
|
| pure subroutine sov_ed25519_scalar_mul(a, b, res)
|
| integer(i64), intent(in), dimension(10) :: a, b
|
| integer(i64), intent(out), dimension(10) :: res
|
| integer(i8) :: ab(32), bb(32), zero(32), out(32)
|
| zero = 0_i8
|
| call fe_tobytes(a, ab)
|
| call fe_tobytes(b, bb)
|
| call sc_muladd(ab, bb, zero, out)
|
| call fe_frombytes(out, res)
|
| end subroutine
|
|
|
|
|
| pure subroutine sov_ed25519_scalar_add_mod_l(a, b, res)
|
| integer(i64), intent(in), dimension(10) :: a, b
|
| integer(i64), intent(inout), dimension(10) :: res
|
|
|
| integer(i8) :: ab(32), bb(32), one32(32), out(32)
|
| one32 = 0_i8; one32(1) = 1_i8
|
| call fe_tobytes(a, ab)
|
| call fe_tobytes(b, bb)
|
| call sc_muladd(one32, ab, bb, out)
|
| call fe_frombytes(out, res)
|
| end subroutine
|
|
|
|
|
| pure subroutine sov_ed25519_scalar_mul_base(s, x,y,z,t)
|
| integer(i64), intent(in), dimension(10) :: s
|
| integer(i64), intent(out), dimension(10) :: x,y,z,t
|
| integer(i64) :: bx(10),by(10),bz(10),bt(10)
|
| integer(i8) :: sb(32)
|
| call ge_basepoint(bx,by,bz,bt)
|
| call fe_tobytes(s, sb)
|
| call ge_scalarmult(sb, bx,by,bz,bt, x,y,z,t)
|
| end subroutine
|
|
|
|
|
| pure subroutine sov_ed25519_scalar_mul_point(s, x1,y1,z1,t1, x2,y2,z2,t2)
|
| integer(i64), intent(in), dimension(10) :: s,x1,y1,z1,t1
|
| integer(i64), intent(inout), dimension(10) :: x2,y2,z2,t2
|
| integer(i64) :: rx(10),ry(10),rz(10),rt(10)
|
| integer(i8) :: sb(32)
|
| call fe_tobytes(s, sb)
|
| call ge_scalarmult(sb, x1,y1,z1,t1, rx,ry,rz,rt)
|
| call ge_add(x2,y2,z2,t2, rx,ry,rz,rt, x2,y2,z2,t2)
|
| end subroutine
|
|
|
|
|
| pure subroutine sov_ed25519_point_add(x1,y1,z1,t1, x2,y2,z2,t2, x3,y3,z3,t3)
|
| integer(i64), intent(in), dimension(10) :: x1,y1,z1,t1,x2,y2,z2,t2
|
| integer(i64), intent(out), dimension(10) :: x3,y3,z3,t3
|
| call ge_add(x1,y1,z1,t1, x2,y2,z2,t2, x3,y3,z3,t3)
|
| end subroutine
|
|
|
|
|
| pure subroutine sov_ed25519_point_negate(x,y,z,t)
|
| integer(i64), intent(inout), dimension(10) :: x,y,z,t
|
| integer(i64) :: nx(10), nt(10)
|
| integer(i64), parameter :: ZERO(10) = 0_i64
|
| call fe_sub(ZERO, x, nx)
|
| call fe_sub(ZERO, t, nt)
|
| x = nx; t = nt
|
| end subroutine
|
|
|
|
|
| pure subroutine sov_ed25519_encode_point(x,y,z,t, b)
|
| integer(i64), intent(in), dimension(10) :: x,y,z,t
|
| integer(i8), intent(out), dimension(32) :: b
|
| integer(i64) :: recip(10), xp(10), yp(10), zx(10)
|
| call fe_inv(z, recip)
|
| call fe_mul(x, recip, xp)
|
| call fe_mul(y, recip, yp)
|
| call fe_tobytes(yp, b)
|
|
|
| integer(i64) :: xb(10)
|
| integer(i8) :: xbytes(32)
|
| call fe_tobytes(xp, xbytes)
|
| b(32) = ior(b(32), shiftl(iand(xbytes(1), 1_i8), 7))
|
| end subroutine
|
|
|
|
|
| pure function sov_ed25519_decode_point(b, x,y,z,t) result(ok)
|
| integer(i8), intent(in), dimension(32) :: b
|
| integer(i64), intent(out), dimension(10) :: x,y,z,t
|
| logical :: ok
|
| integer(i8) :: yb(32)
|
| integer(i64) :: y_fe(10), y2(10), u(10), v(10), v3(10), v7(10)
|
| integer(i64) :: x_candidate(10), check(10), d(10), one(10), tmp(10)
|
| integer :: sign_bit
|
| yb = b; sign_bit = int(iand(shiftr(int(b(32),i64),7), 1_i64))
|
| yb(32) = iand(yb(32), int(Z'7F',i8))
|
| call fe_frombytes(yb, y_fe)
|
|
|
| call fe_sq(y_fe, y2)
|
| call ge_d(d)
|
| one = 0_i64; one(1) = 1_i64
|
| call fe_mul(d, y2, u)
|
| call fe_add(u, one, v)
|
| call fe_sub(y2, one, u)
|
|
|
| call fe_sq(v, v3)
|
| call fe_mul(v3, v, v3)
|
| call fe_sq(v3, v7)
|
| call fe_mul(v7, v, v7)
|
| call fe_mul(u, v7, tmp)
|
|
|
| call fe_sq_n(tmp,1, x)
|
|
|
| call fe_sq(tmp, x)
|
| call fe_mul(tmp, x, x)
|
| call fe_sq_n(x,2, x)
|
| call fe_mul(tmp, x, x)
|
| call fe_sq_n(x,1, x)
|
| call fe_mul(tmp, x, x)
|
| call fe_sq_n(x,5, tmp)
|
| call fe_mul(x,tmp, x)
|
| call fe_sq_n(x,10, tmp)
|
| call fe_mul(x,tmp, x)
|
| call fe_sq_n(x,20, tmp)
|
| call fe_mul(x,tmp, tmp)
|
| call fe_sq_n(tmp,10,tmp)
|
| call fe_mul(x,tmp, x)
|
| call fe_sq_n(x,50, tmp)
|
| call fe_mul(x,tmp, tmp)
|
| call fe_sq_n(tmp,100,tmp)
|
| call fe_mul(x,tmp, tmp)
|
| call fe_sq_n(tmp,50, tmp)
|
| call fe_mul(x,tmp, x)
|
| call fe_sq_n(x,2, x)
|
| call fe_mul(u, v7, tmp)
|
| call fe_mul(tmp,x, x)
|
|
|
| call fe_mul(u, v3, x_candidate)
|
| call fe_mul(x_candidate, x, x_candidate)
|
|
|
| call fe_sq(x_candidate, check)
|
| call fe_mul(v, check, check)
|
| call fe_sub(check, u, check)
|
| call fe_reduce(check)
|
|
|
| integer(i64), parameter :: NEG1(10) = &
|
| [ int(Z'3FFFFEC',i64), int(Z'1FFFFFF',i64), int(Z'3FFFFFF',i64), &
|
| int(Z'1FFFFFF',i64), int(Z'3FFFFFF',i64), int(Z'1FFFFFF',i64), &
|
| int(Z'3FFFFFF',i64), int(Z'1FFFFFF',i64), int(Z'3FFFFFF',i64), &
|
| int(Z'1FFFFFF',i64) ]
|
| if (all(check == 0_i64)) then
|
| ok = .true.
|
| else if (all(check == NEG1)) then
|
|
|
| integer(i64), parameter :: SQRT_M1(10) = &
|
| [ -32595792_i64, -7943725_i64, 9377950_i64, 3500415_i64, &
|
| 12389472_i64, -272473_i64, -25146209_i64, -2005654_i64, &
|
| 326686_i64, 11406482_i64 ]
|
| call fe_mul(x_candidate, SQRT_M1, x_candidate)
|
| ok = .true.
|
| else
|
| ok = .false.
|
| x = 0_i64; y = 0_i64; z = 0_i64; t = 0_i64
|
| return
|
| end if
|
|
|
| integer(i64) :: xbytes_check(10)
|
| integer(i8) :: xb(32)
|
| call fe_tobytes(x_candidate, xb)
|
| if (int(iand(int(xb(1),i64), 1_i64)) /= sign_bit) then
|
| call fe_sub(0_i64*x_candidate, x_candidate, x_candidate)
|
| integer(i64), parameter :: ZERO(10) = 0_i64
|
| call fe_sub(ZERO, x_candidate, x_candidate)
|
| end if
|
| x = x_candidate; y = y_fe
|
| z(1) = 1_i64; z(2:10) = 0_i64
|
| call fe_mul(x, y, t)
|
| ok = .true.
|
| end function
|
|
|
|
|
|
|
|
|
| subroutine sov_fault(code)
|
| integer, intent(in) :: code
|
| write(error_unit,'(A,I0)') "SOV_FAULT: ", code
|
| error stop
|
| end subroutine
|
|
|
| end module sov_monster_kernel
|
|
|