-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
p224_sqrt.go
133 lines (118 loc) · 3.12 KB
/
p224_sqrt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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.
package nistec
import (
"sync"
"filippo.io/nistec/internal/fiat"
)
var p224GG *[96]fiat.P224Element
var p224GGOnce sync.Once
// p224SqrtCandidate sets r to a square root candidate for x. r and x must not overlap.
func p224SqrtCandidate(r, x *fiat.P224Element) {
// Since p = 1 mod 4, we can't use the exponentiation by (p + 1) / 4 like
// for the other primes. Instead, implement a variation of Tonelli–Shanks.
// The constant-time implementation is adapted from Thomas Pornin's ecGFp5.
//
// https://github.com/pornin/ecgfp5/blob/82325b965/rust/src/field.rs#L337-L385
// p = q*2^n + 1 with q odd -> q = 2^128 - 1 and n = 96
// g^(2^n) = 1 -> g = 11 ^ q (where 11 is the smallest non-square)
// GG[j] = g^(2^j) for j = 0 to n-1
p224GGOnce.Do(func() {
p224GG = new([96]fiat.P224Element)
for i := range p224GG {
if i == 0 {
p224GG[i].SetBytes([]byte{0x6a, 0x0f, 0xec, 0x67,
0x85, 0x98, 0xa7, 0x92, 0x0c, 0x55, 0xb2, 0xd4,
0x0b, 0x2d, 0x6f, 0xfb, 0xbe, 0xa3, 0xd8, 0xce,
0xf3, 0xfb, 0x36, 0x32, 0xdc, 0x69, 0x1b, 0x74})
} else {
p224GG[i].Square(&p224GG[i-1])
}
}
})
// r <- x^((q+1)/2) = x^(2^127)
// v <- x^q = x^(2^128-1)
// Compute x^(2^127-1) first.
//
// The sequence of 10 multiplications and 126 squarings is derived from the
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
//
// _10 = 2*1
// _11 = 1 + _10
// _110 = 2*_11
// _111 = 1 + _110
// _111000 = _111 << 3
// _111111 = _111 + _111000
// _1111110 = 2*_111111
// _1111111 = 1 + _1111110
// x12 = _1111110 << 5 + _111111
// x24 = x12 << 12 + x12
// i36 = x24 << 7
// x31 = _1111111 + i36
// x48 = i36 << 17 + x24
// x96 = x48 << 48 + x48
// return x96 << 31 + x31
//
var t0 = new(fiat.P224Element)
var t1 = new(fiat.P224Element)
r.Square(x)
r.Mul(x, r)
r.Square(r)
r.Mul(x, r)
t0.Square(r)
for s := 1; s < 3; s++ {
t0.Square(t0)
}
t0.Mul(r, t0)
t1.Square(t0)
r.Mul(x, t1)
for s := 0; s < 5; s++ {
t1.Square(t1)
}
t0.Mul(t0, t1)
t1.Square(t0)
for s := 1; s < 12; s++ {
t1.Square(t1)
}
t0.Mul(t0, t1)
t1.Square(t0)
for s := 1; s < 7; s++ {
t1.Square(t1)
}
r.Mul(r, t1)
for s := 0; s < 17; s++ {
t1.Square(t1)
}
t0.Mul(t0, t1)
t1.Square(t0)
for s := 1; s < 48; s++ {
t1.Square(t1)
}
t0.Mul(t0, t1)
for s := 0; s < 31; s++ {
t0.Square(t0)
}
r.Mul(r, t0)
// v = x^(2^127-1)^2 * x
v := new(fiat.P224Element).Square(r)
v.Mul(v, x)
// r = x^(2^127-1) * x
r.Mul(r, x)
// for i = n-1 down to 1:
// w = v^(2^(i-1))
// if w == -1 then:
// v <- v*GG[n-i]
// r <- r*GG[n-i-1]
var p224MinusOne = new(fiat.P224Element).Sub(
new(fiat.P224Element), new(fiat.P224Element).One())
for i := 96 - 1; i >= 1; i-- {
w := new(fiat.P224Element).Set(v)
for j := 0; j < i-1; j++ {
w.Square(w)
}
cond := w.Equal(p224MinusOne)
v.Select(t0.Mul(v, &p224GG[96-i]), v, cond)
r.Select(t0.Mul(r, &p224GG[96-i-1]), r, cond)
}
}