1 package ff
2
3 import (
4 "io"
5
6 "github.com/cloudflare/circl/internal/conv"
7 )
8
9
10 const ScalarSize = 32
11
12
13 type scMont = [ScalarSize / 8]uint64
14
15
16 type scRaw = [ScalarSize / 8]uint64
17
18
19 type Scalar struct{ i scMont }
20
21 func (z Scalar) String() string { x := z.fromMont(); return conv.Uint64Le2Hex(x[:]) }
22 func (z *Scalar) Set(x *Scalar) { z.i = x.i }
23 func (z *Scalar) SetUint64(n uint64) { z.toMont(&scRaw{n}) }
24 func (z *Scalar) SetOne() { z.SetUint64(1) }
25 func (z *Scalar) Random(r io.Reader) error { return randomInt(z.i[:], r, scOrder[:]) }
26 func (z Scalar) IsZero() int { return ctUint64Eq(z.i[:], (&scMont{})[:]) }
27 func (z Scalar) IsEqual(x *Scalar) int { return ctUint64Eq(z.i[:], x.i[:]) }
28 func (z *Scalar) Neg() { fiatScMontSub(&z.i, &scMont{}, &z.i) }
29 func (z *Scalar) Add(x, y *Scalar) { fiatScMontAdd(&z.i, &x.i, &y.i) }
30 func (z *Scalar) Sub(x, y *Scalar) { fiatScMontSub(&z.i, &x.i, &y.i) }
31 func (z *Scalar) Mul(x, y *Scalar) { fiatScMontMul(&z.i, &x.i, &y.i) }
32 func (z *Scalar) Sqr(x *Scalar) { fiatScMontSquare(&z.i, &x.i) }
33 func (z *Scalar) Inv(x *Scalar) { z.expVarTime(x, scOrderMinus2[:]) }
34 func (z *Scalar) toMont(in *scRaw) { fiatScMontMul(&z.i, in, &scRSquare) }
35 func (z Scalar) fromMont() (out scRaw) { fiatScMontMul(&out, &z.i, &scMont{1}); return }
36
37
38
39
40
41 func ScalarOrder() []byte { o := scOrder; return o[:] }
42
43
44 func (z *Scalar) expVarTime(x *Scalar, n []byte) {
45 zz := new(Scalar)
46 zz.SetOne()
47 N := 8 * len(n)
48 for i := 0; i < N; i++ {
49 zz.Sqr(zz)
50 bit := 0x1 & (n[i/8] >> uint(7-i%8))
51 if bit != 0 {
52 zz.Mul(zz, x)
53 }
54 }
55 z.Set(zz)
56 }
57
58
59
60 func (z *Scalar) SetBytes(data []byte) {
61 in64 := setBytesUnbounded(data, scOrder[:])
62 s := &scRaw{}
63 copy(s[:], in64[:ScalarSize/8])
64 z.toMont(s)
65 }
66
67
68
69 func (z *Scalar) MarshalBinary() ([]byte, error) {
70 x := z.fromMont()
71 return conv.Uint64Le2BytesBe(x[:]), nil
72 }
73
74
75
76
77 func (z *Scalar) UnmarshalBinary(data []byte) error {
78 if len(data) < ScalarSize {
79 return errInputLength
80 }
81 in64, err := setBytesBounded(data[:ScalarSize], scOrder[:])
82 if err == nil {
83 s := &scRaw{}
84 copy(s[:], in64[:ScalarSize/8])
85 z.toMont(s)
86 }
87 return err
88 }
89
90
91 func (z *Scalar) SetString(s string) error {
92 in64, err := setString(s, scOrder[:])
93 if err == nil {
94 s := &scRaw{}
95 copy(s[:], in64[:ScalarSize/8])
96 z.toMont(s)
97 }
98 return err
99 }
100
101 func fiatScMontCmovznzU64(z *uint64, b, x, y uint64) { cselectU64(z, b, x, y) }
102
103 var (
104
105 scOrder = [ScalarSize]byte{
106 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48,
107 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05,
108 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe,
109 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
110 }
111
112 scOrderMinus2 = [ScalarSize]byte{
113 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48,
114 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05,
115 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe,
116 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
117 }
118
119 scRSquare = scMont{
120 0xc999e990f3f29c6d, 0x2b6cedcb87925c23,
121 0x05d314967254398f, 0x0748d9d99f59ff11,
122 }
123 )
124
View as plain text