mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright Coinbase, Inc. All Rights Reserved.
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0
 | 
						|
//
 | 
						|
 | 
						|
package v0
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/sha256"
 | 
						|
	"crypto/subtle"
 | 
						|
	"fmt"
 | 
						|
	"math/big"
 | 
						|
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
 | 
						|
)
 | 
						|
 | 
						|
type Schnorr struct {
 | 
						|
	params *Params
 | 
						|
	Pub    *curves.EcPoint // this is the public point.
 | 
						|
	C      *big.Int
 | 
						|
	S      *big.Int
 | 
						|
}
 | 
						|
 | 
						|
func (proof *Schnorr) Prove(x *big.Int) error {
 | 
						|
	// assumes that params, Base, and pub are already populated. populates the fields c and s...
 | 
						|
	var err error
 | 
						|
	proof.Pub, err = curves.NewScalarBaseMult(proof.params.Curve, x) // populate the statement
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	k, err := proof.params.Scalar.Random()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	random, err := curves.NewScalarBaseMult(proof.params.Curve, k)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	hash := sha256.New()
 | 
						|
	if _, err = hash.Write(proof.Pub.Bytes()); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if _, err = hash.Write(random.Bytes()); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// do we need to hash anything further here...? maybe some kind of session token or something?
 | 
						|
	proof.C = new(big.Int).SetBytes(hash.Sum(nil))
 | 
						|
	proof.S = proof.params.Scalar.Add(proof.params.Scalar.Mul(proof.C, x), k)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (proof *Schnorr) Verify() error {
 | 
						|
	gs, err := curves.NewScalarBaseMult(proof.params.Curve, proof.S)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	xc, err := proof.Pub.ScalarMult(proof.params.Scalar.Neg(proof.C))
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	random, err := gs.Add(xc)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	hash := sha256.New()
 | 
						|
	if _, err = hash.Write(proof.Pub.Bytes()); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if _, err = hash.Write(random.Bytes()); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if subtle.ConstantTimeCompare(proof.params.Scalar.Bytes(proof.C), hash.Sum(nil)) != 1 {
 | 
						|
		return fmt.Errorf("Schnorr verification failed")
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// this "commits to" a schnorr proof which is later revealed; see Functionality 7.
 | 
						|
// it mutates `st` by adding a proof to it, and then also returns the commitment to the proof.
 | 
						|
func (proof *Schnorr) ProveCommit(x *big.Int) ([]byte, error) {
 | 
						|
	// it remains to be seen why this is actually necessary in the paper. it's unsual.
 | 
						|
	// i suspect it is some "abstract nonsense" necessary for the security proof to go through.
 | 
						|
	// in the implementation (see https://gitlab.com/neucrypt/mpecdsa/-/blob/release/src/zkpok.rs),
 | 
						|
	// they implement this just by hashing the schnorr proof; we do the same (using c, s as the proof instead of K, s).
 | 
						|
	// it's a bit weird that no randomness is used, but "hiding" shouldn't really be an issue, as the proof is random.
 | 
						|
	// confirm that this actually matches how they implement it, and/or is secure. i don't think it should be an issue.
 | 
						|
	if err := proof.Prove(x); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	hash := sha256.New()
 | 
						|
	if _, err := hash.Write(proof.params.Scalar.Bytes(proof.C)); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if _, err := hash.Write(proof.params.Scalar.Bytes(proof.S)); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return hash.Sum(nil), nil
 | 
						|
}
 | 
						|
 | 
						|
func (proof *Schnorr) DecommitVerify(com []byte) error {
 | 
						|
	hash := sha256.New()
 | 
						|
	if _, err := hash.Write(proof.params.Scalar.Bytes(proof.C)); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if _, err := hash.Write(proof.params.Scalar.Bytes(proof.S)); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if subtle.ConstantTimeCompare(hash.Sum(nil), com) != 1 {
 | 
						|
		return fmt.Errorf("initial hash decommitment failed")
 | 
						|
	}
 | 
						|
	return proof.Verify()
 | 
						|
}
 |