1
2
3
4
5 package main
6
7 import (
8 "fmt"
9
10 . "github.com/mmcloughlin/avo/build"
11 . "github.com/mmcloughlin/avo/gotypes"
12 . "github.com/mmcloughlin/avo/operand"
13 . "github.com/mmcloughlin/avo/reg"
14 )
15
16
17
18 func main() {
19 Package("crypto/internal/fips140/edwards25519/field")
20 ConstraintExpr("!purego")
21 feMul()
22 Generate()
23 }
24
25 type namedComponent struct {
26 Component
27 name string
28 }
29
30 func (c namedComponent) String() string { return c.name }
31
32 type uint128 struct {
33 name string
34 hi, lo GPVirtual
35 }
36
37 func (c uint128) String() string { return c.name }
38
39 func feMul() {
40 TEXT("feMul", NOSPLIT, "func(out, a, b *Element)")
41 Doc("feMul sets out = a * b. It works like feMulGeneric.")
42 Pragma("noescape")
43
44 a := Dereference(Param("a"))
45 a0 := namedComponent{a.Field("l0"), "a0"}
46 a1 := namedComponent{a.Field("l1"), "a1"}
47 a2 := namedComponent{a.Field("l2"), "a2"}
48 a3 := namedComponent{a.Field("l3"), "a3"}
49 a4 := namedComponent{a.Field("l4"), "a4"}
50
51 b := Dereference(Param("b"))
52 b0 := namedComponent{b.Field("l0"), "b0"}
53 b1 := namedComponent{b.Field("l1"), "b1"}
54 b2 := namedComponent{b.Field("l2"), "b2"}
55 b3 := namedComponent{b.Field("l3"), "b3"}
56 b4 := namedComponent{b.Field("l4"), "b4"}
57
58
59 r0 := uint128{"r0", GP64(), GP64()}
60 mul64(r0, 1, a0, b0)
61 addMul64(r0, 19, a1, b4)
62 addMul64(r0, 19, a2, b3)
63 addMul64(r0, 19, a3, b2)
64 addMul64(r0, 19, a4, b1)
65
66
67 r1 := uint128{"r1", GP64(), GP64()}
68 mul64(r1, 1, a0, b1)
69 addMul64(r1, 1, a1, b0)
70 addMul64(r1, 19, a2, b4)
71 addMul64(r1, 19, a3, b3)
72 addMul64(r1, 19, a4, b2)
73
74
75 r2 := uint128{"r2", GP64(), GP64()}
76 mul64(r2, 1, a0, b2)
77 addMul64(r2, 1, a1, b1)
78 addMul64(r2, 1, a2, b0)
79 addMul64(r2, 19, a3, b4)
80 addMul64(r2, 19, a4, b3)
81
82
83 r3 := uint128{"r3", GP64(), GP64()}
84 mul64(r3, 1, a0, b3)
85 addMul64(r3, 1, a1, b2)
86 addMul64(r3, 1, a2, b1)
87 addMul64(r3, 1, a3, b0)
88 addMul64(r3, 19, a4, b4)
89
90
91 r4 := uint128{"r4", GP64(), GP64()}
92 mul64(r4, 1, a0, b4)
93 addMul64(r4, 1, a1, b3)
94 addMul64(r4, 1, a2, b2)
95 addMul64(r4, 1, a3, b1)
96 addMul64(r4, 1, a4, b0)
97
98 Comment("First reduction chain")
99 maskLow51Bits := GP64()
100 MOVQ(Imm((1<<51)-1), maskLow51Bits)
101 c0, r0lo := shiftRightBy51(&r0)
102 c1, r1lo := shiftRightBy51(&r1)
103 c2, r2lo := shiftRightBy51(&r2)
104 c3, r3lo := shiftRightBy51(&r3)
105 c4, r4lo := shiftRightBy51(&r4)
106 maskAndAdd(r0lo, maskLow51Bits, c4, 19)
107 maskAndAdd(r1lo, maskLow51Bits, c0, 1)
108 maskAndAdd(r2lo, maskLow51Bits, c1, 1)
109 maskAndAdd(r3lo, maskLow51Bits, c2, 1)
110 maskAndAdd(r4lo, maskLow51Bits, c3, 1)
111
112 Comment("Second reduction chain (carryPropagate)")
113
114 MOVQ(r0lo, c0)
115 SHRQ(Imm(51), c0)
116
117 MOVQ(r1lo, c1)
118 SHRQ(Imm(51), c1)
119
120 MOVQ(r2lo, c2)
121 SHRQ(Imm(51), c2)
122
123 MOVQ(r3lo, c3)
124 SHRQ(Imm(51), c3)
125
126 MOVQ(r4lo, c4)
127 SHRQ(Imm(51), c4)
128 maskAndAdd(r0lo, maskLow51Bits, c4, 19)
129 maskAndAdd(r1lo, maskLow51Bits, c0, 1)
130 maskAndAdd(r2lo, maskLow51Bits, c1, 1)
131 maskAndAdd(r3lo, maskLow51Bits, c2, 1)
132 maskAndAdd(r4lo, maskLow51Bits, c3, 1)
133
134 Comment("Store output")
135 out := Dereference(Param("out"))
136 Store(r0lo, out.Field("l0"))
137 Store(r1lo, out.Field("l1"))
138 Store(r2lo, out.Field("l2"))
139 Store(r3lo, out.Field("l3"))
140 Store(r4lo, out.Field("l4"))
141
142 RET()
143 }
144
145
146 func mul64(r uint128, i int, aX, bX namedComponent) {
147 switch i {
148 case 1:
149 Comment(fmt.Sprintf("%s = %s×%s", r, aX, bX))
150 Load(aX, RAX)
151 case 2:
152 Comment(fmt.Sprintf("%s = 2×%s×%s", r, aX, bX))
153 Load(aX, RAX)
154 SHLQ(Imm(1), RAX)
155 default:
156 panic("unsupported i value")
157 }
158 MULQ(mustAddr(bX))
159 MOVQ(RAX, r.lo)
160 MOVQ(RDX, r.hi)
161 }
162
163
164 func addMul64(r uint128, i uint64, aX, bX namedComponent) {
165 switch i {
166 case 1:
167 Comment(fmt.Sprintf("%s += %s×%s", r, aX, bX))
168 Load(aX, RAX)
169 case 2:
170 Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
171 Load(aX, RAX)
172 SHLQ(U8(1), RAX)
173 case 19:
174 Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
175
176 tmp := Load(aX, GP64())
177 LEAQ(Mem{Base: tmp, Index: tmp, Scale: 8}, RAX)
178 LEAQ(Mem{Base: tmp, Index: RAX, Scale: 2}, RAX)
179 case 38:
180 Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
181
182 tmp := Load(aX, GP64())
183 LEAQ(Mem{Base: tmp, Index: tmp, Scale: 8}, RAX)
184 LEAQ(Mem{Base: tmp, Index: RAX, Scale: 2}, RAX)
185 SHLQ(U8(1), RAX)
186 default:
187 Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
188 IMUL3Q(Imm(i), Load(aX, GP64()), RAX)
189 }
190 MULQ(mustAddr(bX))
191 ADDQ(RAX, r.lo)
192 ADCQ(RDX, r.hi)
193 }
194
195
196
197
198 func shiftRightBy51(r *uint128) (out, lo GPVirtual) {
199 out = r.hi
200 lo = r.lo
201 SHLQ(Imm(64-51), r.lo, r.hi)
202 r.lo, r.hi = nil, nil
203 return
204 }
205
206
207 func maskAndAdd(r, mask, c GPVirtual, i uint64) {
208 ANDQ(mask, r)
209 if i != 1 {
210 IMUL3Q(Imm(i), c, c)
211 }
212 ADDQ(c, r)
213 }
214
215 func mustAddr(c Component) Op {
216 b, err := c.Resolve()
217 if err != nil {
218 panic(err)
219 }
220 return b.Addr
221 }
222
View as plain text