Files
crypto/core/curves/native/p256/fq/fq.go

511 lines
13 KiB
Go
Raw Normal View History

2025-10-09 15:10:39 -04:00
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package fq
import (
"math/big"
"sync"
"github.com/sonr-io/crypto/core/curves/native"
2025-10-09 15:10:39 -04:00
)
var (
p256FqInitonce sync.Once
p256FqParams native.FieldParams
)
func P256FqNew() *native.Field {
return &native.Field{
Value: [native.FieldLimbs]uint64{},
Params: getP256FqParams(),
Arithmetic: p256FqArithmetic{},
}
}
func p256FqParamsInit() {
// See FIPS 186-3, section D.2.3
p256FqParams = native.FieldParams{
R: [native.FieldLimbs]uint64{
0x0c46353d039cdaaf,
0x4319055258e8617b,
0x0000000000000000,
0x00000000ffffffff,
},
R2: [native.FieldLimbs]uint64{
0x83244c95be79eea2,
0x4699799c49bd6fa6,
0x2845b2392b6bec59,
0x66e12d94f3d95620,
},
R3: [native.FieldLimbs]uint64{
0xac8ebec90b65a624,
0x111f28ae0c0555c9,
0x2543b9246ba5e93f,
0x503a54e76407be65,
},
Modulus: [native.FieldLimbs]uint64{
0xf3b9cac2fc632551,
0xbce6faada7179e84,
0xffffffffffffffff,
0xffffffff00000000,
},
BiModulus: new(big.Int).SetBytes([]byte{
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
}),
}
}
func getP256FqParams() *native.FieldParams {
p256FqInitonce.Do(p256FqParamsInit)
return &p256FqParams
}
// p256FqArithmetic is a struct with all the methods needed for working
// in mod q
type p256FqArithmetic struct{}
// ToMontgomery converts this field to montgomery form
func (f p256FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) {
ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg))
}
// FromMontgomery converts this field from montgomery form
func (f p256FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) {
FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
}
// Neg performs modular negation
func (f p256FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) {
Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
}
// Square performs modular square
func (f p256FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) {
Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg))
}
// Mul performs modular multiplication
func (f p256FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) {
Mul(
(*MontgomeryDomainFieldElement)(out),
(*MontgomeryDomainFieldElement)(arg1),
(*MontgomeryDomainFieldElement)(arg2),
)
}
// Add performs modular addition
func (f p256FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) {
Add(
(*MontgomeryDomainFieldElement)(out),
(*MontgomeryDomainFieldElement)(arg1),
(*MontgomeryDomainFieldElement)(arg2),
)
}
// Sub performs modular subtraction
func (f p256FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) {
Sub(
(*MontgomeryDomainFieldElement)(out),
(*MontgomeryDomainFieldElement)(arg1),
(*MontgomeryDomainFieldElement)(arg2),
)
}
// Sqrt performs modular square root
func (f p256FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) {
// See sqrt_ts_ct at
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4
// c1 := s
// c2 := (q - 1) / (2^c1)
// c2 := [4]uint64{
// 0x4f3b9cac2fc63255,
// 0xfbce6faada7179e8,
// 0x0fffffffffffffff,
// 0x0ffffffff0000000,
// }
// c3 := (c2 - 1) / 2
c3 := [native.FieldLimbs]uint64{
0x279dce5617e3192a,
0xfde737d56d38bcf4,
0x07ffffffffffffff,
0x07fffffff8000000,
}
// c4 := generator
// c5 := new(Fq).pow(generator, c2)
c5 := [native.FieldLimbs]uint64{
0x1015708f7e368fe1,
0x31c6c5456ecc4511,
0x5281fe8998a19ea1,
0x0279089e10c63fe8,
}
var z, t, b, c, tv [native.FieldLimbs]uint64
native.Pow(&z, arg, &c3, getP256FqParams(), f)
Square((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&z))
Mul(
(*MontgomeryDomainFieldElement)(&t),
(*MontgomeryDomainFieldElement)(&t),
(*MontgomeryDomainFieldElement)(arg),
)
Mul(
(*MontgomeryDomainFieldElement)(&z),
(*MontgomeryDomainFieldElement)(&z),
(*MontgomeryDomainFieldElement)(arg),
)
copy(b[:], t[:])
copy(c[:], c5[:])
for i := s; i >= 2; i-- {
for j := 1; j <= i-2; j++ {
Square((*MontgomeryDomainFieldElement)(&b), (*MontgomeryDomainFieldElement)(&b))
}
// if b == 1 flag = 0 else flag = 1
flag := -(&native.Field{
Value: b,
Params: getP256FqParams(),
Arithmetic: f,
}).IsOne() + 1
Mul(
(*MontgomeryDomainFieldElement)(&tv),
(*MontgomeryDomainFieldElement)(&z),
(*MontgomeryDomainFieldElement)(&c),
)
Selectznz(&z, uint1(flag), &z, &tv)
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&c))
Mul(
(*MontgomeryDomainFieldElement)(&tv),
(*MontgomeryDomainFieldElement)(&t),
(*MontgomeryDomainFieldElement)(&c),
)
Selectznz(&t, uint1(flag), &t, &tv)
copy(b[:], t[:])
}
Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&z))
*wasSquare = (&native.Field{
Value: c,
Params: getP256FqParams(),
Arithmetic: f,
}).Equal(&native.Field{
Value: *arg,
Params: getP256FqParams(),
Arithmetic: f,
})
Selectznz(out, uint1(*wasSquare), out, &z)
}
// Invert performs modular inverse
func (f p256FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) {
// Using an addition chain from
// https://briansmith.org/ecc-inversion-addition-chains-01#p256_field_inversion
var x1, x10, x11, x101, x111, x1010, x1111, x10101, x101010, x101111 [native.FieldLimbs]uint64
var x6, x8, x16, x32, tmp [native.FieldLimbs]uint64
copy(x1[:], arg[:])
native.Pow2k(&x10, arg, 1, f)
Mul(
(*MontgomeryDomainFieldElement)(&x11),
(*MontgomeryDomainFieldElement)(&x10),
(*MontgomeryDomainFieldElement)(&x1),
)
Mul(
(*MontgomeryDomainFieldElement)(&x101),
(*MontgomeryDomainFieldElement)(&x10),
(*MontgomeryDomainFieldElement)(&x11),
)
Mul(
(*MontgomeryDomainFieldElement)(&x111),
(*MontgomeryDomainFieldElement)(&x10),
(*MontgomeryDomainFieldElement)(&x101),
)
native.Pow2k(&x1010, &x101, 1, f)
Mul(
(*MontgomeryDomainFieldElement)(&x1111),
(*MontgomeryDomainFieldElement)(&x101),
(*MontgomeryDomainFieldElement)(&x1010),
)
native.Pow2k(&x10101, &x1010, 1, f)
Mul(
(*MontgomeryDomainFieldElement)(&x10101),
(*MontgomeryDomainFieldElement)(&x10101),
(*MontgomeryDomainFieldElement)(&x1),
)
native.Pow2k(&x101010, &x10101, 1, f)
Mul(
(*MontgomeryDomainFieldElement)(&x101111),
(*MontgomeryDomainFieldElement)(&x101),
(*MontgomeryDomainFieldElement)(&x101010),
)
Mul(
(*MontgomeryDomainFieldElement)(&x6),
(*MontgomeryDomainFieldElement)(&x10101),
(*MontgomeryDomainFieldElement)(&x101010),
)
native.Pow2k(&x8, &x6, 2, f)
Mul(
(*MontgomeryDomainFieldElement)(&x8),
(*MontgomeryDomainFieldElement)(&x8),
(*MontgomeryDomainFieldElement)(&x11),
)
native.Pow2k(&x16, &x8, 8, f)
Mul(
(*MontgomeryDomainFieldElement)(&x16),
(*MontgomeryDomainFieldElement)(&x16),
(*MontgomeryDomainFieldElement)(&x8),
)
native.Pow2k(&x32, &x16, 16, f)
Mul(
(*MontgomeryDomainFieldElement)(&x32),
(*MontgomeryDomainFieldElement)(&x32),
(*MontgomeryDomainFieldElement)(&x16),
)
native.Pow2k(&tmp, &x32, 64, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x32),
)
native.Pow2k(&tmp, &tmp, 32, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x32),
)
native.Pow2k(&tmp, &tmp, 6, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101111),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x111),
)
native.Pow2k(&tmp, &tmp, 4, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x11),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1111),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x10101),
)
native.Pow2k(&tmp, &tmp, 4, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101),
)
native.Pow2k(&tmp, &tmp, 3, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101),
)
native.Pow2k(&tmp, &tmp, 3, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x111),
)
native.Pow2k(&tmp, &tmp, 9, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101111),
)
native.Pow2k(&tmp, &tmp, 6, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1111),
)
native.Pow2k(&tmp, &tmp, 2, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1),
)
native.Pow2k(&tmp, &tmp, 6, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1111),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x111),
)
native.Pow2k(&tmp, &tmp, 4, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x111),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x111),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101),
)
native.Pow2k(&tmp, &tmp, 3, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x11),
)
native.Pow2k(&tmp, &tmp, 10, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x101111),
)
native.Pow2k(&tmp, &tmp, 2, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x11),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x11),
)
native.Pow2k(&tmp, &tmp, 5, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x11),
)
native.Pow2k(&tmp, &tmp, 3, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1),
)
native.Pow2k(&tmp, &tmp, 7, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x10101),
)
native.Pow2k(&tmp, &tmp, 6, f)
Mul(
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&tmp),
(*MontgomeryDomainFieldElement)(&x1111),
)
*wasInverted = (&native.Field{
Value: *arg,
Params: getP256FqParams(),
Arithmetic: f,
}).IsNonZero()
Selectznz(out, uint1(*wasInverted), out, &tmp)
}
// FromBytes converts a little endian byte array into a field element
func (f p256FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) {
FromBytes(out, arg)
}
// ToBytes converts a field element to a little endian byte array
func (f p256FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) {
ToBytes(out, arg)
}
// Selectznz performs conditional select.
// selects arg1 if choice == 0 and arg2 if choice == 1
func (f p256FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) {
Selectznz(out, uint1(choice), arg1, arg2)
}
// generator = 7 mod q is a generator of the `q - 1` order multiplicative
// subgroup, or in other words a primitive element of the field.
// generator^t where t * 2^s + 1 = q
var generator = &[native.FieldLimbs]uint64{
0x55eb74ab1949fac9,
0xd5af25406e5aaa5d,
0x0000000000000001,
0x00000006fffffff9,
}
// s satisfies the equation 2^s * t = q - 1 with t odd.
var s = 4
// rootOfUnity
var rootOfUnity = &[native.FieldLimbs]uint64{
0x0592d7fbb41e6602,
0x1546cad004378daf,
0xba807ace842a3dfc,
0xffc97f062a770992,
}