github.com/cloudflare/circl@v1.5.0/group/ristretto255.go (about) 1 package group 2 3 import ( 4 "crypto" 5 _ "crypto/sha512" 6 "fmt" 7 "io" 8 "math/big" 9 10 r255 "github.com/bwesterb/go-ristretto" 11 "github.com/cloudflare/circl/expander" 12 "github.com/cloudflare/circl/internal/conv" 13 ) 14 15 // Ristretto255 is a quotient group generated from the edwards25519 curve. 16 var Ristretto255 Group = ristrettoGroup{} 17 18 type ristrettoGroup struct{} 19 20 func (g ristrettoGroup) String() string { 21 return "ristretto255" 22 } 23 24 func (g ristrettoGroup) Params() *Params { 25 return &Params{32, 32, 32} 26 } 27 28 type ristrettoElement struct { 29 p r255.Point 30 } 31 32 type ristrettoScalar struct { 33 s r255.Scalar 34 } 35 36 func (g ristrettoGroup) NewElement() Element { 37 return g.Identity() 38 } 39 40 func (g ristrettoGroup) NewScalar() Scalar { 41 return &ristrettoScalar{ 42 s: r255.Scalar{}, 43 } 44 } 45 46 func (g ristrettoGroup) Identity() Element { 47 var zero r255.Point 48 zero.SetZero() 49 return &ristrettoElement{ 50 p: zero, 51 } 52 } 53 54 func (g ristrettoGroup) Generator() Element { 55 var base r255.Point 56 base.SetBase() 57 return &ristrettoElement{ 58 p: base, 59 } 60 } 61 62 func (g ristrettoGroup) RandomElement(r io.Reader) Element { 63 var x r255.Point 64 x.Rand() 65 return &ristrettoElement{ 66 p: x, 67 } 68 } 69 70 func (g ristrettoGroup) RandomScalar(io.Reader) Scalar { 71 var x r255.Scalar 72 x.Rand() 73 return &ristrettoScalar{ 74 s: x, 75 } 76 } 77 78 func (g ristrettoGroup) RandomNonZeroScalar(io.Reader) Scalar { 79 var s r255.Scalar 80 for { 81 s.Rand() 82 if s.IsNonZeroI() == 1 { 83 return &ristrettoScalar{s} 84 } 85 } 86 } 87 88 func (g ristrettoGroup) HashToElementNonUniform(b, dst []byte) Element { 89 return g.HashToElement(b, dst) 90 } 91 92 func (g ristrettoGroup) HashToElement(msg, dst []byte) Element { 93 // Compliant with draft-irtf-cfrg-hash-to-curve. 94 // Appendix B - Hashing to ristretto255 95 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-B 96 // SuiteID: ristretto255_XMD:SHA-512_R255MAP_RO_ 97 var buf [32]byte 98 xmd := expander.NewExpanderMD(crypto.SHA512, dst) 99 uniformBytes := xmd.Expand(msg, 64) 100 copy(buf[:], uniformBytes[:32]) 101 p0 := new(r255.Point).SetElligator(&buf) 102 copy(buf[:], uniformBytes[32:]) 103 p1 := new(r255.Point).SetElligator(&buf) 104 p0.Add(p0, p1) 105 106 return &ristrettoElement{*p0} 107 } 108 109 func (g ristrettoGroup) HashToScalar(msg, dst []byte) Scalar { 110 // Adapted to be compliant with draft-irtf-cfrg-voprf 111 // Section 4.1.1 - OPRF(ristretto255, SHA-512) 112 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf-09#section-4.1.1 113 var uniformBytes [64]byte 114 xmd := expander.NewExpanderMD(crypto.SHA512, dst) 115 copy(uniformBytes[:], xmd.Expand(msg, 64)) 116 s := g.NewScalar() 117 s.(*ristrettoScalar).s.SetReduced(&uniformBytes) 118 return s 119 } 120 121 func (e *ristrettoElement) Group() Group { return Ristretto255 } 122 123 func (e *ristrettoElement) String() string { return fmt.Sprintf("%x", e.p.Bytes()) } 124 125 func (e *ristrettoElement) IsIdentity() bool { 126 var zero r255.Point 127 zero.SetZero() 128 return e.p.Equals(&zero) 129 } 130 131 func (e *ristrettoElement) IsEqual(x Element) bool { 132 return e.p.Equals(&x.(*ristrettoElement).p) 133 } 134 135 func (e *ristrettoElement) Set(x Element) Element { 136 e.p.Set(&x.(*ristrettoElement).p) 137 return e 138 } 139 140 func (e *ristrettoElement) Copy() Element { 141 return &ristrettoElement{*new(r255.Point).Set(&e.p)} 142 } 143 144 func (e *ristrettoElement) CMov(v int, x Element) Element { 145 if !(v == 0 || v == 1) { 146 panic(ErrSelector) 147 } 148 e.p.ConditionalSet(&x.(*ristrettoElement).p, int32(v)) 149 return e 150 } 151 152 func (e *ristrettoElement) CSelect(v int, x Element, y Element) Element { 153 if !(v == 0 || v == 1) { 154 panic(ErrSelector) 155 } 156 e.p.ConditionalSet(&x.(*ristrettoElement).p, int32(v)) 157 e.p.ConditionalSet(&y.(*ristrettoElement).p, int32(1-v)) 158 return e 159 } 160 161 func (e *ristrettoElement) Add(x Element, y Element) Element { 162 e.p.Add(&x.(*ristrettoElement).p, &y.(*ristrettoElement).p) 163 return e 164 } 165 166 func (e *ristrettoElement) Dbl(x Element) Element { 167 return e.Add(x, x) 168 } 169 170 func (e *ristrettoElement) Neg(x Element) Element { 171 e.p.Neg(&x.(*ristrettoElement).p) 172 return e 173 } 174 175 func (e *ristrettoElement) Mul(x Element, y Scalar) Element { 176 e.p.ScalarMult(&x.(*ristrettoElement).p, &y.(*ristrettoScalar).s) 177 return e 178 } 179 180 func (e *ristrettoElement) MulGen(x Scalar) Element { 181 e.p.ScalarMultBase(&x.(*ristrettoScalar).s) 182 return e 183 } 184 185 func (e *ristrettoElement) MarshalBinaryCompress() ([]byte, error) { 186 return e.p.MarshalBinary() 187 } 188 189 func (e *ristrettoElement) MarshalBinary() ([]byte, error) { 190 return e.p.MarshalBinary() 191 } 192 193 func (e *ristrettoElement) UnmarshalBinary(data []byte) error { 194 return e.p.UnmarshalBinary(data) 195 } 196 197 func (s *ristrettoScalar) Group() Group { return Ristretto255 } 198 func (s *ristrettoScalar) String() string { return conv.BytesLe2Hex(s.s.Bytes()) } 199 func (s *ristrettoScalar) SetUint64(n uint64) Scalar { s.s.SetUint64(n); return s } 200 func (s *ristrettoScalar) SetBigInt(x *big.Int) Scalar { s.s.SetBigInt(x); return s } 201 func (s *ristrettoScalar) IsZero() bool { return s.s.IsNonZeroI() == 0 } 202 func (s *ristrettoScalar) IsEqual(x Scalar) bool { 203 return s.s.Equals(&x.(*ristrettoScalar).s) 204 } 205 206 func (s *ristrettoScalar) Set(x Scalar) Scalar { 207 s.s.Set(&x.(*ristrettoScalar).s) 208 return s 209 } 210 211 func (s *ristrettoScalar) Copy() Scalar { 212 return &ristrettoScalar{*new(r255.Scalar).Set(&s.s)} 213 } 214 215 func (s *ristrettoScalar) CMov(v int, x Scalar) Scalar { 216 if !(v == 0 || v == 1) { 217 panic(ErrSelector) 218 } 219 s.s.ConditionalSet(&x.(*ristrettoScalar).s, int32(v)) 220 return s 221 } 222 223 func (s *ristrettoScalar) CSelect(v int, x Scalar, y Scalar) Scalar { 224 if !(v == 0 || v == 1) { 225 panic(ErrSelector) 226 } 227 s.s.ConditionalSet(&x.(*ristrettoScalar).s, int32(v)) 228 s.s.ConditionalSet(&y.(*ristrettoScalar).s, int32(1-v)) 229 return s 230 } 231 232 func (s *ristrettoScalar) Add(x Scalar, y Scalar) Scalar { 233 s.s.Add(&x.(*ristrettoScalar).s, &y.(*ristrettoScalar).s) 234 return s 235 } 236 237 func (s *ristrettoScalar) Sub(x Scalar, y Scalar) Scalar { 238 s.s.Sub(&x.(*ristrettoScalar).s, &y.(*ristrettoScalar).s) 239 return s 240 } 241 242 func (s *ristrettoScalar) Mul(x Scalar, y Scalar) Scalar { 243 s.s.Mul(&x.(*ristrettoScalar).s, &y.(*ristrettoScalar).s) 244 return s 245 } 246 247 func (s *ristrettoScalar) Neg(x Scalar) Scalar { 248 s.s.Neg(&x.(*ristrettoScalar).s) 249 return s 250 } 251 252 func (s *ristrettoScalar) Inv(x Scalar) Scalar { 253 s.s.Inverse(&x.(*ristrettoScalar).s) 254 return s 255 } 256 257 func (s *ristrettoScalar) MarshalBinary() ([]byte, error) { 258 return s.s.MarshalBinary() 259 } 260 261 func (s *ristrettoScalar) UnmarshalBinary(data []byte) error { 262 return s.s.UnmarshalBinary(data) 263 }