mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-26 00:25:17 +00:00
541 lines
16 KiB
Go
541 lines
16 KiB
Go
package feldman
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
|
|
"source.quilibrium.com/quilibrium/ceremonyclient/ec/bls48581"
|
|
)
|
|
|
|
// This will not be used in the initial ceremony, but will be used in a end of ceremony event
|
|
type FeldmanECP struct {
|
|
threshold int
|
|
total int
|
|
id int
|
|
fragsForCounterparties map[int][]byte
|
|
fragsFromCounterparties map[int]*bls48581.BIG
|
|
zkpok *bls48581.BIG
|
|
secret *bls48581.BIG
|
|
scalar *bls48581.BIG
|
|
publicKey *bls48581.ECP
|
|
point *bls48581.ECP
|
|
randomCommitmentPoint *bls48581.ECP
|
|
round FeldmanRound
|
|
zkcommitsFromCounterparties map[int][]byte
|
|
pointsFromCounterparties map[int]*bls48581.ECP
|
|
}
|
|
|
|
type FeldmanReveal struct {
|
|
Point []byte
|
|
RandomCommitmentPoint []byte
|
|
ZKPoK []byte
|
|
}
|
|
|
|
type FeldmanECP8 struct {
|
|
threshold int
|
|
total int
|
|
id int
|
|
fragsForCounterparties map[int][]byte
|
|
fragsFromCounterparties map[int]*bls48581.BIG
|
|
zkpok *bls48581.BIG
|
|
secret *bls48581.BIG
|
|
scalar *bls48581.BIG
|
|
publicKey *bls48581.ECP8
|
|
point *bls48581.ECP8
|
|
randomCommitmentPoint *bls48581.ECP8
|
|
round FeldmanRound
|
|
zkcommitsFromCounterparties map[int][]byte
|
|
pointsFromCounterparties map[int]*bls48581.ECP8
|
|
}
|
|
|
|
type FeldmanRound int
|
|
|
|
const (
|
|
FELDMAN_ROUND_UNINITIALIZED = FeldmanRound(0)
|
|
FELDMAN_ROUND_INITIALIZED = FeldmanRound(1)
|
|
FELDMAN_ROUND_COMMITTED = FeldmanRound(2)
|
|
FELDMAN_ROUND_REVEALED = FeldmanRound(3)
|
|
FELDMAN_ROUND_RECONSTRUCTED = FeldmanRound(4)
|
|
)
|
|
|
|
func NewFeldmanECP(threshold, total, id int, secret *bls48581.BIG) (*FeldmanECP, error) {
|
|
return &FeldmanECP{
|
|
threshold: threshold,
|
|
total: total,
|
|
id: id,
|
|
fragsForCounterparties: make(map[int][]byte),
|
|
fragsFromCounterparties: make(map[int]*bls48581.BIG),
|
|
zkpok: nil,
|
|
secret: secret,
|
|
scalar: nil,
|
|
publicKey: bls48581.ECP_generator(),
|
|
point: bls48581.ECP_generator(),
|
|
round: FELDMAN_ROUND_UNINITIALIZED,
|
|
zkcommitsFromCounterparties: make(map[int][]byte),
|
|
pointsFromCounterparties: make(map[int]*bls48581.ECP),
|
|
}, nil
|
|
}
|
|
|
|
func NewFeldmanECP8(threshold, total, id int, secret *bls48581.BIG) (*FeldmanECP8, error) {
|
|
return &FeldmanECP8{
|
|
threshold: threshold,
|
|
total: total,
|
|
id: id,
|
|
fragsForCounterparties: make(map[int][]byte),
|
|
fragsFromCounterparties: make(map[int]*bls48581.BIG),
|
|
zkpok: nil,
|
|
secret: secret,
|
|
scalar: nil,
|
|
publicKey: bls48581.ECP8_generator(),
|
|
point: bls48581.ECP8_generator(),
|
|
round: FELDMAN_ROUND_UNINITIALIZED,
|
|
zkcommitsFromCounterparties: make(map[int][]byte),
|
|
pointsFromCounterparties: make(map[int]*bls48581.ECP8),
|
|
}, nil
|
|
}
|
|
|
|
func (f *FeldmanECP) SamplePolynomial() {
|
|
coeffs := append([]*bls48581.BIG{}, f.secret)
|
|
|
|
for i := 0; i < f.threshold-1; i++ {
|
|
secretBytes := make([]byte, int(bls48581.MODBYTES))
|
|
rand.Read(secretBytes)
|
|
secret := bls48581.FromBytes(secretBytes)
|
|
coeffs = append(coeffs, secret)
|
|
}
|
|
|
|
for i := 1; i <= f.total; i++ {
|
|
result := coeffs[len(coeffs)-1]
|
|
|
|
for j := len(coeffs) - 2; j >= 0; j-- {
|
|
result = bls48581.Modadd(
|
|
coeffs[j],
|
|
bls48581.Modmul(
|
|
result,
|
|
bls48581.NewBIGint(i),
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
),
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
}
|
|
|
|
if i == f.id {
|
|
f.scalar = result
|
|
} else {
|
|
fragBytes := make([]byte, int(bls48581.MODBYTES))
|
|
result.ToBytes(fragBytes)
|
|
f.fragsForCounterparties[i] = fragBytes
|
|
}
|
|
}
|
|
|
|
f.round = FELDMAN_ROUND_INITIALIZED
|
|
}
|
|
|
|
func (f *FeldmanECP) Scalar() *bls48581.BIG {
|
|
return f.scalar
|
|
}
|
|
|
|
func (f *FeldmanECP) GetPolyFrags() map[int][]byte {
|
|
return f.fragsForCounterparties
|
|
}
|
|
|
|
func (f *FeldmanECP) SetPolyFragForParty(id int, frag []byte) []byte {
|
|
f.fragsFromCounterparties[id] = bls48581.FromBytes(frag)
|
|
|
|
if len(f.fragsFromCounterparties) == f.total-1 {
|
|
for _, v := range f.fragsFromCounterparties {
|
|
f.scalar = bls48581.Modadd(f.scalar, v, bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
}
|
|
|
|
f.point = f.point.Mul(f.scalar)
|
|
|
|
randCommitmentBytes := make([]byte, int(bls48581.MODBYTES))
|
|
rand.Read(randCommitmentBytes)
|
|
randCommitment := bls48581.FromBytes(randCommitmentBytes)
|
|
f.randomCommitmentPoint = f.publicKey.Mul(randCommitment)
|
|
|
|
publicPointBytes := make([]byte, bls48581.MODBYTES+1)
|
|
randCommitmentPointBytes := make([]byte, bls48581.MODBYTES+1)
|
|
f.point.ToBytes(publicPointBytes, true)
|
|
f.randomCommitmentPoint.ToBytes(randCommitmentPointBytes, true)
|
|
|
|
challenge := sha256.Sum256(append(append([]byte{}, publicPointBytes...), randCommitmentPointBytes...))
|
|
challengeBig := bls48581.FromBytes(challenge[:])
|
|
challengeBig.Mod(bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
|
|
f.zkpok = bls48581.Modadd(
|
|
bls48581.Modmul(
|
|
f.scalar,
|
|
challengeBig,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
),
|
|
randCommitment,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
|
|
zkpokBytes := make([]byte, int(bls48581.MODBYTES))
|
|
f.zkpok.ToBytes(zkpokBytes)
|
|
zkcommit := sha256.Sum256(append(append([]byte{}, randCommitmentPointBytes...), zkpokBytes...))
|
|
|
|
f.round = FELDMAN_ROUND_COMMITTED
|
|
return zkcommit[:]
|
|
}
|
|
|
|
return []byte{}
|
|
}
|
|
|
|
func (f *FeldmanECP) ReceiveCommitments(id int, zkcommit []byte) *FeldmanReveal {
|
|
f.zkcommitsFromCounterparties[id] = zkcommit
|
|
|
|
if len(f.zkcommitsFromCounterparties) == f.total-1 {
|
|
publicPointBytes := make([]byte, bls48581.MODBYTES+1)
|
|
randCommitmentPointBytes := make([]byte, bls48581.MODBYTES+1)
|
|
f.point.ToBytes(publicPointBytes, true)
|
|
f.randomCommitmentPoint.ToBytes(randCommitmentPointBytes, true)
|
|
f.round = FELDMAN_ROUND_REVEALED
|
|
zkpokBytes := make([]byte, int(bls48581.MODBYTES))
|
|
f.zkpok.ToBytes(zkpokBytes)
|
|
|
|
return &FeldmanReveal{
|
|
Point: publicPointBytes,
|
|
RandomCommitmentPoint: randCommitmentPointBytes,
|
|
ZKPoK: zkpokBytes,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *FeldmanECP) Recombine(id int, reveal *FeldmanReveal) {
|
|
counterpartyPoint := bls48581.ECP_fromBytes(reveal.Point)
|
|
if counterpartyPoint.Equals(bls48581.ECP_generator()) {
|
|
fmt.Printf("invalid point from %d", id)
|
|
return
|
|
}
|
|
|
|
counterpartyRandomCommitmentPoint := bls48581.ECP_fromBytes(reveal.RandomCommitmentPoint)
|
|
if counterpartyRandomCommitmentPoint.Equals(bls48581.ECP_generator()) {
|
|
fmt.Printf("invalid commitment point from %d", id)
|
|
return
|
|
}
|
|
|
|
counterpartyZKPoK := bls48581.FromBytes(reveal.ZKPoK)
|
|
counterpartyZKCommit := f.zkcommitsFromCounterparties[id]
|
|
|
|
challenge := sha256.Sum256(append(append([]byte{}, reveal.Point...), reveal.RandomCommitmentPoint...))
|
|
challengeBig := bls48581.FromBytes(challenge[:])
|
|
challengeBig.Mod(bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
|
|
proof := f.publicKey.Mul(counterpartyZKPoK)
|
|
counterpartyRandomCommitmentPoint.Add(counterpartyPoint.Mul(challengeBig))
|
|
|
|
if !proof.Equals(counterpartyRandomCommitmentPoint) {
|
|
fmt.Printf("invalid proof from %d", id)
|
|
return
|
|
}
|
|
|
|
verifier := sha256.Sum256(append(append([]byte{}, reveal.RandomCommitmentPoint...), reveal.ZKPoK...))
|
|
if !bytes.Equal(counterpartyZKCommit, verifier[:]) {
|
|
fmt.Printf("%d changed zkpok after commit", id)
|
|
return
|
|
}
|
|
|
|
f.pointsFromCounterparties[id] = counterpartyPoint
|
|
|
|
if len(f.pointsFromCounterparties) == f.total-1 {
|
|
f.pointsFromCounterparties[f.id] = f.point
|
|
|
|
for i := 1; i <= f.total-f.threshold; i++ {
|
|
reconstructedSum := bls48581.ECP_generator()
|
|
|
|
for j := i; j <= f.threshold+i; j++ {
|
|
coefficientNumerator := bls48581.NewBIGint(1)
|
|
coefficientDenominator := bls48581.NewBIGint(1)
|
|
|
|
for k := i; k <= f.threshold+i; k++ {
|
|
if j != k {
|
|
k := bls48581.NewBIGint(k)
|
|
|
|
coefficientNumerator = bls48581.Modmul(
|
|
coefficientNumerator,
|
|
k,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
kj := bls48581.Modadd(
|
|
k,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order).Minus(bls48581.NewBIGint(j)),
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
coefficientDenominator = bls48581.Modmul(
|
|
coefficientDenominator,
|
|
kj,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
}
|
|
}
|
|
|
|
coefficientDenominator.Invmodp(bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
|
|
reconstructedFragment := f.pointsFromCounterparties[j].Mul(
|
|
bls48581.Modmul(
|
|
coefficientNumerator,
|
|
coefficientDenominator,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
),
|
|
)
|
|
|
|
if reconstructedSum.Equals(bls48581.ECP_generator()) {
|
|
reconstructedSum = reconstructedFragment
|
|
} else {
|
|
reconstructedSum.Add(reconstructedFragment)
|
|
}
|
|
}
|
|
|
|
if f.publicKey.Equals(bls48581.ECP_generator()) {
|
|
f.publicKey = reconstructedSum
|
|
} else if !f.publicKey.Equals(reconstructedSum) {
|
|
fmt.Println("key mismatch")
|
|
fmt.Println(f.publicKey.ToString())
|
|
fmt.Println(reconstructedSum.ToString())
|
|
return
|
|
}
|
|
}
|
|
f.round = FELDMAN_ROUND_RECONSTRUCTED
|
|
}
|
|
}
|
|
|
|
func (f *FeldmanECP) PublicKey() *bls48581.ECP {
|
|
key := bls48581.NewECP()
|
|
key.Copy(f.publicKey)
|
|
return key
|
|
}
|
|
|
|
func (f *FeldmanECP) PublicKeyBytes() []byte {
|
|
publicKeyBytes := make([]byte, bls48581.MODBYTES+1)
|
|
f.publicKey.ToBytes(publicKeyBytes, true)
|
|
return publicKeyBytes
|
|
}
|
|
|
|
func (f *FeldmanECP8) SamplePolynomial() {
|
|
coeffs := append([]*bls48581.BIG{}, f.secret)
|
|
|
|
for i := 0; i < f.threshold-1; i++ {
|
|
secretBytes := make([]byte, int(bls48581.MODBYTES))
|
|
rand.Read(secretBytes)
|
|
secret := bls48581.FromBytes(secretBytes)
|
|
coeffs = append(coeffs, secret)
|
|
}
|
|
|
|
for i := 1; i <= f.total; i++ {
|
|
result := coeffs[len(coeffs)-1]
|
|
|
|
for j := len(coeffs) - 2; j >= 0; j-- {
|
|
result = bls48581.Modadd(
|
|
coeffs[j],
|
|
bls48581.Modmul(
|
|
result,
|
|
bls48581.NewBIGint(i),
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
),
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
}
|
|
|
|
if i == f.id {
|
|
f.scalar = result
|
|
} else {
|
|
fragBytes := make([]byte, int(bls48581.MODBYTES))
|
|
result.ToBytes(fragBytes)
|
|
f.fragsForCounterparties[i] = fragBytes
|
|
}
|
|
}
|
|
|
|
f.round = FELDMAN_ROUND_INITIALIZED
|
|
}
|
|
|
|
func (f *FeldmanECP8) GetPolyFrags() map[int][]byte {
|
|
return f.fragsForCounterparties
|
|
}
|
|
|
|
func (f *FeldmanECP8) SetPolyFragForParty(id int, frag []byte) []byte {
|
|
f.fragsFromCounterparties[id] = bls48581.FromBytes(frag)
|
|
|
|
if len(f.fragsFromCounterparties) == f.total-1 {
|
|
for _, v := range f.fragsFromCounterparties {
|
|
f.scalar = bls48581.Modadd(f.scalar, v, bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
}
|
|
|
|
f.point = f.point.Mul(f.scalar)
|
|
|
|
randCommitmentBytes := make([]byte, int(bls48581.MODBYTES))
|
|
rand.Read(randCommitmentBytes)
|
|
randCommitment := bls48581.FromBytes(randCommitmentBytes)
|
|
f.randomCommitmentPoint = f.publicKey.Mul(randCommitment)
|
|
|
|
publicPointBytes := make([]byte, bls48581.MODBYTES*8+1)
|
|
randCommitmentPointBytes := make([]byte, bls48581.MODBYTES*8+1)
|
|
f.point.ToBytes(publicPointBytes, true)
|
|
f.randomCommitmentPoint.ToBytes(randCommitmentPointBytes, true)
|
|
|
|
challenge := sha256.Sum256(append(append([]byte{}, publicPointBytes...), randCommitmentPointBytes...))
|
|
challengeBig := bls48581.FromBytes(challenge[:])
|
|
challengeBig.Mod(bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
|
|
f.zkpok = bls48581.Modadd(
|
|
bls48581.Modmul(
|
|
f.scalar,
|
|
challengeBig,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
),
|
|
randCommitment,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
|
|
zkpokBytes := make([]byte, int(bls48581.MODBYTES))
|
|
f.zkpok.ToBytes(zkpokBytes)
|
|
zkcommit := sha256.Sum256(append(append([]byte{}, randCommitmentPointBytes...), zkpokBytes...))
|
|
|
|
f.round = FELDMAN_ROUND_COMMITTED
|
|
return zkcommit[:]
|
|
}
|
|
|
|
return []byte{}
|
|
}
|
|
|
|
func (f *FeldmanECP8) Scalar() *bls48581.BIG {
|
|
return f.scalar
|
|
}
|
|
|
|
func (f *FeldmanECP8) ReceiveCommitments(id int, zkcommit []byte) *FeldmanReveal {
|
|
f.zkcommitsFromCounterparties[id] = zkcommit
|
|
|
|
if len(f.zkcommitsFromCounterparties) == f.total-1 {
|
|
publicPointBytes := make([]byte, bls48581.MODBYTES*8+1)
|
|
randCommitmentPointBytes := make([]byte, bls48581.MODBYTES*8+1)
|
|
f.point.ToBytes(publicPointBytes, true)
|
|
f.randomCommitmentPoint.ToBytes(randCommitmentPointBytes, true)
|
|
f.round = FELDMAN_ROUND_REVEALED
|
|
zkpokBytes := make([]byte, int(bls48581.MODBYTES))
|
|
f.zkpok.ToBytes(zkpokBytes)
|
|
|
|
return &FeldmanReveal{
|
|
Point: publicPointBytes,
|
|
RandomCommitmentPoint: randCommitmentPointBytes,
|
|
ZKPoK: zkpokBytes,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *FeldmanECP8) Recombine(id int, reveal *FeldmanReveal) {
|
|
counterpartyPoint := bls48581.ECP8_fromBytes(reveal.Point)
|
|
if counterpartyPoint.Equals(bls48581.ECP8_generator()) {
|
|
fmt.Printf("invalid point from %d", id)
|
|
return
|
|
}
|
|
|
|
counterpartyRandomCommitmentPoint := bls48581.ECP8_fromBytes(reveal.RandomCommitmentPoint)
|
|
if counterpartyRandomCommitmentPoint.Equals(bls48581.ECP8_generator()) {
|
|
fmt.Printf("invalid commitment point from %d", id)
|
|
return
|
|
}
|
|
|
|
counterpartyZKPoK := bls48581.FromBytes(reveal.ZKPoK)
|
|
counterpartyZKCommit := f.zkcommitsFromCounterparties[id]
|
|
|
|
challenge := sha256.Sum256(append(append([]byte{}, reveal.Point...), reveal.RandomCommitmentPoint...))
|
|
challengeBig := bls48581.FromBytes(challenge[:])
|
|
challengeBig.Mod(bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
|
|
proof := f.publicKey.Mul(counterpartyZKPoK)
|
|
counterpartyRandomCommitmentPoint.Add(counterpartyPoint.Mul(challengeBig))
|
|
|
|
if !proof.Equals(counterpartyRandomCommitmentPoint) {
|
|
fmt.Printf("invalid proof from %d", id)
|
|
return
|
|
}
|
|
|
|
verifier := sha256.Sum256(append(append([]byte{}, reveal.RandomCommitmentPoint...), reveal.ZKPoK...))
|
|
if !bytes.Equal(counterpartyZKCommit, verifier[:]) {
|
|
fmt.Printf("%d changed zkpok after commit", id)
|
|
return
|
|
}
|
|
|
|
f.pointsFromCounterparties[id] = counterpartyPoint
|
|
|
|
if len(f.pointsFromCounterparties) == f.total-1 {
|
|
f.pointsFromCounterparties[f.id] = f.point
|
|
for i := 1; i <= f.total-f.threshold; i++ {
|
|
reconstructedSum := bls48581.ECP8_generator()
|
|
|
|
for j := i; j <= f.threshold+i; j++ {
|
|
coefficientNumerator := bls48581.NewBIGint(1)
|
|
coefficientDenominator := bls48581.NewBIGint(1)
|
|
|
|
for k := i; k <= f.threshold+i; k++ {
|
|
if j != k {
|
|
k := bls48581.NewBIGint(k)
|
|
|
|
coefficientNumerator = bls48581.Modmul(
|
|
coefficientNumerator,
|
|
k,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
kj := bls48581.Modadd(
|
|
k,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order).Minus(bls48581.NewBIGint(j)),
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
coefficientDenominator = bls48581.Modmul(
|
|
coefficientDenominator,
|
|
kj,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
)
|
|
}
|
|
}
|
|
|
|
coefficientDenominator.Invmodp(bls48581.NewBIGints(bls48581.CURVE_Order))
|
|
|
|
reconstructedFragment := f.pointsFromCounterparties[j].Mul(
|
|
bls48581.Modmul(
|
|
coefficientNumerator,
|
|
coefficientDenominator,
|
|
bls48581.NewBIGints(bls48581.CURVE_Order),
|
|
),
|
|
)
|
|
|
|
if reconstructedSum.Equals(bls48581.ECP8_generator()) {
|
|
reconstructedSum = reconstructedFragment
|
|
} else {
|
|
reconstructedSum.Add(reconstructedFragment)
|
|
}
|
|
}
|
|
|
|
if f.publicKey.Equals(bls48581.ECP8_generator()) {
|
|
f.publicKey = reconstructedSum
|
|
} else if !f.publicKey.Equals(reconstructedSum) {
|
|
fmt.Println("key mismatch")
|
|
fmt.Println(f.publicKey.ToString())
|
|
fmt.Println(reconstructedSum.ToString())
|
|
return
|
|
}
|
|
}
|
|
f.round = FELDMAN_ROUND_RECONSTRUCTED
|
|
}
|
|
}
|
|
|
|
func (f *FeldmanECP8) PublicKey() *bls48581.ECP8 {
|
|
key := bls48581.NewECP8()
|
|
key.Copy(f.publicKey)
|
|
return key
|
|
}
|
|
|
|
func (f *FeldmanECP8) PublicKeyBytes() []byte {
|
|
publicKeyBytes := make([]byte, bls48581.MODBYTES*8+1)
|
|
f.publicKey.ToBytes(publicKeyBytes, true)
|
|
return publicKeyBytes
|
|
}
|