Prad Nukala 807b2e86ec
feature/1220 origin handle exists method (#1241)
* feat: add docs and CI workflow for publishing to onsonr.dev

* (refactor): Move hway,motr executables to their own repos

* feat: simplify devnet and testnet configurations

* refactor: update import path for didcrypto package

* docs(networks): Add README with project overview, architecture, and community links

* refactor: Move network configurations to deploy directory

* build: update golang version to 1.23

* refactor: move logger interface to appropriate package

* refactor: Move devnet configuration to networks/devnet

* chore: improve release process with date variable

* (chore): Move Crypto Library

* refactor: improve code structure and readability in DID module

* feat: integrate Trunk CI checks

* ci: optimize CI workflow by removing redundant build jobs

---------

Co-authored-by: Darp Alakun <i@prad.nu>
2025-01-06 17:06:10 +00:00

435 lines
10 KiB
Go
Executable File

package bls12381
import (
"io"
"github.com/onsonr/sonr/crypto/core/curves/native"
"github.com/onsonr/sonr/crypto/internal"
)
// GtFieldBytes is the number of bytes needed to represent this field
const GtFieldBytes = 576
// Gt is the target group
type Gt fp12
// Random generates a random field element
func (gt *Gt) Random(reader io.Reader) (*Gt, error) {
_, err := (*fp12)(gt).Random(reader)
return gt, err
}
// FinalExponentiation performs a "final exponentiation" routine to convert the result
// of a Miller loop into an element of `Gt` with help of efficient squaring
// operation in the so-called `cyclotomic subgroup` of `Fq6` so that
// it can be compared with other elements of `Gt`.
func (gt *Gt) FinalExponentiation(a *Gt) *Gt {
var t0, t1, t2, t3, t4, t5, t6, t fp12
t0.FrobeniusMap((*fp12)(a))
t0.FrobeniusMap(&t0)
t0.FrobeniusMap(&t0)
t0.FrobeniusMap(&t0)
t0.FrobeniusMap(&t0)
t0.FrobeniusMap(&t0)
// Shouldn't happen since we enforce `a` to be non-zero but just in case
_, wasInverted := t1.Invert((*fp12)(a))
t2.Mul(&t0, &t1)
t1.Set(&t2)
t2.FrobeniusMap(&t2)
t2.FrobeniusMap(&t2)
t2.Mul(&t2, &t1)
t1.cyclotomicSquare(&t2)
t1.Conjugate(&t1)
t3.cyclotomicExp(&t2)
t4.cyclotomicSquare(&t3)
t5.Mul(&t1, &t3)
t1.cyclotomicExp(&t5)
t0.cyclotomicExp(&t1)
t6.cyclotomicExp(&t0)
t6.Mul(&t6, &t4)
t4.cyclotomicExp(&t6)
t5.Conjugate(&t5)
t4.Mul(&t4, &t5)
t4.Mul(&t4, &t2)
t5.Conjugate(&t2)
t1.Mul(&t1, &t2)
t1.FrobeniusMap(&t1)
t1.FrobeniusMap(&t1)
t1.FrobeniusMap(&t1)
t6.Mul(&t6, &t5)
t6.FrobeniusMap(&t6)
t3.Mul(&t3, &t0)
t3.FrobeniusMap(&t3)
t3.FrobeniusMap(&t3)
t3.Mul(&t3, &t1)
t3.Mul(&t3, &t6)
t.Mul(&t3, &t4)
(*fp12)(gt).CMove((*fp12)(gt), &t, wasInverted)
return gt
}
// IsZero returns 1 if gt == 0, 0 otherwise
func (gt *Gt) IsZero() int {
return (*fp12)(gt).IsZero()
}
// IsOne returns 1 if gt == 1, 0 otherwise
func (gt *Gt) IsOne() int {
return (*fp12)(gt).IsOne()
}
// SetOne gt = one
func (gt *Gt) SetOne() *Gt {
(*fp12)(gt).SetOne()
return gt
}
// Set copies a into gt
func (gt *Gt) Set(a *Gt) *Gt {
gt.A.Set(&a.A)
gt.B.Set(&a.B)
return gt
}
// Bytes returns the Gt field byte representation
func (gt *Gt) Bytes() [GtFieldBytes]byte {
var out [GtFieldBytes]byte
t := gt.A.A.A.Bytes()
copy(out[:FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.A.A.B.Bytes()
copy(out[FieldBytes:2*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.A.B.A.Bytes()
copy(out[2*FieldBytes:3*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.A.B.B.Bytes()
copy(out[3*FieldBytes:4*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.A.C.A.Bytes()
copy(out[4*FieldBytes:5*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.A.C.B.Bytes()
copy(out[5*FieldBytes:6*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.B.A.A.Bytes()
copy(out[6*FieldBytes:7*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.B.A.B.Bytes()
copy(out[7*FieldBytes:8*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.B.B.A.Bytes()
copy(out[8*FieldBytes:9*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.B.B.B.Bytes()
copy(out[9*FieldBytes:10*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.B.C.A.Bytes()
copy(out[10*FieldBytes:11*FieldBytes], internal.ReverseScalarBytes(t[:]))
t = gt.B.C.B.Bytes()
copy(out[11*FieldBytes:12*FieldBytes], internal.ReverseScalarBytes(t[:]))
return out
}
// SetBytes attempts to convert a big-endian byte representation of
// a scalar into a `Gt`, failing if the input is not canonical.
func (gt *Gt) SetBytes(input *[GtFieldBytes]byte) (*Gt, int) {
var t [FieldBytes]byte
var valid [12]int
copy(t[:], internal.ReverseScalarBytes(input[:FieldBytes]))
_, valid[0] = gt.A.A.A.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[FieldBytes:2*FieldBytes]))
_, valid[1] = gt.A.A.B.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[2*FieldBytes:3*FieldBytes]))
_, valid[2] = gt.A.B.A.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[3*FieldBytes:4*FieldBytes]))
_, valid[3] = gt.A.B.B.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[4*FieldBytes:5*FieldBytes]))
_, valid[4] = gt.A.C.A.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[5*FieldBytes:6*FieldBytes]))
_, valid[5] = gt.A.C.B.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[6*FieldBytes:7*FieldBytes]))
_, valid[6] = gt.B.A.A.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[7*FieldBytes:8*FieldBytes]))
_, valid[7] = gt.B.A.B.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[8*FieldBytes:9*FieldBytes]))
_, valid[8] = gt.B.B.A.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[9*FieldBytes:10*FieldBytes]))
_, valid[9] = gt.B.B.B.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[10*FieldBytes:11*FieldBytes]))
_, valid[10] = gt.B.C.A.SetBytes(&t)
copy(t[:], internal.ReverseScalarBytes(input[11*FieldBytes:12*FieldBytes]))
_, valid[11] = gt.B.C.B.SetBytes(&t)
return gt, valid[0] & valid[1] &
valid[2] & valid[3] &
valid[4] & valid[5] &
valid[6] & valid[7] &
valid[8] & valid[9] &
valid[10] & valid[11]
}
// Equal returns 1 if gt == rhs, 0 otherwise
func (gt *Gt) Equal(rhs *Gt) int {
return (*fp12)(gt).Equal((*fp12)(rhs))
}
// Generator returns the base point
func (gt *Gt) Generator() *Gt {
// pairing(&G1::generator(), &G2::generator())
gt.Set((*Gt)(&fp12{
A: fp6{
A: fp2{
A: fp{
0x1972e433a01f85c5,
0x97d32b76fd772538,
0xc8ce546fc96bcdf9,
0xcef63e7366d40614,
0xa611342781843780,
0x13f3448a3fc6d825,
},
B: fp{
0xd26331b02e9d6995,
0x9d68a482f7797e7d,
0x9c9b29248d39ea92,
0xf4801ca2e13107aa,
0xa16c0732bdbcb066,
0x083ca4afba360478,
},
},
B: fp2{
A: fp{
0x59e261db0916b641,
0x2716b6f4b23e960d,
0xc8e55b10a0bd9c45,
0x0bdb0bd99c4deda8,
0x8cf89ebf57fdaac5,
0x12d6b7929e777a5e,
},
B: fp{
0x5fc85188b0e15f35,
0x34a06e3a8f096365,
0xdb3126a6e02ad62c,
0xfc6f5aa97d9a990b,
0xa12f55f5eb89c210,
0x1723703a926f8889,
},
},
C: fp2{
A: fp{
0x93588f2971828778,
0x43f65b8611ab7585,
0x3183aaf5ec279fdf,
0xfa73d7e18ac99df6,
0x64e176a6a64c99b0,
0x179fa78c58388f1f,
},
B: fp{
0x672a0a11ca2aef12,
0x0d11b9b52aa3f16b,
0xa44412d0699d056e,
0xc01d0177221a5ba5,
0x66e0cede6c735529,
0x05f5a71e9fddc339,
},
},
},
B: fp6{
A: fp2{
A: fp{
0xd30a88a1b062c679,
0x5ac56a5d35fc8304,
0xd0c834a6a81f290d,
0xcd5430c2da3707c7,
0xf0c27ff780500af0,
0x09245da6e2d72eae,
},
B: fp{
0x9f2e0676791b5156,
0xe2d1c8234918fe13,
0x4c9e459f3c561bf4,
0xa3e85e53b9d3e3c1,
0x820a121e21a70020,
0x15af618341c59acc,
},
},
B: fp2{
A: fp{
0x7c95658c24993ab1,
0x73eb38721ca886b9,
0x5256d749477434bc,
0x8ba41902ea504a8b,
0x04a3d3f80c86ce6d,
0x18a64a87fb686eaa,
},
B: fp{
0xbb83e71bb920cf26,
0x2a5277ac92a73945,
0xfc0ee59f94f046a0,
0x7158cdf3786058f7,
0x7cc1061b82f945f6,
0x03f847aa9fdbe567,
},
},
C: fp2{
A: fp{
0x8078dba56134e657,
0x1cd7ec9a43998a6e,
0xb1aa599a1a993766,
0xc9a0f62f0842ee44,
0x8e159be3b605dffa,
0x0c86ba0d4af13fc2,
},
B: fp{
0xe80ff2a06a52ffb1,
0x7694ca48721a906c,
0x7583183e03b08514,
0xf567afdd40cee4e2,
0x9a6d96d2e526a5fc,
0x197e9f49861f2242,
},
},
},
}))
return gt
}
// Add adds this value to another value.
func (gt *Gt) Add(arg1, arg2 *Gt) *Gt {
(*fp12)(gt).Mul((*fp12)(arg1), (*fp12)(arg2))
return gt
}
// Double this value
func (gt *Gt) Double(a *Gt) *Gt {
(*fp12)(gt).Square((*fp12)(a))
return gt
}
// Sub subtracts the two values
func (gt *Gt) Sub(arg1, arg2 *Gt) *Gt {
var t fp12
t.Conjugate((*fp12)(arg2))
(*fp12)(gt).Mul((*fp12)(arg1), &t)
return gt
}
// Neg negates this value
func (gt *Gt) Neg(a *Gt) *Gt {
(*fp12)(gt).Conjugate((*fp12)(a))
return gt
}
// Mul multiplies this value by the input scalar
func (gt *Gt) Mul(a *Gt, s *native.Field) *Gt {
var f, p fp12
f.Set((*fp12)(a))
bytes := s.Bytes()
precomputed := [16]fp12{}
precomputed[1].Set(&f)
for i := 2; i < 16; i += 2 {
precomputed[i].Square(&precomputed[i>>1])
precomputed[i+1].Mul(&precomputed[i], &f)
}
for i := 0; i < 256; i += 4 {
// Brouwer / windowing method. window size of 4.
for j := 0; j < 4; j++ {
p.Square(&p)
}
window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F
p.Mul(&p, &precomputed[window])
}
(*fp12)(gt).Set(&p)
return gt
}
// Square this value
func (gt *Gt) Square(a *Gt) *Gt {
(*fp12)(gt).cyclotomicSquare((*fp12)(a))
return gt
}
// Invert this value
func (gt *Gt) Invert(a *Gt) (*Gt, int) {
_, wasInverted := (*fp12)(gt).Invert((*fp12)(a))
return gt, wasInverted
}
func fp4Square(a, b, arg1, arg2 *fp2) {
var t0, t1, t2 fp2
t0.Square(arg1)
t1.Square(arg2)
t2.MulByNonResidue(&t1)
a.Add(&t2, &t0)
t2.Add(arg1, arg2)
t2.Square(&t2)
t2.Sub(&t2, &t0)
b.Sub(&t2, &t1)
}
func (f *fp12) cyclotomicSquare(a *fp12) *fp12 {
// Adaptation of Algorithm 5.5.4, Guide to Pairing-Based Cryptography
// Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions
// https://eprint.iacr.org/2009/565.pdf
var z0, z1, z2, z3, z4, z5, t0, t1, t2, t3 fp2
z0.Set(&a.A.A)
z4.Set(&a.A.B)
z3.Set(&a.A.C)
z2.Set(&a.B.A)
z1.Set(&a.B.B)
z5.Set(&a.B.C)
fp4Square(&t0, &t1, &z0, &z1)
z0.Sub(&t0, &z0)
z0.Double(&z0)
z0.Add(&z0, &t0)
z1.Add(&t1, &z1)
z1.Double(&z1)
z1.Add(&z1, &t1)
fp4Square(&t0, &t1, &z2, &z3)
fp4Square(&t2, &t3, &z4, &z5)
z4.Sub(&t0, &z4)
z4.Double(&z4)
z4.Add(&z4, &t0)
z5.Add(&z5, &t1)
z5.Double(&z5)
z5.Add(&z5, &t1)
t0.MulByNonResidue(&t3)
z2.Add(&z2, &t0)
z2.Double(&z2)
z2.Add(&z2, &t0)
z3.Sub(&t2, &z3)
z3.Double(&z3)
z3.Add(&z3, &t2)
f.A.A.Set(&z0)
f.A.B.Set(&z4)
f.A.C.Set(&z3)
f.B.A.Set(&z2)
f.B.B.Set(&z1)
f.B.C.Set(&z5)
return f
}
func (f *fp12) cyclotomicExp(a *fp12) *fp12 {
var t fp12
t.SetOne()
foundOne := 0
for i := 63; i >= 0; i-- {
b := int((paramX >> i) & 1)
if foundOne == 1 {
t.cyclotomicSquare(&t)
} else {
foundOne = b
}
if b == 1 {
t.Mul(&t, a)
}
}
f.Conjugate(&t)
return f
}