// Copyright 2022 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.

//go:build amd64 || arm64

package nistec

import 

// Montgomery multiplication modulo org(G). Sets res = in1 * in2 * R⁻¹.
//
//go:noescape
func p256OrdMul(, ,  *p256OrdElement)

// Montgomery square modulo org(G), repeated n times (n >= 1).
//
//go:noescape
func p256OrdSqr(,  *p256OrdElement,  int)

func ( []byte) ([]byte, error) {
	if len() != 32 {
		return nil, errors.New("invalid scalar length")
	}

	 := new(p256OrdElement)
	p256OrdBigToLittle(, (*[32]byte)())
	p256OrdReduce()

	// Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem.
	//
	// The sequence of 38 multiplications and 254 squarings is derived from
	// https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion
	 := new(p256OrdElement)
	 := new(p256OrdElement)
	 := new(p256OrdElement)
	 := new(p256OrdElement)
	 := new(p256OrdElement)
	 := new(p256OrdElement)
	 := new(p256OrdElement)
	 := new(p256OrdElement)

	// This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is
	// the order of the scalar field. Elements in the Montgomery domain take the
	// form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the
	// domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x
	// into the Montgomery domain.
	 := &p256OrdElement{0x83244c95be79eea2, 0x4699799c49bd6fa6,
		0x2845b2392b6bec59, 0x66e12d94f3d95620}

	p256OrdMul(, , )      // _1
	p256OrdSqr(, , 1)       // _10
	p256OrdMul(, , )     // _11
	p256OrdMul(, , )   // _101
	p256OrdMul(, , )  // _111
	p256OrdSqr(, , 1)     // _1010
	p256OrdMul(, , ) // _1111

	p256OrdSqr(, , 1)          // _10100
	p256OrdMul(, , )    // _10101
	p256OrdSqr(, , 1)     // _101010
	p256OrdMul(, , ) // _101111
	p256OrdMul(, , )     // _111111 = x6
	p256OrdSqr(, , 2)          // _11111100
	p256OrdMul(, , )        // _11111111 = x8
	p256OrdSqr(, , 8)          // _ff00
	p256OrdMul(, , )          // _ffff = x16
	p256OrdSqr(, , 16)         // _ffff0000
	p256OrdMul(, , )          // _ffffffff = x32

	p256OrdSqr(, , 64)
	p256OrdMul(, , )
	p256OrdSqr(, , 32)
	p256OrdMul(, , )

	 := []int{
		6, 5, 4, 5, 5,
		4, 3, 3, 5, 9,
		6, 2, 5, 6, 5,
		4, 5, 5, 3, 10,
		2, 5, 5, 3, 7, 6}
	 := []*p256OrdElement{
		, , , , ,
		, , , , ,
		, , , , ,
		, , , , ,
		, , , , , }

	for ,  := range  {
		p256OrdSqr(, , )
		p256OrdMul(, , [])
	}

	// Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1,
	// converts a Montgomery value out of the domain.
	 := &p256OrdElement{1}
	p256OrdMul(, , )

	var  [32]byte
	p256OrdLittleToBig(&, )
	return [:], nil
}