mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 15:37:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			182 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright Coinbase, Inc. All Rights Reserved.
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0
 | 
						|
//
 | 
						|
 | 
						|
package gennaro2p
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/elliptic"
 | 
						|
	"fmt"
 | 
						|
	"reflect"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/btcsuite/btcd/btcec"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
 | 
						|
	v1 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/sharing/v1"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	curveScalar = curves.NewK256Scalar()
 | 
						|
	curve       = btcec.S256()
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	clientId = 1
 | 
						|
	serverId = 2
 | 
						|
)
 | 
						|
 | 
						|
// Benchmark full DKG including blind selection and setup
 | 
						|
func BenchmarkDkg(b *testing.B) {
 | 
						|
	if testing.Short() {
 | 
						|
		b.Skip("skipping test in short mode.")
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		_, _, err := dkg()
 | 
						|
		require.NoError(b, err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Run a DKG and reports the client/server results
 | 
						|
func dkg() (*DkgResult, *DkgResult, error) {
 | 
						|
	// Create client/server
 | 
						|
	blind, _ := newBlind(curveScalar, curve)
 | 
						|
 | 
						|
	client, err := NewParticipant(clientId, serverId, blind, curveScalar, curve)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	server, err := NewParticipant(serverId, clientId, blind, curveScalar, curve)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	// R1
 | 
						|
	clientR1, err := client.Round1(nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	serverR1, err := server.Round1(nil)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	// R2
 | 
						|
	clientR2, err := client.Round2(serverR1)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	serverR2, err := server.Round2(clientR1)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	// Finalize
 | 
						|
	clientResult, err := client.Finalize(serverR2)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	serverResult, err := server.Finalize(clientR2)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return clientResult, serverResult, nil
 | 
						|
}
 | 
						|
 | 
						|
// Run a full DKG and verify the absence of errors and valid results
 | 
						|
func TestDkg(t *testing.T) {
 | 
						|
	// Setup and ensure no errors
 | 
						|
	clientResult, serverResult, err := dkg()
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.NotNil(t, clientResult)
 | 
						|
	require.NotNil(t, serverResult)
 | 
						|
 | 
						|
	// Now run tests
 | 
						|
	t.Run("produce the same public key", func(t *testing.T) {
 | 
						|
		require.Equal(t, clientResult.PublicKey, serverResult.PublicKey)
 | 
						|
	})
 | 
						|
	t.Run("produce identical public shares", func(t *testing.T) {
 | 
						|
		require.True(t, reflect.DeepEqual(clientResult.PublicShares, serverResult.PublicShares))
 | 
						|
	})
 | 
						|
	t.Run("produce distinct secret shares", func(t *testing.T) {
 | 
						|
		require.NotEqual(t, clientResult.SecretShare, serverResult.SecretShare)
 | 
						|
	})
 | 
						|
	t.Run("produce distinct secret shares", func(t *testing.T) {
 | 
						|
		require.NotEqual(t, clientResult.SecretShare, serverResult.SecretShare)
 | 
						|
	})
 | 
						|
	t.Run("shares sum to expected public key", func(t *testing.T) {
 | 
						|
		pubkey, err := reconstructPubkey(
 | 
						|
			clientResult.SecretShare,
 | 
						|
			serverResult.SecretShare,
 | 
						|
			curve)
 | 
						|
		require.NoError(t, err)
 | 
						|
		require.Equal(t, serverResult.PublicKey, pubkey)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Reconstruct the pubkey from 2 shares
 | 
						|
func reconstructPubkey(s1, s2 *v1.ShamirShare, curve elliptic.Curve) (*curves.EcPoint, error) {
 | 
						|
	s, err := v1.NewShamir(2, 2, s1.Value.Field())
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	sk, err := s.Combine(s1, s2)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	x, y := curve.ScalarBaseMult(sk)
 | 
						|
	return &curves.EcPoint{
 | 
						|
		Curve: curve,
 | 
						|
		X:     x,
 | 
						|
		Y:     y,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// Test blind generator helper function produces a value on the expected curve
 | 
						|
func TestNewBlindOnCurve(t *testing.T) {
 | 
						|
	const n = 1024
 | 
						|
	for i := 0; i < n; i++ {
 | 
						|
		b, err := newBlind(curveScalar, curve)
 | 
						|
		require.NoError(t, err)
 | 
						|
		require.NotNil(t, b)
 | 
						|
 | 
						|
		// Valid point?
 | 
						|
		require.True(t, b.IsOnCurve() && b.IsValid())
 | 
						|
		require.True(t, b.IsValid())
 | 
						|
		require.False(t, b.IsIdentity())
 | 
						|
		require.False(t, b.IsBasePoint())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestNewBlindProvidesDistinctPoints(t *testing.T) {
 | 
						|
	const n = 1024
 | 
						|
	seen := make(map[string]bool, n)
 | 
						|
	// seen := make(map[core.EcPoint]bool, n)
 | 
						|
 | 
						|
	for i := 0; i < n; i++ {
 | 
						|
		b, err := newBlind(curveScalar, curve)
 | 
						|
		require.NoError(t, err)
 | 
						|
 | 
						|
		// serialize so the point is hashable
 | 
						|
		txt := fmt.Sprintf("%#v", b)
 | 
						|
 | 
						|
		// We shouldn't see the same point twice
 | 
						|
		ok := seen[txt]
 | 
						|
		require.False(t, ok)
 | 
						|
 | 
						|
		// store
 | 
						|
		seen[txt] = true
 | 
						|
	}
 | 
						|
}
 |