github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/crypto/internal/nistec/p256_asm_ordinv.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build amd64 || arm64 6 7 package nistec 8 9 import "errors" 10 11 // Montgomery multiplication modulo org(G). Sets res = in1 * in2 * R⁻¹. 12 // 13 //go:noescape 14 func p256OrdMul(res, in1, in2 *p256OrdElement) 15 16 // Montgomery square modulo org(G), repeated n times (n >= 1). 17 // 18 //go:noescape 19 func p256OrdSqr(res, in *p256OrdElement, n int) 20 21 func P256OrdInverse(k []byte) ([]byte, error) { 22 if len(k) != 32 { 23 return nil, errors.New("invalid scalar length") 24 } 25 26 x := new(p256OrdElement) 27 p256OrdBigToLittle(x, (*[32]byte)(k)) 28 29 // Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem. 30 // 31 // The sequence of 38 multiplications and 254 squarings is derived from 32 // https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion 33 _1 := new(p256OrdElement) 34 _11 := new(p256OrdElement) 35 _101 := new(p256OrdElement) 36 _111 := new(p256OrdElement) 37 _1111 := new(p256OrdElement) 38 _10101 := new(p256OrdElement) 39 _101111 := new(p256OrdElement) 40 t := new(p256OrdElement) 41 42 // This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is 43 // the order of the scalar field. Elements in the Montgomery domain take the 44 // form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the 45 // domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x 46 // into the Montgomery domain. 47 RR := &p256OrdElement{0x83244c95be79eea2, 0x4699799c49bd6fa6, 48 0x2845b2392b6bec59, 0x66e12d94f3d95620} 49 50 p256OrdMul(_1, x, RR) // _1 51 p256OrdSqr(x, _1, 1) // _10 52 p256OrdMul(_11, x, _1) // _11 53 p256OrdMul(_101, x, _11) // _101 54 p256OrdMul(_111, x, _101) // _111 55 p256OrdSqr(x, _101, 1) // _1010 56 p256OrdMul(_1111, _101, x) // _1111 57 58 p256OrdSqr(t, x, 1) // _10100 59 p256OrdMul(_10101, t, _1) // _10101 60 p256OrdSqr(x, _10101, 1) // _101010 61 p256OrdMul(_101111, _101, x) // _101111 62 p256OrdMul(x, _10101, x) // _111111 = x6 63 p256OrdSqr(t, x, 2) // _11111100 64 p256OrdMul(t, t, _11) // _11111111 = x8 65 p256OrdSqr(x, t, 8) // _ff00 66 p256OrdMul(x, x, t) // _ffff = x16 67 p256OrdSqr(t, x, 16) // _ffff0000 68 p256OrdMul(t, t, x) // _ffffffff = x32 69 70 p256OrdSqr(x, t, 64) 71 p256OrdMul(x, x, t) 72 p256OrdSqr(x, x, 32) 73 p256OrdMul(x, x, t) 74 75 sqrs := []int{ 76 6, 5, 4, 5, 5, 77 4, 3, 3, 5, 9, 78 6, 2, 5, 6, 5, 79 4, 5, 5, 3, 10, 80 2, 5, 5, 3, 7, 6} 81 muls := []*p256OrdElement{ 82 _101111, _111, _11, _1111, _10101, 83 _101, _101, _101, _111, _101111, 84 _1111, _1, _1, _1111, _111, 85 _111, _111, _101, _11, _101111, 86 _11, _11, _11, _1, _10101, _1111} 87 88 for i, s := range sqrs { 89 p256OrdSqr(x, x, s) 90 p256OrdMul(x, x, muls[i]) 91 } 92 93 // Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1, 94 // converts a Montgomery value out of the domain. 95 one := &p256OrdElement{1} 96 p256OrdMul(x, x, one) 97 98 var xOut [32]byte 99 p256OrdLittleToBig(&xOut, x) 100 return xOut[:], nil 101 }