mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:57:26 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright Coinbase, Inc. All Rights Reserved.
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0
 | 
						|
//
 | 
						|
 | 
						|
package frost
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/internal"
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
 | 
						|
)
 | 
						|
 | 
						|
// Round3Bcast contains the output of FROST signature, i.e., it contains FROST signature (z,c) and the
 | 
						|
// corresponding message msg.
 | 
						|
type Round3Bcast struct {
 | 
						|
	R    curves.Point
 | 
						|
	Z, C curves.Scalar
 | 
						|
	msg  []byte
 | 
						|
}
 | 
						|
 | 
						|
// Define frost signature type
 | 
						|
type Signature struct {
 | 
						|
	Z curves.Scalar
 | 
						|
	C curves.Scalar
 | 
						|
}
 | 
						|
 | 
						|
func (signer *Signer) SignRound3(round3Input map[uint32]*Round2Bcast) (*Round3Bcast, error) {
 | 
						|
	// Make sure signer is not empty
 | 
						|
	if signer == nil || signer.curve == nil {
 | 
						|
		return nil, internal.ErrNilArguments
 | 
						|
	}
 | 
						|
 | 
						|
	// Make sure signer's smallD and smallE are zero
 | 
						|
	if !signer.state.smallD.IsZero() || !signer.state.smallE.IsZero() {
 | 
						|
		return nil, fmt.Errorf("signer's private smallD and smallE should be zero since one-time use")
 | 
						|
	}
 | 
						|
 | 
						|
	// Make sure the signer has had the msg
 | 
						|
	if len(signer.state.msg) == 0 {
 | 
						|
		return nil, internal.ErrNilArguments
 | 
						|
	}
 | 
						|
 | 
						|
	// Validate Round3Input
 | 
						|
	if round3Input == nil {
 | 
						|
		return nil, internal.ErrNilArguments
 | 
						|
	}
 | 
						|
	for _, data := range round3Input {
 | 
						|
		if data == nil {
 | 
						|
			return nil, internal.ErrNilArguments
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Make sure the signer has commitments stored at the end of round 1.
 | 
						|
	if signer.state.commitments == nil || len(signer.state.commitments) != len(round3Input) {
 | 
						|
		return nil, internal.ErrNilArguments
 | 
						|
	}
 | 
						|
 | 
						|
	// Make sure the round number is correct
 | 
						|
	if signer.round != 3 {
 | 
						|
		return nil, internal.ErrInvalidRound
 | 
						|
	}
 | 
						|
 | 
						|
	// Round2 Input has different length of threshold
 | 
						|
	if uint32(len(round3Input)) != signer.threshold {
 | 
						|
		return nil, fmt.Errorf("invalid length of round3Input")
 | 
						|
	}
 | 
						|
 | 
						|
	// Step 1-3
 | 
						|
	// Step 1: For j in [1...t]
 | 
						|
	z := signer.curve.NewScalar()
 | 
						|
	negate := signer.state.sumR.IsNegative()
 | 
						|
	for id, data := range round3Input {
 | 
						|
		zj := data.Zi
 | 
						|
		vkj := data.Vki
 | 
						|
 | 
						|
		// Step 2: Verify zj*G = Rj + c*Lj*vkj
 | 
						|
		// zj*G
 | 
						|
		zjG := signer.curve.ScalarBaseMult(zj)
 | 
						|
 | 
						|
		// c*Lj
 | 
						|
		cLj := signer.state.c.Mul(signer.lCoeffs[id])
 | 
						|
 | 
						|
		// cLjvkj
 | 
						|
		cLjvkj := vkj.Mul(cLj)
 | 
						|
 | 
						|
		// Rj + c*Lj*vkj
 | 
						|
		Rj := signer.state.capRs[id]
 | 
						|
		if negate {
 | 
						|
			Rj = Rj.Neg()
 | 
						|
		}
 | 
						|
		right := cLjvkj.Add(Rj)
 | 
						|
 | 
						|
		// Check equation
 | 
						|
		if !zjG.Equal(right) {
 | 
						|
			return nil, fmt.Errorf("zjG != right with participant id %d\n", id)
 | 
						|
		}
 | 
						|
 | 
						|
		// Step 3 - z = z+zj
 | 
						|
		z = z.Add(zj)
 | 
						|
	}
 | 
						|
 | 
						|
	// Step 4 - 7: Self verify the signature (z, c)
 | 
						|
	// Step 5 - R' = z*G + (-c)*vk
 | 
						|
	zG := signer.curve.ScalarBaseMult(z)
 | 
						|
	cvk := signer.verificationKey.Mul(signer.state.c.Neg())
 | 
						|
	tempR := zG.Add(cvk)
 | 
						|
	// Step 6 - c' = H(m, R')
 | 
						|
	tempC, err := signer.challengeDeriver.DeriveChallenge(signer.state.msg, signer.verificationKey, tempR)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	// Step 7 - Check c = c'
 | 
						|
	if tempC.Cmp(signer.state.c) != 0 {
 | 
						|
		return nil, fmt.Errorf("invalid signature: c != c'")
 | 
						|
	}
 | 
						|
 | 
						|
	// Updating round number
 | 
						|
	signer.round = 4
 | 
						|
 | 
						|
	// Step 8 - Broadcast signature and message
 | 
						|
	return &Round3Bcast{
 | 
						|
		signer.state.sumR,
 | 
						|
		z,
 | 
						|
		signer.state.c,
 | 
						|
		signer.state.msg,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// Method to verify a frost signature.
 | 
						|
func Verify(curve *curves.Curve, challengeDeriver ChallengeDerive, vk curves.Point, msg []byte, signature *Signature) (bool, error) {
 | 
						|
	if vk == nil || msg == nil || len(msg) == 0 || signature.C == nil || signature.Z == nil {
 | 
						|
		return false, fmt.Errorf("invalid input")
 | 
						|
	}
 | 
						|
	z := signature.Z
 | 
						|
	c := signature.C
 | 
						|
 | 
						|
	//R' = z*G - c*vk
 | 
						|
	zG := curve.ScalarBaseMult(z)
 | 
						|
	cvk := vk.Mul(c.Neg())
 | 
						|
	tempR := zG.Add(cvk)
 | 
						|
 | 
						|
	//c' = H(m, R')
 | 
						|
	tempC, err := challengeDeriver.DeriveChallenge(msg, vk, tempR)
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
 | 
						|
	// Check c == c'
 | 
						|
	if tempC.Cmp(c) != 0 {
 | 
						|
		return false, fmt.Errorf("invalid signature: c != c'")
 | 
						|
	}
 | 
						|
	return true, nil
 | 
						|
}
 |