github.com/cloudflare/circl@v1.5.0/sign/ed25519/modular.go (about)

     1  package ed25519
     2  
     3  import (
     4  	"encoding/binary"
     5  	"math/bits"
     6  )
     7  
     8  var order = [paramB]byte{
     9  	0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
    10  	0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
    11  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    12  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
    13  }
    14  
    15  // isLessThan returns true if 0 <= x < y, and assumes that slices have the same length.
    16  func isLessThan(x, y []byte) bool {
    17  	i := len(x) - 1
    18  	for i > 0 && x[i] == y[i] {
    19  		i--
    20  	}
    21  	return x[i] < y[i]
    22  }
    23  
    24  // reduceModOrder calculates k = k mod order of the curve.
    25  func reduceModOrder(k []byte, is512Bit bool) {
    26  	var X [((2 * paramB) * 8) / 64]uint64
    27  	numWords := len(k) >> 3
    28  	for i := 0; i < numWords; i++ {
    29  		X[i] = binary.LittleEndian.Uint64(k[i*8 : (i+1)*8])
    30  	}
    31  	red512(&X, is512Bit)
    32  	for i := 0; i < numWords; i++ {
    33  		binary.LittleEndian.PutUint64(k[i*8:(i+1)*8], X[i])
    34  	}
    35  }
    36  
    37  // red512 calculates x = x mod Order of the curve.
    38  func red512(x *[8]uint64, full bool) {
    39  	// Implementation of Algs.(14.47)+(14.52) of Handbook of Applied
    40  	// Cryptography, by A. Menezes, P. van Oorschot, and S. Vanstone.
    41  	const (
    42  		ell0   = uint64(0x5812631a5cf5d3ed)
    43  		ell1   = uint64(0x14def9dea2f79cd6)
    44  		ell160 = uint64(0x812631a5cf5d3ed0)
    45  		ell161 = uint64(0x4def9dea2f79cd65)
    46  		ell162 = uint64(0x0000000000000001)
    47  	)
    48  
    49  	var c0, c1, c2, c3 uint64
    50  	r0, r1, r2, r3, r4 := x[0], x[1], x[2], x[3], uint64(0)
    51  
    52  	if full {
    53  		q0, q1, q2, q3 := x[4], x[5], x[6], x[7]
    54  
    55  		for i := 0; i < 3; i++ {
    56  			h0, s0 := bits.Mul64(q0, ell160)
    57  			h1, s1 := bits.Mul64(q1, ell160)
    58  			h2, s2 := bits.Mul64(q2, ell160)
    59  			h3, s3 := bits.Mul64(q3, ell160)
    60  
    61  			s1, c0 = bits.Add64(h0, s1, 0)
    62  			s2, c1 = bits.Add64(h1, s2, c0)
    63  			s3, c2 = bits.Add64(h2, s3, c1)
    64  			s4, _ := bits.Add64(h3, 0, c2)
    65  
    66  			h0, l0 := bits.Mul64(q0, ell161)
    67  			h1, l1 := bits.Mul64(q1, ell161)
    68  			h2, l2 := bits.Mul64(q2, ell161)
    69  			h3, l3 := bits.Mul64(q3, ell161)
    70  
    71  			l1, c0 = bits.Add64(h0, l1, 0)
    72  			l2, c1 = bits.Add64(h1, l2, c0)
    73  			l3, c2 = bits.Add64(h2, l3, c1)
    74  			l4, _ := bits.Add64(h3, 0, c2)
    75  
    76  			s1, c0 = bits.Add64(s1, l0, 0)
    77  			s2, c1 = bits.Add64(s2, l1, c0)
    78  			s3, c2 = bits.Add64(s3, l2, c1)
    79  			s4, c3 = bits.Add64(s4, l3, c2)
    80  			s5, s6 := bits.Add64(l4, 0, c3)
    81  
    82  			s2, c0 = bits.Add64(s2, q0, 0)
    83  			s3, c1 = bits.Add64(s3, q1, c0)
    84  			s4, c2 = bits.Add64(s4, q2, c1)
    85  			s5, c3 = bits.Add64(s5, q3, c2)
    86  			s6, s7 := bits.Add64(s6, 0, c3)
    87  
    88  			q := q0 | q1 | q2 | q3
    89  			m := -((q | -q) >> 63) // if q=0 then m=0...0 else m=1..1
    90  			s0 &= m
    91  			s1 &= m
    92  			s2 &= m
    93  			s3 &= m
    94  			q0, q1, q2, q3 = s4, s5, s6, s7
    95  
    96  			if (i+1)%2 == 0 {
    97  				r0, c0 = bits.Add64(r0, s0, 0)
    98  				r1, c1 = bits.Add64(r1, s1, c0)
    99  				r2, c2 = bits.Add64(r2, s2, c1)
   100  				r3, c3 = bits.Add64(r3, s3, c2)
   101  				r4, _ = bits.Add64(r4, 0, c3)
   102  			} else {
   103  				r0, c0 = bits.Sub64(r0, s0, 0)
   104  				r1, c1 = bits.Sub64(r1, s1, c0)
   105  				r2, c2 = bits.Sub64(r2, s2, c1)
   106  				r3, c3 = bits.Sub64(r3, s3, c2)
   107  				r4, _ = bits.Sub64(r4, 0, c3)
   108  			}
   109  		}
   110  
   111  		m := -(r4 >> 63)
   112  		r0, c0 = bits.Add64(r0, m&ell160, 0)
   113  		r1, c1 = bits.Add64(r1, m&ell161, c0)
   114  		r2, c2 = bits.Add64(r2, m&ell162, c1)
   115  		r3, c3 = bits.Add64(r3, 0, c2)
   116  		r4, _ = bits.Add64(r4, m&1, c3)
   117  		x[4], x[5], x[6], x[7] = 0, 0, 0, 0
   118  	}
   119  
   120  	q0 := (r4 << 4) | (r3 >> 60)
   121  	r3 &= (uint64(1) << 60) - 1
   122  
   123  	h0, s0 := bits.Mul64(ell0, q0)
   124  	h1, s1 := bits.Mul64(ell1, q0)
   125  	s1, c0 = bits.Add64(h0, s1, 0)
   126  	s2, _ := bits.Add64(h1, 0, c0)
   127  
   128  	r0, c0 = bits.Sub64(r0, s0, 0)
   129  	r1, c1 = bits.Sub64(r1, s1, c0)
   130  	r2, c2 = bits.Sub64(r2, s2, c1)
   131  	r3, _ = bits.Sub64(r3, 0, c2)
   132  
   133  	x[0], x[1], x[2], x[3] = r0, r1, r2, r3
   134  }
   135  
   136  // calculateS performs s = r+k*a mod Order of the curve.
   137  func calculateS(s, r, k, a []byte) {
   138  	K := [4]uint64{
   139  		binary.LittleEndian.Uint64(k[0*8 : 1*8]),
   140  		binary.LittleEndian.Uint64(k[1*8 : 2*8]),
   141  		binary.LittleEndian.Uint64(k[2*8 : 3*8]),
   142  		binary.LittleEndian.Uint64(k[3*8 : 4*8]),
   143  	}
   144  	S := [8]uint64{
   145  		binary.LittleEndian.Uint64(r[0*8 : 1*8]),
   146  		binary.LittleEndian.Uint64(r[1*8 : 2*8]),
   147  		binary.LittleEndian.Uint64(r[2*8 : 3*8]),
   148  		binary.LittleEndian.Uint64(r[3*8 : 4*8]),
   149  	}
   150  	var c3 uint64
   151  	for i := range K {
   152  		ai := binary.LittleEndian.Uint64(a[i*8 : (i+1)*8])
   153  
   154  		h0, l0 := bits.Mul64(K[0], ai)
   155  		h1, l1 := bits.Mul64(K[1], ai)
   156  		h2, l2 := bits.Mul64(K[2], ai)
   157  		h3, l3 := bits.Mul64(K[3], ai)
   158  
   159  		l1, c0 := bits.Add64(h0, l1, 0)
   160  		l2, c1 := bits.Add64(h1, l2, c0)
   161  		l3, c2 := bits.Add64(h2, l3, c1)
   162  		l4, _ := bits.Add64(h3, 0, c2)
   163  
   164  		S[i+0], c0 = bits.Add64(S[i+0], l0, 0)
   165  		S[i+1], c1 = bits.Add64(S[i+1], l1, c0)
   166  		S[i+2], c2 = bits.Add64(S[i+2], l2, c1)
   167  		S[i+3], c3 = bits.Add64(S[i+3], l3, c2)
   168  		S[i+4], _ = bits.Add64(S[i+4], l4, c3)
   169  	}
   170  	red512(&S, true)
   171  	binary.LittleEndian.PutUint64(s[0*8:1*8], S[0])
   172  	binary.LittleEndian.PutUint64(s[1*8:2*8], S[1])
   173  	binary.LittleEndian.PutUint64(s[2*8:3*8], S[2])
   174  	binary.LittleEndian.PutUint64(s[3*8:4*8], S[3])
   175  }