github.com/consensys/gnark-crypto@v0.14.0/field/generator/internal/templates/element/conv.go (about) 1 package element 2 3 const Conv = ` 4 5 // rSquare where r is the Montgommery constant 6 // see section 2.3.2 of Tolga Acar's thesis 7 // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf 8 var rSquare = {{.ElementName}}{ 9 {{- range $i := .RSquare}} 10 {{$i}},{{end}} 11 } 12 13 // toMont converts z to Montgomery form 14 // sets and returns z = z * r² 15 func (z *{{.ElementName}}) toMont() *{{.ElementName}} { 16 return z.Mul(z, &rSquare) 17 } 18 19 // String returns the decimal representation of z as generated by 20 // z.Text(10). 21 func (z *{{.ElementName}}) String() string { 22 return z.Text(10) 23 } 24 25 // toBigInt returns z as a big.Int in Montgomery form 26 func (z *{{.ElementName}}) toBigInt(res *big.Int) *big.Int { 27 var b [Bytes]byte 28 {{- range $i := reverse .NbWordsIndexesFull}} 29 {{- $j := mul $i 8}} 30 {{- $k := sub $.NbWords 1}} 31 {{- $k := sub $k $i}} 32 {{- $jj := add $j 8}} 33 binary.BigEndian.PutUint64(b[{{$j}}:{{$jj}}], z[{{$k}}]) 34 {{- end}} 35 36 return res.SetBytes(b[:]) 37 } 38 39 {{- $noNeg := and (eq $.NbWords 1) (ltu64 (index $.Q 0) 1000000)}} 40 // Text returns the string representation of z in the given base. 41 // Base must be between 2 and 36, inclusive. The result uses the 42 // lower-case letters 'a' to 'z' for digit values 10 to 35. 43 // No prefix (such as "0x") is added to the string. If z is a nil 44 // pointer it returns "<nil>". 45 {{- if not $noNeg}} 46 // If base == 10 and -z fits in a uint16 prefix "-" is added to the string. 47 {{- end}} 48 func (z *{{.ElementName}}) Text(base int) string { 49 if base < 2 || base > 36 { 50 panic("invalid base") 51 } 52 if z == nil { 53 return "<nil>" 54 } 55 56 const maxUint16 = 65535 57 {{- if eq $.NbWords 1}} 58 {{- if not $noNeg}} 59 if base == 10 { 60 var zzNeg {{.ElementName}} 61 zzNeg.Neg(z) 62 zzNeg.fromMont() 63 if zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { 64 return "-" + strconv.FormatUint(zzNeg[0], base) 65 } 66 } 67 {{- end}} 68 zz := z.Bits() 69 return strconv.FormatUint(zz[0], base) 70 {{- else }} 71 if base == 10 { 72 var zzNeg {{.ElementName}} 73 zzNeg.Neg(z) 74 zzNeg.fromMont() 75 if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { 76 return "-" + strconv.FormatUint(zzNeg[0], base) 77 } 78 } 79 zz := *z 80 zz.fromMont() 81 if zz.FitsOnOneWord() { 82 return strconv.FormatUint(zz[0], base) 83 } 84 vv := pool.BigInt.Get() 85 r := zz.toBigInt(vv).Text(base) 86 pool.BigInt.Put(vv) 87 return r 88 {{- end}} 89 } 90 91 // BigInt sets and return z as a *big.Int 92 func (z *{{.ElementName}}) BigInt(res *big.Int) *big.Int { 93 _z := *z 94 _z.fromMont() 95 return _z.toBigInt(res) 96 } 97 98 // ToBigIntRegular returns z as a big.Int in regular form 99 // 100 // Deprecated: use BigInt(*big.Int) instead 101 func (z {{.ElementName}}) ToBigIntRegular(res *big.Int) *big.Int { 102 z.fromMont() 103 return z.toBigInt(res) 104 } 105 106 // Bits provides access to z by returning its value as a little-endian [{{.NbWords}}]uint64 array. 107 // Bits is intended to support implementation of missing low-level {{.ElementName}} 108 // functionality outside this package; it should be avoided otherwise. 109 func (z *{{.ElementName}}) Bits() [{{.NbWords}}]uint64 { 110 _z := *z 111 fromMont(&_z) 112 return _z 113 } 114 115 // Bytes returns the value of z as a big-endian byte array 116 func (z *{{.ElementName}}) Bytes() (res [Bytes]byte) { 117 BigEndian.PutElement(&res, *z) 118 return 119 } 120 121 // Marshal returns the value of z as a big-endian byte slice 122 func (z *{{.ElementName}}) Marshal() []byte { 123 b := z.Bytes() 124 return b[:] 125 } 126 127 // Unmarshal is an alias for SetBytes, it sets z to the value of e. 128 func (z *{{.ElementName}}) Unmarshal(e []byte) { 129 z.SetBytes(e) 130 } 131 132 // SetBytes interprets e as the bytes of a big-endian unsigned integer, 133 // sets z to that value, and returns z. 134 func (z *{{.ElementName}}) SetBytes(e []byte) *{{.ElementName}} { 135 if len(e) == Bytes { 136 // fast path 137 v, err := BigEndian.Element((*[Bytes]byte)(e)) 138 if err == nil { 139 *z = v 140 return z 141 } 142 } 143 144 // slow path. 145 // get a big int from our pool 146 vv := pool.BigInt.Get() 147 vv.SetBytes(e) 148 149 // set big int 150 z.SetBigInt(vv) 151 152 // put temporary object back in pool 153 pool.BigInt.Put(vv) 154 155 return z 156 } 157 158 // SetBytesCanonical interprets e as the bytes of a big-endian {{.NbBytes}}-byte integer. 159 // If e is not a {{.NbBytes}}-byte slice or encodes a value higher than q, 160 // SetBytesCanonical returns an error. 161 func (z *{{.ElementName}}) SetBytesCanonical(e []byte) error { 162 if len(e) != Bytes { 163 return errors.New("invalid {{.PackageName}}.{{.ElementName}} encoding") 164 } 165 v, err := BigEndian.Element((*[Bytes]byte)(e)) 166 if err != nil { 167 return err 168 } 169 *z = v 170 return nil 171 } 172 173 174 // SetBigInt sets z to v and returns z 175 func (z *{{.ElementName}}) SetBigInt(v *big.Int) *{{.ElementName}} { 176 z.SetZero() 177 178 var zero big.Int 179 180 // fast path 181 c := v.Cmp(&_modulus) 182 if c == 0 { 183 // v == 0 184 return z 185 } else if c != 1 && v.Cmp(&zero) != -1 { 186 // 0 < v < q 187 return z.setBigInt(v) 188 } 189 190 // get temporary big int from the pool 191 vv := pool.BigInt.Get() 192 193 // copy input + modular reduction 194 vv.Mod(v, &_modulus) 195 196 // set big int byte value 197 z.setBigInt(vv) 198 199 // release object into pool 200 pool.BigInt.Put(vv) 201 return z 202 } 203 204 // setBigInt assumes 0 ⩽ v < q 205 func (z *{{.ElementName}}) setBigInt(v *big.Int) *{{.ElementName}} { 206 vBits := v.Bits() 207 208 if bits.UintSize == 64 { 209 for i := 0; i < len(vBits); i++ { 210 z[i] = uint64(vBits[i]) 211 } 212 } else { 213 for i := 0; i < len(vBits); i++ { 214 if i%2 == 0 { 215 z[i/2] = uint64(vBits[i]) 216 } else { 217 z[i/2] |= uint64(vBits[i]) << 32 218 } 219 } 220 } 221 222 return z.toMont() 223 } 224 225 // SetString creates a big.Int with number and calls SetBigInt on z 226 // 227 // The number prefix determines the actual base: A prefix of 228 // ''0b'' or ''0B'' selects base 2, ''0'', ''0o'' or ''0O'' selects base 8, 229 // and ''0x'' or ''0X'' selects base 16. Otherwise, the selected base is 10 230 // and no prefix is accepted. 231 // 232 // For base 16, lower and upper case letters are considered the same: 233 // The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. 234 // 235 // An underscore character ''_'' may appear between a base 236 // prefix and an adjacent digit, and between successive digits; such 237 // underscores do not change the value of the number. 238 // Incorrect placement of underscores is reported as a panic if there 239 // are no other errors. 240 // 241 // If the number is invalid this method leaves z unchanged and returns nil, error. 242 func (z *{{.ElementName}}) SetString(number string) (*{{.ElementName}}, error) { 243 // get temporary big int from the pool 244 vv := pool.BigInt.Get() 245 246 if _, ok := vv.SetString(number, 0); !ok { 247 return nil, errors.New("{{.ElementName}}.SetString failed -> can't parse number into a big.Int " + number) 248 } 249 250 z.SetBigInt(vv) 251 252 // release object into pool 253 pool.BigInt.Put(vv) 254 255 return z, nil 256 } 257 258 259 // MarshalJSON returns json encoding of z (z.Text(10)) 260 // If z == nil, returns null 261 func (z *{{.ElementName}}) MarshalJSON() ([]byte, error) { 262 if z == nil { 263 return []byte("null"), nil 264 } 265 const maxSafeBound = 15 // we encode it as number if it's small 266 s := z.Text(10) 267 if len(s) <= maxSafeBound { 268 return []byte(s), nil 269 } 270 var sbb strings.Builder 271 sbb.WriteByte('"') 272 sbb.WriteString(s) 273 sbb.WriteByte('"') 274 return []byte(sbb.String()), nil 275 } 276 277 // UnmarshalJSON accepts numbers and strings as input 278 // See {{.ElementName}}.SetString for valid prefixes (0x, 0b, ...) 279 func (z *{{.ElementName}}) UnmarshalJSON(data []byte) error { 280 s := string(data) 281 if len(s) > Bits*3 { 282 return errors.New("value too large (max = {{.ElementName}}.Bits * 3)") 283 } 284 285 // we accept numbers and strings, remove leading and trailing quotes if any 286 if len(s) > 0 && s[0] == '"' { 287 s = s[1:] 288 } 289 if len(s) > 0 && s[len(s)-1] == '"' { 290 s = s[:len(s)-1] 291 } 292 293 // get temporary big int from the pool 294 vv := pool.BigInt.Get() 295 296 if _, ok := vv.SetString(s, 0); !ok { 297 return errors.New("can't parse into a big.Int: " + s) 298 } 299 300 z.SetBigInt(vv) 301 302 // release object into pool 303 pool.BigInt.Put(vv) 304 return nil 305 } 306 307 308 // A ByteOrder specifies how to convert byte slices into a {{.ElementName}} 309 type ByteOrder interface { 310 Element(*[Bytes]byte) ({{.ElementName}}, error) 311 PutElement(*[Bytes]byte, {{.ElementName}}) 312 String() string 313 } 314 315 316 // BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. 317 var BigEndian bigEndian 318 319 type bigEndian struct{} 320 321 // Element interpret b is a big-endian {{.NbBytes}}-byte slice. 322 // If b encodes a value higher than q, Element returns error. 323 func (bigEndian) Element(b *[Bytes]byte) ({{.ElementName}}, error) { 324 var z {{.ElementName}} 325 {{- range $i := reverse .NbWordsIndexesFull}} 326 {{- $j := mul $i 8}} 327 {{- $k := sub $.NbWords 1}} 328 {{- $k := sub $k $i}} 329 {{- $jj := add $j 8}} 330 z[{{$k}}] = binary.BigEndian.Uint64((*b)[{{$j}}:{{$jj}}]) 331 {{- end}} 332 333 if !z.smallerThanModulus() { 334 return {{.ElementName}}{}, errors.New("invalid {{.PackageName}}.{{.ElementName}} encoding") 335 } 336 337 z.toMont() 338 return z, nil 339 } 340 341 func (bigEndian) PutElement(b *[Bytes]byte, e {{.ElementName}}) { 342 e.fromMont() 343 344 {{- range $i := reverse .NbWordsIndexesFull}} 345 {{- $j := mul $i 8}} 346 {{- $k := sub $.NbWords 1}} 347 {{- $k := sub $k $i}} 348 {{- $jj := add $j 8}} 349 binary.BigEndian.PutUint64((*b)[{{$j}}:{{$jj}}], e[{{$k}}]) 350 {{- end}} 351 } 352 353 func (bigEndian) String() string { return "BigEndian" } 354 355 356 357 // LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. 358 var LittleEndian littleEndian 359 360 type littleEndian struct{} 361 362 func (littleEndian) Element(b *[Bytes]byte) ({{.ElementName}}, error) { 363 var z {{.ElementName}} 364 {{- range $i := .NbWordsIndexesFull}} 365 {{- $j := mul $i 8}} 366 {{- $jj := add $j 8}} 367 z[{{$i}}] = binary.LittleEndian.Uint64((*b)[{{$j}}:{{$jj}}]) 368 {{- end}} 369 370 if !z.smallerThanModulus() { 371 return {{.ElementName}}{}, errors.New("invalid {{.PackageName}}.{{.ElementName}} encoding") 372 } 373 374 z.toMont() 375 return z, nil 376 } 377 378 func (littleEndian) PutElement(b *[Bytes]byte, e {{.ElementName}}) { 379 e.fromMont() 380 381 {{- range $i := .NbWordsIndexesFull}} 382 {{- $j := mul $i 8}} 383 {{- $jj := add $j 8}} 384 binary.LittleEndian.PutUint64((*b)[{{$j}}:{{$jj}}], e[{{$i}}]) 385 {{- end}} 386 } 387 388 func (littleEndian) String() string { return "LittleEndian" } 389 390 391 392 393 `